Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   *Флейм* | Delphi. Синтаксис. Использование WinAPI (http://forum.oszone.net/showthread.php?t=41364)

DillerInc 19-11-2004 17:41 274174

*Флейм* | Delphi. Синтаксис. Использование WinAPI
 
Итак,вопрос начинающего программиста заключается в следующем - имеется следующий текст кода:
Цитата:

// Показываем результат
lbOutput.Caption := Trim(edInput1.Text)+' '+cbSign.Items[cbSign.ItemIndex]+' '+
Trim(edInput2.Text)+' = ' ;
...для меня остаётся непонятным,по какому принципу выставляются знаки апострофа и плюса('+)в данном примере.
Не мог бы кто-нибудь разъяснить это дело?

P.S. Пример кода взят из книги Валерия Фаронова "Система программирования Delphi" .

shurikan 19-11-2004 20:05 274203

DillerInc

Это просто:

Код:

// Показываем результат

//            v - этот параметр имеет тип String
lbOutput.Caption :=  // мы присваиваем ему конкатенацию других строк

 Trim(edInput1.Text) // первая
+                              // складывается со следующей,
' '                              // вот этой. Результат - первая строка с пробелом на конце
+                              // складывается с...
cbSign.Items[cbSign.ItemIndex]
+                              // в конец результата опять добавляется
' '                              // пробел... и т.д.
+
Trim(edInput2.Text)
+
' = ' ;

:)

DillerInc 19-11-2004 23:27 274243

shurikan
Спасибо,конечно,за ответ.
Признаюсь,долго ломал голову над вышенаписанным.Но постараюсь как-нибудь разобраться.Правильно ли я понял,что
Цитата:

Trim(edInput1.Text)+' // это первая складывающаяся строка
'+cbSign.Items[cbSign.ItemIndex]+' // это вторая складывающаяся строка
'+Trim.edInput2.Text)+' // это третья складывающаяся строка
// и между ними стоит везде пробел
...или нет?

Новичёк 20-11-2004 00:14 274251

DillerInc, нет, совсем не правильно :(
Строк тут шесть:
Trim(edInput1.Text) //1-ая
' ' //2-ая, содержит один-единственный пробел для //разделения
cbSign.Items[cbSign.ItemIndex] // 3-я
' ' // 4-я, опять только пробел
Trim(edInput2.Text) // 5-я
' = ' // символ "=" с пробелами - разделителями
Ты, как я понял, решил, что знаки конкатенации ("+") надо заключать вместе со строкой в апострофы? Если нет, то извини, зря я шум поднял ;), а если нет... Вобщем, плюсы ЗА апострофами, просто строка тута такая, что можно запутаться :)

DillerInc 20-11-2004 00:58 274260

Новичёк
Потихоньку туман начинает рассеиваться,в любом случае,огромное спасибо за разъяснения :) .

P.S. Удивительно,почему в той самой книге Фаронова об этом ничего не говорится.

DillerInc 26-12-2004 22:17 283702

Господа,имеется следующий код:
Код:

unit AssignFileU;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls;

type
  TfmExample = class(TForm)
    Panel1: TPanel;
    bbRun: TBitBtn;
    bbClose: TBitBtn;
    edInput: TEdit;
    lbOutput: TLabel;
    mmOutput: TMemo;
    procedure bbRunClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  fmExample: TfmExample;

implementation

{$R *.dfm}

procedure TfmExample.bbRunClick(Sender: TObject);
var
 F : TextFile;
 S : String;
begin
  AssignFile(F, 'Passion.srt');
  Reset(F);
while not EOF(F) do
begin
 ReadLn(F,S);
 mmOutput.Lines.Add(S)
end;
 CloseFile(F)
end;

Так вот при прогоне этой программы Delphi выдаёт мне ошибку "Declaration expected but end of file found".
Подскажите,пожалуйста,как это можно исправить и в чём тут дело.

hasherfrog 27-12-2004 09:36 283785

Энд с точкой?

DillerInc 27-12-2004 19:49 283946

hasherfrog
Если я ставлю end.,он помимо вышеупомянутого сообщения об ошибке выдаёт ещё одно :
Код:

";" expected but "." found
Вроде бы он в первом сообщении просит что-то объявить(declaration),а что...?

DillerInc 27-12-2004 21:34 283965

hasherfrog
То ли я тебя неправильно понял,то ли ещё что... :)
Короче,в конец кода надо было просто добавить недостающее end.,и тогда всё становится путём.

hasherfrog 28-12-2004 00:10 283996

:lol: Короче, дело к ночи.
недостающее end. - Энд с точкой, как и было сказано :)
Бегин с кисточкой. Скобка ласточкой. Кхм. Где комодеры?

DillerInc 28-12-2004 23:24 284270

Это опять я со своими вопросами.
Итак,вот ситуация:
имеется текстовый файл(как в примере выше),содержащий текст.В этом тексте есть две определённые ошибки,встречающиеся часто на протяжении всего текста.
Так вот как сделать так,чтобы создаваемая программка открывала этот файл,читала его(типа всё как в примере выше),а затем находила эти определённые(неправильные)символы и заменяла их опять-таки определёнными,но уже правильными символами?Возможно ли такое?Если что,пожалуйста,с комментариями.

hasherfrog 29-12-2004 09:03 284369

Найти что-то в тексте (разобрать его на составляющие, или по-научному "пропарсить" :rotate:) - одна из наиболее простых и частых задач программирования. Подробнее, какие трудности? И вообще, зачем писать программу? Обычно в таких случаях хватает CTRL+R.

DillerInc 29-12-2004 17:14 284501

hasherfrog
Дело в том,что есть такая программка как SubRip,которая выдирает титры из VOB-файлов.Всё работает замечательно,но если титры русские,есть одна запара - программа не распознаёт русской буквы "ы",поэтому при обработке таких титров в теле самой программы вместо "ы" приходится писать "ьl".Этот недостаток можно,конечно,потом самому "ручками" в текстовом редакторе исправить,но это довольно муторно.Поэтому я и хочу автоматизировать этот процесс.
При написании кода для меня остаётся непонятным,как заставить программу найти то,что я ищу,т.е. необходимо ввести какие-то переменные(возможно типа Char)и воспользоваться какой-то процедурой или функцией,чтобы найти нужные символы и затем с помощью оператора присваивания исправить их на нужные,так что ли?

DillerInc 31-12-2004 18:35 284930

В общем-то,вот некоторые намётки:
Код:

Function GetSymb(sbInp: String) : String;
{Эта кустарная функция должна преобразовывать определённые символы в нужные}
var
 k : Integer;
begin
 Result := sbInp;
 for k := 1 to Length(Result) do
begin
 if Result[k] = 'l' then
    Result[k] := Chr(Ord('ы'));
 if Result[k] = 'ь' then
    Delete(sbInp,Ord('ь'),1);
end;
end; // GetSymb

...но я никак не могу добиться,чтобы процедура Delete уничтожала символ "ь" .
Следовательно,в чём может быть ошибка?

Savant 01-01-2005 04:29 285007

DillerInc
Привет!
Ну что ж, подправим твою "кустарную" функцию:
Код:

Function GetSymb(sbInp: String) : String;
{Эта кустарная функция должна преобразовывать определённые символы в нужные}
var
  k : Integer;
begin
  Result := sbInp;
  for k := 1 to Length(Result)-1 do
        if (Result[k] = 'ь') and (Result[k+1] = 'l') then begin
          Result[k] := 'ы'; Delete(Result,k+1,1);
        end;
end; // GetSymb

На заметку: подучи функции Pos, Delete и Ord. Ты их неверно используешь
Можно и проще, не используя Result (в виде - procedure Convert(var sbInp: String); )

Кстать, а на php/perl такие задачи ваще халява: $your_text=preg_replace('ьl','ы',$your_text);

DillerInc 01-01-2005 16:35 285049

Savant
Получилось - ну,спасибо!!!
:applause:
Да,кстати,с Наступившим тебя!

Savant 01-01-2005 17:10 285061

DillerInc
Да ладно? а если я скажу, что в функции была ошибка, не замеченная мною по случаю Нового Года? :) Я тока щас заметил. Кто рабирается в программировании, сразу ее заметит. Правда, я не знаю, как на ошибку среагирует delphi, поскольку нет возможности проверить код в действии.
Перепишу код (и заодно в новом варианте, про который я упоминал):
Код:

procedure ConvertStr(var sbInp : String);
{Эта кустарная функция должна преобразовывать определённые символы в нужные}
var
  k : Integer;
begin
  k := 1;
  while k < Length( Result ) do begin
    if (sbInp[k] = 'ь') and (sbInp[k+1] = 'l') then begin
      sbInp[k] := 'ы';
      Delete(sbInp,k+1,1);
      end;
    inc(k);
    end;
end; // ConvertStr

Если нужен вариант в виде функции, то можно добавить:
Код:

function ConvertStrF(const sbInp: String) : String;
begin
  Result := sbInp;
  ConvertStr(Result);
end;


DillerInc 01-01-2005 17:37 285069

Savant
Цитата:

Да ладно? а если я скажу, что в функции была ошибка
...не знаю,не знаю.Код реализовал,проверил - откомпилированная программа работает исправно.
Если не секрет,то,что за ошибка(для тех,кто с трудом разбирается в программировании :) )?

Savant 01-01-2005 18:26 285075

DillerInc
Да не секрет конечно... :)
Обрати внимание - в цикле for предельное значение переменной k является константой начальной длины входной строки, уменьшенной на единицу. А в процессе замены длина строки уменьшается с каждой заменой на 1 (а предельное значение является константой и не уменьшается), поэтому, если в конце обрабатываемой строки будет "ьl" и несколько "ьl" где-то в середине, то возможно в процедуре Delete() или при чтении из Result[k], где k в данный момент времени уже больше Length(Result), возникнет исключение. Но, к счастью, этого не происходит ни там ни там (хотя не очень понятно почему, может наадо включить Overflow Checking?). Ага, я ток что заглянул в справку по Дельфям и прочитал там кое-что интересное насчет Delete() (исключение генерироваться не будет при выходе за пределы строки):
Цитата:

procedure Delete(var S: string; Index, Count: Integer);

Description

In Delphi code, Delete removes a substring of Count characters from string S starting with S[Index]. S is a string-type variable. Index and Count are integer-type expressions.

If index is larger than the length of the string or less than 1, no characters are deleted.

If count specifies more characters than remain starting at the index, Delete removes the rest of the string. If count is less than or equal to 0, no characters are deleted.
Поэтому изначальный код хоть и работает , но имеет некоторые изъяны. Только маленький вопрос напоследок, а Overflow Checking у тебя включен ?

Или Range Checking...

DillerInc 01-01-2005 18:44 285078

Savant
Огромное спасибо за помощь и советы :) .
Цитата:

а Overflow Checking у тебя включен ?
...нет,не включен.Лучше включить?

Savant 01-01-2005 19:10 285080

DillerInc
увеличится размер выходного файла (при установке Range или Overflow Checking), но будешь узнавать о всех недосмотрах в коде программы

DillerInc 03-01-2005 22:00 285507

Чего-то я запутался в следующем:
Код:

procedure TfmSubRip_Mod.bbOpenClick(Sender: TObject);
{Открываем текстовый файл с титрами}
begin
 OpenDialog1.Filter := 'Титры с расширением "srt"|*.srt';
if OpenDialog1.Execute and FileExists(OpenDialog1.FileName) then
  mmOutput.Lines.LoadFromFile(OpenDialog1.FileName);  // Загружаем в многострочное поле текст из файла
  lbOutput.Caption := 'Нажмите "Пуск",чтобы начать исправление символов';  // Добавляем текст в метку

...это всё если OpenDialog1.Execute = True,а мне надо добавить сюда ещё обработчик события OpenDialog1.Execute = False(типа пользователь передумал открывать файл и нажал Cancel),который будет опять добавлять текст в метку,например:
Код:

lbOutput := 'Повторите операцию "Открыть файл" ';
В общем,попытка добавить в конец вышеуказанного кода слово else вызывает кучу всяких ошибок.Если добавить ещё один условный оператор if...then,то диалоговое окно открытия файла заставляет по два раза открывать нужный файл...

Savant 03-01-2005 22:08 285511

DillerInc
Код:

procedure TfmSubRip_Mod.bbOpenClick(Sender: TObject);
{Открываем текстовый файл с титрами}
begin
  OpenDialog1.Filter := 'Титры с расширением "srt"|*.srt';
  if OpenDialog1.Execute then begin
    if FileExists(OpenDialog1.FileName) then begin
      mmOutput.Lines.LoadFromFile(OpenDialog1.FileName);  // Загружаем в многострочное поле текст из файла
      lbOutput.Caption := 'Нажмите "Пуск",чтобы начать исправление символов';  // Добавляем текст в метку
      end else lbOutput.Caption := 'Файл не найден' end else
    lbOutput.Caption := 'Повторите операцию "Открыть файл" ';


DillerInc 03-01-2005 22:37 285520

Savant
Ай да Savant - выручатель мой!Действительно получилось,как я хотел.
Спасибо :) .

DillerInc 20-01-2005 01:12 290242

Доброго всем времени суток!
Это снова я...со своими вопросами.А именно,имеется вопрос по использованию переменных в подпрограммах.
Код:
Код:

unit FileDateU;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Buttons, StdCtrls, ExtCtrls, Mask;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    bbOpen: TButton;
    OpenDialog1: TOpenDialog;
    Panel2: TPanel;
    lbOutput2: TLabel;
    Panel3: TPanel;
    lbOutput1: TLabel;
    edMaskInput: TMaskEdit;
    bbRun: TBitBtn;
    procedure bbOpenClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure bbRunClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
 lbOutput2.Caption := 'Нажмите "Открыть",чтобы открыть файл и узнать дату его создания';
end;

procedure TForm1.bbOpenClick(Sender: TObject);
var
 FileHandle : Integer;
 Date : String;
begin
  OpenDialog1.Filter := 'Все файлы|*.*';
if OpenDialog1.Execute then
begin
if FileExists(OpenDialog1.FileName) then
begin
  FileHandle := FileOpen(OpenDialog1.FileName, fmOpenWrite or fmShareDenyNone);
  Date := DateTimeToStr(FileDateToDateTime(FileGetDate(FileHandle)));
  lbOutput1.Caption := Date;
  lbOutput2.Caption := 'Теперь введите новую дату в редактируемое поле и нажмите "OK",чтобы установить новую дату создания файла';
  edMaskInput.SetFocus;
end else
  lbOutput2.Caption := 'Файл не найден'
end else
  lbOutput2.Caption := 'Повторите операцию открытия файла';
end;

procedure TForm1.bbRunClick(Sender: TObject);
var
 Date2 : String;
begin
 Date2 := edMaskInput.Text;
 FileSetDate(FileHandle, (DateTimeToFileDate(StrToDateTime(Date2))));
end;

end.

Вот насчёт переменной
Код:

var
 FileHandle : Integer;

...мне почему-то не удаётся связать практику с теорией.По теории подпрограмме доступны те переменные,которые были уже объявлены и описаны в предшествующих подпрограммах.Получается,что подпрограмма TForm1.bbRunClick должна видеть переменную,объявленную и описанную в подпрограмме TForm1.bbOpenClick,но при прогоне программы компилятор,проверяя функцию FileSetDate,сообщает об ошибке "Undeclared Identifier"(FileHandle).
Подскажите,пожалуйста,что я не так понимаю и как можно поправить ситуацию?

Savant 20-01-2005 06:27 290266

DillerInc
Цитата:

По теории подпрограмме доступны те переменные,которые были уже объявлены и описаны в предшествующих подпрограммах
По теории подпрограмме доступны те переменные, которые объявлены в зоне её видимости. Т.е. глобальные переменные, объявленные вообще вне любой подпрораммы, а также еще в случае, когда одна процедура вложена в другую. Лучше наверно показать на довольно прикольном примере, который ща сочинил:
Код:

program Project_test;
{$APPTYPE CONSOLE}

Код:

var TEST: Integer = 5; // объявляем глобальную переменную
procedure a(SUPER: Integer);
// заметим, что переменная SUPER является объявленной локально,
// т.е. существует только внутри процедуры a; и вложенных в неё
  procedure b;
  begin
        inc( SUPER ); // super = 2+1 = 3
        dec( TEST );  // test = 5-1 = 4 <-тут изменяем глобальную переменную TEST
  end;

var TEST: Integer; // перекрываем глобальную переменную локальной
  procedure c;
  begin
        dec( SUPER ); // super = 3-1 = 2
        inc( TEST );  // test = 2+1 = 3 <- а тут - локальную
  end;

begin
  TEST := SUPER;
  b; WriteLn(TEST,' ',SUPER); // test=2!!! super=3
  c; WriteLn(TEST,' ',SUPER); // test=3        super=2
end;

begin
  a(2);
  WriteLn(TEST); // И наконец в подтверждение выводим глобальную переменную TEST
                                // уменьшенную в процедуре b; на единицу
  ReadLn;
end.


Savant 20-01-2005 06:37 290271

Ах да, еще спрашивалось, как подправить. Ну, думаю, это уже стало понятно - сделать FileHandle глобальной:
Код:

...........
implementation
 
{$R *.dfm}
 
var
  FileHandle : Integer;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
...........

Правда, она не становится глобальной в общем смысле, а также есть некоторые особенности объявления переменных внутри interface и implementation.

DillerInc 20-01-2005 17:14 290422

Savant
Спасибо,действительно начинает потихоньку мотаться на ус,только для меня теперь остаётся непонятным использование секции интерфейсных объявлений(interface) и секции реализаций(implementation),т.е. всегда ли можно объявлять глобальные переменные в секции реализаций и какие там есть особенности или можно также использовать т.н. поля класса - объявления переменных в следующем месте:
private
{Private declarations}
...?

Savant 20-01-2005 17:23 290426

1. Переменная, объявленная внутри implementation будет доступна всему коду , расположенному ниже её объявления.
2. Переменная, объявленная внутри interface будет доступна всему коду , расположенному ниже её объявления, а также программе, которая использует данный unit.
3. Переменная, объявленная внутри секции private будет доступна только для внутренних вызовов из данного класса.

DillerInc 20-01-2005 18:00 290438

Savant
Премного благодарю :) .
Теперь немного о функциях рассмотренного выше кода,а именно функции FileGetDate и FileSetDate - насколько я впоследствии понял,они орудуют датой последней модификации определённого файла.А я хотел,чтобы программка изменяла именно дату создания файла.Так вот вопрос: возможно ли такое "дельфийскими силами" и какие функции тогда использовать?

Savant 20-01-2005 22:46 290524

Можно так (используя WinAPI):
Код:

program Project_test;

uses Windows, SysUtils; // Необходимые модули

var
  CreateTime,  // Дата создания
  LastAccess,  // Дата последнего доступа
  LastWrite    // Дата последней записи в файл
  : PFileTime;

  SystemTime: _SystemTime;

  FileHandle: THandle;

begin
  New(CreateTime);  // Создаем переменную под хранение даты/времени
  LastAccess:=nil;  // Не изменять эту дату/времени
  LastWrite:=nil;  // Не изменять эту дату/времени
  // Открываем некоторый файл
  FileHandle:=FileOpen('Project_test.dpr', fmOpenWrite or fmShareDenyNone);
  // Произошла ошибка - выводим диагностическое сообщение
  if FileHandle < 1 then MessageBox(0,'Не могу открыть файл','Ошибка',0);
  try
    GetSystemTime(SystemTime); // Получаем текущее системное время
    // Преобразовываем переменную к сжатому виду
    SystemTimeToFileTime(SystemTime,CreateTime^);
    // Устанавливаем дату и время для файла FileHandle
    SetFileTime(FileHandle,CreateTime,LastAccess,LastWrite);
  finally
    FileClose(FileHandle); // Закрываем дескриптор (файл)
    Dispose(LastWrite);    // Уничтожаем переменную под хранение даты/времени
  end;
end.


DillerInc 20-01-2005 23:04 290531

Savant
...хм...хм...ну,ничего себе...в любом случае спасибо - попробую :) .

Savant 21-01-2005 02:04 290565

DillerInc
Я тут сижу и думаю: какая идиллия!.. Я помогаю тебе осваивать Obj. Pascal , а frizzn по сути так же хелпает мне с Си/Си++ :)
Нет, ну просто умора :lol:

DillerInc 21-01-2005 21:07 290862

Savant
Взяв в пример код,приведённый тобой выше(который я,кстати,так и не компилировал,т.к. толку создавать программу,если я не до конца понимаю алгоритма её работы)...в общем,решил я залесть в дебри функций WinAPI(типа те,в модуле Windows.pas)и окончательно потерялся :gigi: .

Во-первых,правильно ли,что...
PFileTime = ^TFileTime
...и можно ли так объявлять эти типизированные указатели,т.е. ...
CreationTime : ^TFileTime;

Во-вторых,как понимать запись:
_SystemTime
...т.е. именно это подчёркивание впереди?

Далее имеется API-функция:
function GetFileTime(hFile: THandle;
lpCreationTime, lpLastAccessTime, lpLastWriteTime: PFileTime): BOOL; stdcall;
Хотелось бы уточнить,что представляют из себя буквы lp,например: lpCreationTime ?

Результатом этой функции является значение логического типа BOOL,спрашивается: как я могу использовать это логиское значение,если я хочу вывести,к примеру,вывести дату создания файла в Label1.Caption?И ведь,по-моему,в модулях SysUtils.pas и Windows.pas нету какой-нибудь функции типа FileTimeToDateTime,или...?

Заранее прошу прощения,если уж очень пристаю со своими вопросами :) .

Savant 22-01-2005 16:06 291087

Цитата:

Во-первых,правильно ли,что...
PFileTime = ^TFileTime
Правильно. PFileType = pointer of variable of type FileTime, а TFileTime = variable of type FileTime.

Цитата:

...и можно ли так объявлять эти типизированные указатели,т.е. ...
CreationTime : ^TFileTime;
Объявлять можно, а вот использовать вместо PFileTime... Теоретически должна вылезти ошибка о несовместимости типов, хотя не пробовал.

Цитата:

Во-вторых,как понимать запись:
_SystemTime
...т.е. именно это подчёркивание впереди?
Просто название типа переменной. Введено в Делфи для избежание путаницы с системными типами SYSTEMTIME, FILETIME. Это в принципе не должно тебя волновать, т.к. меж собой эти типы фактически равны.

Цитата:

Далее имеется API-функция:
function GetFileTime(hFile: THandle; lpCreationTime, lpLastAccessTime, lpLastWriteTime: PFileTime): BOOL; stdcall;
Хотелось бы уточнить,что представляют из себя буквы lp,например: lpCreationTime ?
Опять же, это просто сокращенное для удобства название типа переменной. h*, например, = handle, lp* = long pointer (т.е. "расширенно" можно было написать long_pointer_CreationTime и программисту сразу становится ясно, что требуется передать в функцию указатель на переменную). В си (C/C++) это действительно нужно/полезно, в Делфи - не очень, хотя иногда обращаешь внимание.

Цитата:

Результатом этой функции является значение логического типа BOOL,спрашивается: как я могу использовать это логиское значение,если я хочу вывести,к примеру,вывести дату создания файла в Label1.Caption?
Логическое значение отражает лишь факт выполнения функции (0 или отрицательное значение обычно говорит об ошибке, положительное обычно об успехе, в Делфи это соответствует False и True). Все необходимые значение переменных (в данном случае различные времена файла) записываются в соотв. переменные.

Цитата:

И ведь,по-моему,в модулях SysUtils.pas и Windows.pas нету какой-нибудь функции типа FileTimeToDateTime,или...?
Нету. А что?
Кстати есть FileTimeToSystemTime();

DillerInc 22-01-2005 17:44 291102

Savant
В общем,насчёт функции GetFileTime - в одном месте подсмотрел :biggrin: :
Код:

Procedure A;
var
 FileHandle : THandle;
 FileTime, LocalFileTime : TFileTime;
 SystemTime : TSystemTime;
 Date1 : String;
begin
 FileHandle := FileOpen(OpenDialog1.FileName, fmOpenWrite or fmShareDenyNone);
 GetFileTime(FileHandle, @FileTime,NIL,NIL);
 FileTimeToLocalFileTime(FileTime, LocalFileTime);
 FileTimeToSystemTime(LocalFileTime, SystemTime);
 Date1 := DateTimeToStr(SystemTimeToDateTime(SystemTime));
 Label1.Caption := Date1;

На основании этого хочется спросить,насколько в Delphi вообще актуально использование указателей на адреса в динамической памяти?Т.е. здесь(в представленном коде)вместо типа PFileTime используется простой TFileTime;процедура New для выделения памяти динамической переменной не используется;в месте,где необходимо использование lpпеременной используется знак @,который как я понял возвращает адрес данной переменной в памяти.Или всё-таки...?

Savant 22-01-2005 17:59 291105

DillerInc
При использовании маленьких переменных - практически все равно, что использовать - динамическое создание/уничтожение переменных ( New(), Dispose() ) или статическое. Мне просто уже привычно работать с динамическим выделением буфера и поэтому я привёл свой пример в том виде в каком привёл :biggrin: . В данном случае я действительно немного переборщил, можно было обойтись одной "собачкой", которая возвращает адрес элемента, стоящего за ней (причем не только переменной, но также функции). Процедура New необходима, когда используются буферы (переменные) по несколько МБайт.

frizzn 22-01-2005 23:26 291172

Savant
Цитата:

Опять же, это просто сокращенное для удобства название типа переменной. h*, например, = handle, lp* = long pointer (т.е. "расширенно" можно было написать long_pointer_CreationTime и программисту сразу становится ясно, что требуется передать в функцию указатель на переменную). В си (C/C++) это действительно нужно/полезно, в Делфи - не очень, хотя иногда обращаешь внимание.
В Си ( и в C++) от этих lp*, sz* и dw* имхо пользы не больше, чем в Delphi. :shuffle:

DillerInc 07-02-2005 13:19 296028

Для начала - с челобитной к ув. Модераторам: с какой стати тему окрестили как Флейм?По-моему,здесь идёт самый настоящий процесс разгрызания гранита науки :biggrin: ,т.е. на мой взгляд точнее было бы назвать тему *Практика*|Delphi. Синтаксис или что-то наподобие.
:pray:

Далее...помогите,господа,пожалуйста по следующему делу:
хочу вставить в программу возможность показа сообщения типа mtConfirmation(ну,если пользователь сделал какие-то изменения в открытом документе и хочет выйти из программы,не сохранив эти изменения.Т.к. подобного компонента-диалога в среде Delphi вроде нету,я написал пробный обработчик события нажатия кнопки:
Код:

procedure TfmExample.bbRunClick(Sender: TObject);
const
 Msg : String = 'Changes you made are not saved yet.Would you like to save them?';
 DlgType : TMsgDlgType = mtConfirmation;
 Buttons : TMsgDlgButtons = mbYesNoCancel;
var
 d : Integer;
begin
  d := CreateMessageDialog(Msg, DlgType, Buttons).ShowModal;
case d of
 mrYes : SaveDialog1.Execute;
 mrNo  : fmExample.Close;
 mrCancel : Abort;
end

end;

Проблема же заключается в том,что я почему-то не могу нормально вызвать данный диалог в самой программе,т.е. когда сделаны изменения в файле и когда пользователь выходит,не сохранившись.
Насколько я понимаю,необходимо сделать обработчик события OnCloseQuery основной формы и,применяя условные операторы,вывести в нужный момент на экран диалоговое сообщение...а вот как это сделать логически правильно?

Savant 07-02-2005 17:16 296139

Вложений: 1
Объяснять долговато, лучше на примере.
Вот, наклепал по-быстрому, но хоть понятно что-то...

DillerInc 07-02-2005 18:52 296157

Вложений: 1
Savant
Спасибо,попробую это теперь осмыслить и как-нибудь применить :) .

...код переварил,и то,что вышло,прикрепил в файле :) .
Вроде работает,но всё равно так и не смог придумать нормальную схему условных операторов в обработчике события OnCloseQuery,поэтому пришлось идти немного обходным путём.
Дело в том,что мне необходимо в этом обработчике проверить не только наличие изменений в открытом документе,но и то,сохранил ли пользователь уже этот документ или нет.И с последним пунктом у меня как раз и возникает загвоздка.

DillerInc 01-03-2005 23:44 302723

В общем,как можно догадаться - у меня снова вопросы...
...а именно,необходимо получить ссылку на какое-нибудь окно - то бишь т.н. Handle Window (HWND).И не просто получить,а вывести её как-то в виде символов,к примеру,в компоненте TLabel(метка).
Значит в чём заключается вопрос...имеется функция WinAPI :
function FindWindow(lpClassName, lpWindowName : PChar) : HWND;
...возвращающая "хэндл" искомого окна.А вот как теперь этому значению придать наглядный вид,чтобы отобразить символьно это значение в той же метке?
Возможно ли такое вообще,если да,то как?С помощью каких функций?

Savant 02-03-2005 19:09 302987

DillerInc
Сначала теория: хэндл окна представляет собой просто двойное слово, т.е. 32-битное число. Число можно представить в символьной форме функцией Int2Str. А например с помощью GetWindowText() можно получить заголовок окна. Функций работы с окнами очень много, конкретизируйте цель пожалуйста...

DillerInc 02-03-2005 20:08 303004

Savant
Цель - использование этого самого хэндла,32-битного числа,в другой программе,т.е. мне необходимо прописать в другой программе это значение как один из параметров для выполнения определённой команды.Именно поэтому мне необходимо получить символьное представление значения типа HWND.
Цитата:

Число можно представить в символьной форме функцией Int2Str
...т.е. если я правильно понял,можно сделать следующее:
Код:

procedure A;
var
 h : String;
begin
 h := IntToStr(FindWindow(TForm, Form1));
end;

...не так ли?Или...
Цитата:

А например с помощью GetWindowText() можно получить заголовок окна
...а что конкретно имеется в виду под словосочетанием "заголовок окна" - данная функция,если я не ошибаюсь,возвращает значение типа Integer?

Savant 02-03-2005 22:05 303050

DillerInc
Цитата:

если я правильно понял,можно сделать следующее...
да, можно, но нужно ли? Повторяю еще раз HWND есть не что иное, как Cardinal (беззнаковое длинное целое), не проще ли его передавать как параметр?
Цитата:

а что конкретно имеется в виду под словосочетанием "заголовок окна"
Код:

var
  S: array[0..999] of Char; // Запас всегда иметь хорошо ;)
begin
  .....
  // Записываем по адресу @S заголовок окна формы Form1
  // GetWindowText приплёл тут просто для примера,
  // можно было написать вместо него константу 1000
  GetWindowText(Form1.Handle,@S,GetWindowTextLength(Form1.Handle)+1);
  // Выводим текст в Label1
  Label1.Caption:=S;
end;

Хочу отметить также универсальность GetWindowText. Если HWND указывает на окно - возвращается заголовок окна, если на некоторый контрол, то - текстовое содержимое этого контрола (в Дельфи то же делают свойства Caption и Text).

DillerInc 02-03-2005 23:46 303071

Savant
Спасибо за информацию - будем мотать на ус :) .

DillerInc 18-08-2005 20:26 349061

Доброго всем времени суток!
Это называется - сижу, туплю...
Как можно грамотно на Delphi организовать оператор выбора case..of..end;, чтобы он был не такой примитивный как обычно его описывают,например:
Код:

case Ch of
 'n', 'N', 'н', 'Н' : lbOutput.Caption := 'Нет';
 'y', 'Y', 'д', 'Д' : lbOutput.Caption := 'Да';
end;

...а такой,чтобы каждая константа выбора содержала определённый кусок кода.

Можно сделать,конечно,и так:
Код:

if dEvent.dwDebugEventCode = LOAD_DLL_DEBUG_EVENT then  // Первый вариант константы выбора
begin
 hDllFile := dEvent.LoadDll.hFile;
if GetFileNameFromHandle(hDllFile) then
begin
 PPointer(Base) := dEvent.LoadDll.lpBaseOfDll;
 RestoreCode := InjectCode(EntryPoint, $FFFF);
end;
end;


if dEvent.dwDebugEventCode = EXCEPTION_DEBUG_EVENT then  // второй вариант константы выбора
if dEvent.Exception.ExceptionRecord.ExceptionCode =
                      EXCEPTION_ILLEGAL_INSTRUCTION then
begin
 RestoreData(EntryPoint, RestoreCode);
 DecryptStart := SeekBpPlace(Base);
 SendMessage(hMemo, WM_SETTEXT, 0,
      lParam(' * Тра-ля-ля '+IntToHex(DecryptStart, 8)));
end;

...хотя подобный код работает,но он всегда будет полностью проверять все варианты прежде,чем найдёт подходящий.На что будет уходить лишнее время,что "не есть гут" .
Следовательно - как быть ?

Savant 18-08-2005 20:56 349075

DillerInc
Не совсем понятно, как "каждая константа выбора" может содержать "определённый кусок кода" ))). Да к тому же в общем случае процессорное время будет все равно уходить (но меньше), т.к. программа будет последовательно (хотя и это зависит от компилятора, где-то могут для поиска (при большом кол-ве вариантов) использоваться другие алгоритмы) сравнивать значения, пока не найдёт подходящее.

Но если Ваша мысля дошла, то есть два (в принципе одинаковых) решения:
1) внешние операторы if преобразовать к виду
Код:

if dEvent.dwDebugEventCode = LOAD_DLL_DEBUG_EVENT then begin
  < .. >
end else
if dEvent.dwDebugEventCode = EXCEPTION_DEBUG_EVENT then begin
  < .. >
end;

2) использовать case .. of .. end =)
Код:

case dEvent.dwDebugEventCode of
  LOAD_DLL_DEBUG_EVENT:
    begin
      < .. >
    end;
  EXCEPTION_DEBUG_EVENT:
    begin
      < .. >
    end;
end;

Справка: конструкция begin .. end; (блок) являет собой один оператор, вне зависимости от того, сколько операторов в ней находится и находится ли вообще хоть один.

DillerInc 18-08-2005 22:15 349100

Savant
Спасибо за разъяснения насчёт case .. of .. end .
Сейчас вот подумал,потом глянул это дело в отладчике - действительно оба решения в принципе одинаковы :) .

DillerInc 19-08-2005 14:10 349261

Вот ещё один вопрос возник:
в Delphi есть объект класса TMemo. У его свойтсва Lines имеются методы Add и Append.
Так вот как можно с помощью WinAPI организовать процедуру,аналогичную дельфийскому методу Append ?
Т.к. если послать сообщение классу STATIC...
Код:

SendMessage(handleStatic, WM_SETTEXT, 0, lParam('К примеру '+IntToHex(some_stuff)));
...то это будет аналогично дельфийскому Add, т.е. текст целиком заменится на новый,а мне необходимо добавить этот текст...

Savant 19-08-2005 21:44 349359

Ну нет ничего проще, чем заглянуть в папку .\vcl\source\ и хорошенько там покопаться. Итогом может стать например это:
Код:

function GetLine(hwnd: Cardinal; Index: Integer): String;
// Получает строку под номером Index из контрола с Handle = hwnd
var
  Text: array[0..4095] of Char;
begin
  Word((@Text)^) := SizeOf(Text);
  SetString(Result, Text, SendMessage(hwnd, EM_GETLINE, Index, Longint(@Text)));
end;

procedure ReplaceLine(hwnd: Cardinal; Index: Integer; const S: String);
// Заменяет строку под номером Index в контроле hwnd на строку S
var
  SelStart: Integer;
begin
  SelStart := SendMessage(hwnd, EM_LINEINDEX, Index, 0);
  if SelStart >= 0 then begin
    SendMessage(hwnd, EM_SETSEL, SelStart, SelStart + SendMessage(hwnd, EM_LINELENGTH, SelStart, 0));
    SendMessage(hwnd, EM_REPLACESEL, 0, Longint(PChar(S)));
  end;
end;

procedure AddToLine(hwnd: Cardinal; Index: Integer; what: String);
// Добавляет к строке под номером Index строку what
begin
  ReplaceLine(hwnd, Index, GetLine(hwnd, Index) + what);
end;

>>Т.к. если послать сообщение классу STATIC...
Замечу, что TMemo относится к "классу" (точнее, типу) EDIT

DillerInc 20-08-2005 14:38 349488

Savant
Я немного недопонял насчёт параметра Index, который мы передаём процедуре AddToLine, т.е. откуда мы его возьмём...или... :huh:

Savant 20-08-2005 18:11 349517

Мде, заклинило меня на этом Append , с StrCat чего-то попутал :rolleyes: (подумал, что надо добавить одну строку в конец другой, а не новую строку в Memo :shuffle: ). Второе намного проще:
Код:

procedure AppendLine(hwnd: Cardinal; const S: String);
// соответствует методу Append
begin
  SendMessage(hwnd, EM_SETSEL, MaxInt, MaxInt);
  SendMessage(hwnd, EM_REPLACESEL, 0, Longint(PChar(S + #13#10)));
end;

function AddLine(hwnd: Cardinal; const S: String): Integer;
// соответствует методу Add
begin
  AppendLine(hwnd, S);
  Result := SendMessage(hwnd, EM_LINEFROMCHAR, -1, 0) - 1;
end;


DillerInc 20-08-2005 19:28 349522

Savant
Спасибо,вот теперь всё получилось :) .

DillerInc 10-02-2006 23:39 405321

Вот возникла у меня тупиковая ситуация:
Код:

var
 Buffer : array of Byte; // Есть массив байтов
 Pos : Integer;
 Bytes : DWORD; есть 32-битная переменная
begin
 Bytes := Buffer[Pos+01]; Тут хочу переслать четыре байта
end;

После компиляции команда пересылки байтов выглядит как:
mov al, [edx+01] ; в EDX располагается массив
...т.е. пересылается только один байт вместо четырёх.Приходится уже вручную править это место на:
mov eax, [edx+01]
Подскажите пожалуйста,где я туплю и как заставить компилятор пересылать в данном случае двойное слово,а не один байт.

Savant 11-02-2006 16:29 405460

вар. 1 (следить за границами!!!)
способ универсальный, когда откуда-то надо достать нужное кол-во байтов с любой позиции
Код:

var
  Buffer: array of Byte; // Есть массив байтов
  Pos: Integer;
  Bytes: Cardinal;
  BytesPtr: ^Cardinal;
begin
  BytesPtr := @Buffer[Pos+01];
  Bytes := BytesPtr^;
...

вар. 2
применительно к динамическим массивам
Код:

var
  Buffer: array of Byte; // Есть массив байтов
  Pos: Integer;
  Bytes: Cardinal;
begin
  Bytes := Cardinal(Copy(Buffer, Pos+01, 4));
...


DillerInc 11-02-2006 17:01 405465

Savant
Спасибо,что откликнулся и помог :) .
Воспользовался первым вариантом - получилось.

P.S. Хотел бы уточнить - существуют ли всё-таки какие-то различия между типами DWORD и Cardinal ??

Savant 11-02-2006 20:03 405516

DillerInc
Цитата:

Хотел бы уточнить - существуют ли всё-таки какие-то различия между типами DWORD и Cardinal ??
Абсолютно одно и то же.
32-битное беззнаковое целое, 4 байта в памяти.

serg700 11-03-2006 20:54 416635

Буду очень признателен тому, кто поможет решить такую задачу : при нахождении на форме кусора без движения 3 секунды - он должен исчезать , если пошевелить мышкой - появлятся ( как это сделано в видеоплеерах , например Light Alloy при просмотре видео на весь экран ) .

DillerInc 13-03-2006 14:21 417251

serg700
Давай пробовать :) .

Значит есть такая WinAPI-функция TrackMouseEvent,которая способна следить за состоянием курсора и отправлять соответствующие сообщения.Эти сообщения будут приниматься и обрабатываться с помощью функции WindowProc приложения.
Функция TrackMouseEvent принимает в качестве параметра указатель на структуру TRACKMOUSEEVENT,заполняя которую мы указываем особенности слежения за курсором.

Итак,нам понадобится создать функцию,обрабатывающую различные сообщения, - WindowProc:

Код:

var
 Hovering : Boolean; // переменная типа Boolean,которая сигнализирует о зависании курсора
 TME : TTrackMouseEvent;
function WindowProc(hWnd : HWND; uMsg : UINT; wParam : WPARAM;
                    lParam : LPARAM) : LRESULT; stdcall;
begin
 Result := DefWindowProc(hWnd, uMsg, wParam, lParam);
 
if uMsg = WM_MOUSEMOVE then
begin
 { Заполняем структуру TRACKMOUSEEVENT }

 TME.cbSize := SizeOf(TME);
 TME.dwFlags := TME_HOVER; // Вариант с зависанием курсора
 TME.hwndTrack := hWnd; // Описатель,который используется первым параметром в WindowProc
 TME.dwHoverTime := 3000; // три секунды зависания
 TrackMouseEvent(TME); // Вызываем саму функцию

if Hovering then // Если курсор зависал и был спрятан,
begin
 ShowCursor(True);  // то показываем его
 Hovering := False;
 end;
end;
// uMsg = WM_MOUSEMOVE

if uMsg = WM_MOUSEHOVER then // Если поступает сообщение
begin                                                        // о зависании курсора,то
 Hovering := True;                                              // прячем его
 ShowCursor(False);
end; // uMsg = WM_MOUSEHOVER

end; // WindowProc

Функция TrackMouseEvent словно бы одноразовая,т.е. сгенерировав одно сообщение,она перестаёт функционировать,поэтому её необходимо каждый раз запускать заново.Именно поэтому я поставил её инициацию в обработчик сообщения передвижения курсора (WM_MOUSEMOVE) .

P.S. Я точно не уверен возможно ли таким образом реализовать функцию WindowProc на чистом Delphi,т.е. с применением всяких там VCL и т.п.
Я это делал на примере минимального Delphi-приложения,где используется только WinAPI.
P.P.S. Вероятно описанная WindowProc не является полнофункциональной,т.к. я старался объяснить только принцип актуального вопроса.

serg700 13-03-2006 21:36 417424

DillerInc
Спасибо , попробую ; надеюсь сработает ! ;)


Время: 10:22.

Время: 10:22.
© OSzone.net 2001-