Kitobni o'qish: «Иcпользование API на Delphi 7»

Shrift:

ЛЕКЦИЯ №1

1. РАБОТА С INI – ФАЙЛАМИ

Ini-файл – это текстовый файл, в котором информация сгруппирована по секциям, ключам. Данные файлы широко применяются во многих приложениях и в операционной системе Windows для хранения различных программных данных и настроек пользователя. В таком файле можно хранить, например, положение окон программы, дату, время и продолжительность работы программы, пути к разным данным и данным, выбранные в программе настройки пользователя Ниже приведена структура и пример Ini-файла:


Для работы с Ini-файлами применяется дополнительный модуль Delhi «inifiles». Ссылку на данный модуль необходимо прописать в разделе «uses» работающей с Ini-файлами форме программы. Вся работа с Ini-файлами осуществляется через тип «TiniFile» модуля «inifiles». Основные методы данного типа следующие:



CreateОткрытие Ini-файла для чтения или записи
FreeЗакрытие открытого Ini-файла
UpdateFileОбновляет данные из/в файла на диске
SectionExistsПроверка существования в файле данной секции
ValueExistsПроверка существования в файле ключа в данной секции
ReadSectionsПолучение перечня всех секций файла
EraseSectionУдаление данной секции со всеми ее ключами
DeleteKeyУдаление ключа в данной секции
ReadSectionПолучение перечня ключей данной секции
ReadSectionValuesПолучение значений всех ключей (с именами) данной секции
ReadStringЧтение строкового значения из ключа данной секции
ReadBoolЧтение логического значения из ключа данной секции
ReadDateЧтение даты из ключа данной секции
ReadDateTimeЧтение даты и время из ключа данной секции
ReadFloatЧтение вещественного значения из ключа данной секции
ReadIntegerЧтение целого значения из ключа данной секции
ReadTimeЧтение времени из ключа данной секции
WriteStringЗапись (обновление) строкового значения в ключ данной секции
WriteBoolЗапись логического значения в ключ данной секции
WriteDateЗапись даты в ключ данной секции
WriteDateTimeЗапись даты и времени в ключ данной секции
WriteFloatЗапись вещественного значения в ключ данной секции
WriteIntegerЗапись целого значения в ключ данной секции
WriteTimeЗапись времени в ключ данной секции



Рассмотрим на подробном примере процедуру записи информации в Ini-файл:

procedure TForm1.Button3Click(Sender: TObject);

var t_Ini: TIniFile;

  k: integer; s, path_pr, nfile: string; td: tdatetime;

begin

  k:=736; s:='Okey'; td:=now;

  path_pr:=ExtractFilePath(application.exename) +'tsn.ini';

  t_Ini := TIniFile.Create(nfile);

  try

  with t_Ini do begin

     WriteInteger('TSN', 'str1', k);

     WriteFloat('TSN', 'str2', 736.123);

     WriteString('TSN', 'str3', s);

     WriteDate('TSN', 'str4', strtodate('01.02.2012'));

     WriteTime('TSN', 'str5', td);

     Writebool('TSN', 'str6', true);

  end;

  except

    showmessage('Нет доступа к Ini-файлу !');

  end;

  t_Ini.Updatefile; t_Ini.Free;

end;


Рассмотрим на примере процедуру считывания ранее сохраненной информации из Ini-файла:


procedure TForm1.Button4Click(Sender: TObject);

var t_Ini: TIniFile;

  k: integer; s, path_pr, nfile: string; td: tdatetime;

begin

  path_pr:=ExtractFilePath(application.exename) +'tsn.ini';

  t_Ini := TIniFile.Create(nfile);

  try

  with t_Ini do begin

     k:=ReadInteger('TSN', 'str1', -1); showmessage(inttostr(k));

     s:=ReadString('TSN', 'str3', '-1'); showmessage(s);

     td:=ReadDate('TSN', 'str4', strtodate('1.1.2000'));

     showmessage(datetostr(td));

     showmessage(floattostr(ReadFloat('TSN', 'str2', -1.123)));

     showmessage(timetostr(ReadTime('TSN2', 'str5', now)));

     showmessage(inttostr(byte(ReadBool('TSN2', 'str6', false))));

  end;

  except

    showmessage('Нет доступа к Ini-файлу !');

  end;

  t_Ini.Free;

end;


ЛЕКЦИЯ №2

1. РАБОТА С РЕЕСТРОМ WINDOWS


Реестр Windows – это база данных, в которой операционная система Windows и внешние программы сохраняют нужные им данные. Логическая структура реестра напоминает строение Ini-файла, отличие состоит в том, что Ini-файл состоит из разделов (секций) и ключей раздела со значениями, а реестр состоит из разделов, вложенных подразделов (неограниченное число) и ключей (параметров) разделов/подразделов со значениями.


Реестр Windows имеет древовидную структуру, подобную файловой системе, где разделы и подразделы соответствуют каталогам и подкаталогам, а ключи со значениями – именам файлов:


Рис. 1


Любая программа может сохранять свои данные или в реестре Windows или в Ini-файлах. Достоинства и недостатки использования реестра и Ini-файлов следующие:



ПараметрИспользование реестра WindowsИспользование Ini-файлов
Перенос данных с компьютера на компьютерТрудность переноса данных с использованием экспорта/импорта ветвей реестра через программу редактора реестра («regedit»)Легкость переноса данных путем простого копирования Ini-файла с одного компьютера на другой
Модификация данныхЧерез функции прикладной программы или программу редактора реестраЧерез функции прикладной программы или корректировки в обычном текстовом редакторе
Привязка к конкретному пользователю WindowsАвтоматически на уровне операционной системы через корневой раздел «HKEY_CURRENT_USER»Трудно через функции прикладной программы
Привязка к конкретному компьютеруАвтоматически на уровне операционной системы через корневой раздел «HKEY_LOCAL_MACHINE»Трудно через функции прикладной программы

Таблица 1


Реестр состоит из шести корневых разделов, два из которых представляют наибольший интерес: раздел «HKEY_LOCAL_MACHINE» предназначен для хранения данных, доступных всем пользователям Windows, а раздел «HKEY_CURRENT_USER» хранит данные, доступные только для текущего пользователя Windows. Другие корневые разделы обычно используются только операционной системой и некоторыми системными программами.


Язык программирования Delphi 5 позволяет производить с реестром Windows любые манипуляции через подключение модуля «Registry» в разделе «interface -> uses». Рассмотрим на примере основные базовые операции при записи и считывании данных с реестра:


procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

{ Процедура записи данных в реестр }

var Reg: tRegistry;

begin

  Reg:=tRegistry.Create;

  Reg.RootKey:=HKEY_LOCAL_MACHINE;

  try

    if Reg.OpenKey('\Software\TSN736\', true) then begin

      if not Reg.KeyExists('setup') then Reg.CreateKey('setup');

      if Reg.OpenKey('\Software\TSN736\setup', false) then begin

        Reg.WriteInteger('Left', form1.left); Reg.WriteInteger('Top', form1.top);

        Reg.CloseKey;

      end;

    end;

  finally

    Reg.Free;

  end;

end;


procedure TForm1.FormCreate(Sender: TObject);

{ Процедура чтения данных с реестра }

var Reg: tRegistry;

begin

  Reg:=tRegistry.Create;

  Reg.RootKey:=HKEY_LOCAL_MACHINE;

  try

    if Reg.OpenKey('\Software\TSN736\setup', false) then begin

       try form1.left:=Reg.ReadInteger('Left'); except; end;

       try form1.top:=Reg.ReadInteger('Top'); except; end;

        Reg.CloseKey;

    end;

  finally

    Reg.Free;

  end;

end;



ЛЕКЦИЯ №3

1. ПРЕОБРАЗОВАНИЕ ТИПОВ. ДОСТУП К ОБЪЕКТАМ И КОМПОНЕНТАМ ЧЕРЕЗ УКАЗАТЕЛИ

При написании обработчиков событий для компонент практически всегда в процедуру передается указатель «Sender» типа «TObject». Данный указатель как правило указывает (ссылается) на тот визуальный компонент, который вызывает данную процедуру. Параметр «Sender» является некоторым усовершенствованным аналогом ссылочной переменной языка Pascal.

Использование параметра «Sender» позволяет делать процедуры – обработчики событий универсальными, позволяющими работать не с одним конкретным компонентом, а с несколькими, имеющими одинаковый тип. Например, можно написать процедуру перемещения кнопки по экрану и привязать эту процедуру ко всем кнопкам формы, после чего все кнопки также смогут перемещаться по экрану. Для этого в процедуре-обработчике необходимо пользоваться только «Sender» конструкциями, а не явными указаниями на компоненты.

Рассмотрим способы доступа к компонентам через указатель «Sender» и методы преобразования типов:

procedure TForm1.Button2Click(Sender: TObject);

var s: TObject; ss: string;

{ Пример опознания типа объекта по указателю "Sender" }

begin

  s:=Sender; { или так: s:=button2; }

  ss:='tbutton'; { запишем имя типа кнопки в строк. переменную }

  if s.ClassNameIs(ss) then showmessage('Кнопка!');

  if (s is tbutton) then showmessage('Это кнопка типа "TButton" !')

    else showmessage('Это "'+s.ClassName+'" !');

  { Можно так }

  try (s as tbutton).caption:='Ok!!!'; except end;

  { Или так }

  tbutton(s).caption:='Ok!!!';

  { Или вот-так, если свойство не "Protected" и не "Read-only" }

  tcontrol(s).left:=300;

end;

ЛЕКЦИЯ №4

1. ТЕХНОЛОГИЯ ПЕРЕТАСКИВАНИЯ ОБЪЕКТОВ «DRAG & DROP»

Технология «Drag & Drop» («Перетащи и кинь») предназначается для перемещения (перетаскивания) данных из одних визуальных компонент в другие в процессе работы программы с помощью мыши. Данная технология делает интерфейс программы более удобным и быстрым и используется во многих системных и прикладных Windows-программах.

Технология «Drag & Drop» позволяет, например, копировать строку текста (пункт) из одного компонента формы «ListBox» в другой компонент «ListBox» или предложение из одного компонента «Memo» в другой компонент «Memo». Технология «Drag & Drop» позволяет перемещать данные из любого визуального компонента в любой другой визуальный компонент для любой формы текущего приложения. С окнами других приложений данная технология по умолчанию не работает.

Для перетаскивания данных из одних визуальных компонент в другие с помощью технологии «Drag & Drop» необходимо на этапе создания программы настроить компоненты на данную технологию и запрограммировать алгоритм их поведение при перетаскивании из (в) них данных.

Для того, чтобы компонент смог «откликаться» (выделять перетаскиваемый компонент другим цветом и менять форму курсора) на начало процесса перетаскивания из него данного, необходимо его свойству «DragMode» присвоить значение «dmAutomatic». После этого компонент сможет предоставлять выделенное данное в распоряжение технологии «Drag & Drop» для перетаскивания.

Edit1.DragMode:=dmAutomatic; ListBox1.DragMode:=dmAutomatic;

Компонент, давший данное для перетаскивания, отдает управление Widows и выходит из участия из процесса перетаскивания. Далее Windows следит за тем, куда пользователь перемещает данное по компонентам формы. Как только данное будет находится над каким-нибудь визуальным компонентом, Windows вызовет у него событие «OnDragOver» и передаст в соответствующую ему процедуру – обработчик данное о том, от кого (какого компонента) прибыло перетащенное данное. Компонент, над которым находится перетаскиваемое данное, в процедуре-обработчике события «OnDragOver» анализирует его и если ему оно нужно, то устанавливает параметру процедуры «Accept» значение «true», или значение «false» в противном случае. Значение «Accept» равное «true» озночает, что компонент не возражает принять «зависшее» над ним данное.

procedure TForm1.Edit1DragOver(Sender, Source: TObject; X, Y: Integer;

                  State: TDragState; var Accept: Boolean);

{ Можно принять (едиту), если "кидается" на него метка или данные из лист-бокса}

begin Accept := (Source is TEdit) or (Source is TListBox); end;

Если данное переместится на другой компонент, или пользователь отменит перетаскивание клавишей клавиатуры «Esc», то компонент «забывает» о «зависшем» над ним данным и нечего больше не предпринимает. Если же пользователь отпустил данное над компонентом, то у компонента возникает событие «OnDragDrop».

В обработчик события «OnDragDrop» передается данное о том, кто послал данное и в какое место компонента его кинули. Именно данная процедура обработчик (у компонента-приемника данного) реализует алгоритм перемещения данного с другого компонента в данный. Операционная система Windows в данной технологии служит только посредником для визуального отображения процесса перетаскивания, и не участвует в фактической обработке процесса переноса данных.

В процедуре – обработчике события «OnDragDrop» необходимо программно реализовать алгоритм перемещения информации из одного визуального компонента, в другой.

procedure TForm1.Edit1DragDrop(Sender, Source: TObject; X, Y: Integer);

{ Обработка факта "кидка" для едита; Sender – на кого кинули; Source – что кинули (кого) }

begin { Если кинули из лист-бокса, то …}

   if Source is TListbox then with Sender as TEdit do begin

       Text:=(Source as TListbox).items[(Source as TListbox).itemindex];

          { если кинули из другого едита , то … }

    end else (Sender as TEdit).Text:=(Source as TEdit).text;

end;

ЛЕКЦИЯ №5

1. СОЗДАНИЕ КЛИЕНТ – СЕРВЕРНЫХ СИСТЕМ

С ИСПОЛЬЗОВАНИЕМ СОКЕТНОЙ ТЕХНОЛОГИИ ПРОТОКОЛА TCP/IP

В настоящее время наиболее распространенным протоколом передачи данных в локальной сети и Интернет является протокол TCP/IP. Данный протокол позволяет передавать любые данные на любое расстояние. Протокол – это специальное программное обеспечение, входящее в операционную систему, которое реализует прием и передачу данных по сети.

При связи двух программ (компьютеров) между собой по сети через протокол TCP/IP для каждой программы операционная система создает (открывает) свой «сокет». Сокет – это буфер (канал) обмена данными по сети. Сокет открывается для конкретного экземпляра программы для указанного сетевого адреса (идентифицирующий компьютер в сети) и порта TCP/IP (идентифицирующий конкретную сетевую программу). Каждый сокет получает от операционной системы уникальный номер (дескриптор, хэндл).

При обмене данными по протоколу TCP/IP одна машина обычно выступает в роли "сервера", другая – в роли "клиента". Клиент, как и сервер, может передавать и принимать данные, отличие между ними заключается в том, что программа "сервер" может одновременно работать с несколькими "клиентами", а "клиент" – только с одним сервером. На рис. 1 показана схема модели клиент – серверного взаимодействия на основе сокетов для протокола TCP/IP.

Для создания сокетного клиента TCP/IP в Делфи используется компонент «ClientSocket», а для создания сокетного сервера компонент «ServerSocket». Используя свойства, методы и события данных компонент создадим программы «клиент» и «сервер».

2. СОЗДАНИЕ ПРОГРАММЫ TCP/IP – КЛИЕНТ НА ОСНОВЕ СОКЕТОВ

Компоненты программы – клиента:

ClientSocket1: TClientSocket – компонент сокета клиента;

Edit1 – IP-адрес сервера;

Edit2 -порт TCP/IP;

Memo1 – посылаемые на сервер данные;

ListBox1 – получаемые с сервера данные;

Button1 – активизация клиента (подключение);

Button2 – посылка данных;

Button3 – отключение клиента.

Свойства ClientSocket1:

ClientType – тип передачи данных по протоколу TCP/IP (блочная передача, не блочная);

Active – открытие/закрытие связи с сервером (сокета);

Address – IP адрес сервера TCP/IP;

Host – имя сервера TCP/IP (задается либо адрес, либо хост сервера);

Port – номер порта TCP/IP сервера;

Socket – объект доступа к сокету.

События ClientSocket1:

OnConnect – подключение к серверу;

OnDisconnect – отключение от сервера;

OnError – ошибка при подключении к серверу;

OnRead – чтение данных с сервера.

В процедуры-обработчики данных событий

передается параметр «Socket» типа

“TCustomWinSocket”. Данный параметр имеет

свойство «Socket . ReceiveText» – хранящий принятые с сервера данные.

Методы ClientSocket1:

Socket . SendText – отправка текста на сервер;

Open – подключение к серверу (открытие сокета);

Close – отключение от сервера (закрытие сокета).



procedure TForm1.Button1Click(Sender: TObject);

{ Подключение к серверу }

begin

  { Если соединение уже установлено – прерываем его }

  ClientSocket1.Close;

  { Устанавливаем не блочную передачу/прием данных }

  ClientSocket1.ClientType:=ctNonBlocking;

  { Присваиваем свойствам Address и Port нужные значения }

  ClientSocket1.Address := Edit1.Text; ClientSocket1.Port := StrToInt(Edit2.Text);

  { Пытаемся открыть сокет и установить соединение с сервером }

   ClientSocket1.Open;

end;


procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

{ Отключение от сервера }

begin

  ClientSocket1.Close;

end;


procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);

{ Прием текста от сервера }

begin

  ListBox1.Items.Text:=Socket.ReceiveText;

end;


procedure TForm1.Button2Click(Sender: TObject);

{ Отправка текста на сервер }

begin

  if ClientSocket1.Socket.SendText(Memo1.lines.Text)=0 then

     MessageDlg('Не могу отправить данные на сервер',

        mtError,[mbOk], 0) else showmessage('Ok!');

end;


procedure TForm1.ClientSocket1Error(Sender: TObject;

  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);

{ Произошла ошибка соединения с сервером }

begin

  ErrorCode:=0; MessageDlg('Нет связи с сервером', mtError,[mbOk], 0);

end;


procedure TForm1.Button3Click(Sender: TObject);

{ Отключение от сервера }

begin

  ClientSocket1.Close;

end;


procedure TForm1.ClientSocket1Connect(Sender: TObject; Socket: TCustomWinSocket);

{ Факт подключения к серверу }

begin

  ListBox1.Items.Text:='On line…';

end;


procedure TForm1.ClientSocket1Disconnect(Sender: TObject;

  Socket: TCustomWinSocket);

{ Факт отключения к серверу }

begin

  ListBox1.Items.Text:='Off line…';

end;



3. СОЗДАНИЕ ПРОГРАММЫ TCP/IP – СЕРВЕР НА ОСНОВЕ СОКЕТОВ


Компоненты программы – сервера:

ServerSocket1: TServerSocket – компонент – сокет сервера TCP/IP;

Edit1 – IP-адрес сервера;

Memo1 – посылаемые на клиент данные;

ListBox1 – полученные от клиента данные;

Button1 – запуск сервера;

Button2 – остановка сервера;

Button3 – отправка данных на клиенты.


Свойства ServerSocket1:

Active – запуск/остановка сервера (сокета);

Port – номер порта TCP/IP сервера;

Socket – объект доступа к сокету;

Socket . ActiveConnections – количество подключенных к серверу клиентов.


События ServerSocket1:

OnClientConnect – подключение клиента к серверу;

OnClientDisconnect – отключение клиента от сервера;

OnClientError – ошибка связи с клиентом;

OnClientRead – получение данных от клиента;

OnListen – ожидание подключения клиента.

В процедуры-обработчики данных событий передается параметр

«Socket» типа “TCustomWinSocket”.

Данный параметр имеет свойство

«Socket . ReceiveText» – хранящий принятые с клиента данные.


Методы ServerSocket1:

Socket . Connections[i] . SendText – отправка на i-й клиент текста;

Open – активизация сервера (открытие сервера);

Close – деактивизация сервера (закрытие сервера).

(!) Каждый сокет имеет свойство «Socket . SocketHandle» – уникальный дескриптор данного сокета, используемый для идентификации клиента (в обработчике события «OnClientRead».


procedure TForm2.Button1Click(Sender: TObject);

{ Определяем порт и запускаем сервер }

begin

  ServerSocket1.Close; ServerSocket1.Port := StrToInt(Edit1.Text); ServerSocket1.Open;

end;


procedure TForm2.Button2Click(Sender: TObject);

{ Останавливаем сервер }

begin

  ServerSocket1.Close; ListBox1.Items.Text:='Server is stop.';

end;


procedure TForm2.ServerSocket1ClientError(Sender: TObject;

  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);

{ Произошла ошибка связи с клиентом }

begin

  MessageDlg('Нет связи с клиентом', mtError,[mbOk], 0);

end;


procedure TForm2.ServerSocket1ClientRead(Sender: TObject;

  Socket: TCustomWinSocket);

{ Получение данного с клиента }

begin

  Listbox1.Items.Text:=Socket.ReceiveText;

end;


procedure TForm2.Button3Click(Sender: TObject);

{ Отправка данных на клиент }

label 1;

begin

  with ServerSocket1.Socket do begin

    if ActiveConnections=0 then goto 1;

    if Connections[0].SendText(Memo1.Lines.text)=0 then

     1: MessageDlg('Не могу отправить данные на клиент',

        mtError,[mbOk], 0) else showmessage('Ok!');

  end;

end;


procedure TForm2.ServerSocket1ClientConnect(Sender: TObject;

  Socket: TCustomWinSocket);

{ Запрет доступа "вторым" клиентам }

begin

  if ServerSocket1.Socket.ActiveConnections>1 then abort;

end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);

{ Остановка сервера }

begin

  ServerSocket1.Close;

end;

procedure TForm2.ServerSocket1Listen(Sender: TObject;

  Socket: TCustomWinSocket);

{ Ожидание подключения клиентов }

begin

  ListBox1.Items.Text:='Server is active…';

end;

ЛЕКЦИЯ №6

1. РАЗРАБОТКА DLL – БИБЛИОТЕК

Язык программирования Delphi является языком визуального объектно-ориентированного программирования (ООП). В современных программах, совместно с ООП, очень часто используется и модульный принцип создания программ. Наибольшее развитие данная технология получила в форме разработки динамически загружаемых DLL-библиотек. DLL-библиотека представляет собой отдельный файл с расширением «DLL», в котором находятся какие-либо процедуры и функции. Они становятся доступными при подключении к программе DLL-файла.

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

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

Прикладная программа на Delphi может подключать DLL-библиотеку двумя способами: динамическим и статическим. При статическом способе DLL-библиотека автоматически подключается при запуске программы и автоматически деактивируется при ее завершении. Если указанный DLL-файл будет не найден, то возникнет ошибка выполнения программы. При динамическом способе DLL-библиотека подключается и отключается в нужное программисту время, при этом обеспечивается контроль над ошибочными ситуациями (например, если DLL-файл не найден).

Для создания файла DLL в Delphi необходимо выбрать пункт меню: «File -> New Item -> DLL wizard». Исходный код DLL-библиотеки нужно набрать в открывшимся окне и сохранить как файл с расширением «DPR». Никакие формы и файлы с расширение «PAS» здесь не используются.

Для одновременной отладки и создания программы и DLL-библиотеки лучше всего запустить две копии «Delphi» и в них работать отдельно.

1.1. Пример простейшей библиотеки DLL

library demo_dll;

function sc(x: real): real export; stdcall; { Функция расчета }

begin

  xsin:=sin(x)+ cos(x);

end;

exports sc; { Экспорт процедур и функций для внешних программ }

begin { Секция инициализации библиотеки DLL }

end.

end.

1.2. Пример использования библиотеки DLL

unit Demo_dll;

…

var Form1: TForm1;

function sc(x: real): real; stdcall; external 'demo_dll.dll'; { Подключение функции из DLL-библиотеки }

implementation

procedure TForm1.Button1Click(Sender: TObject);

begin

  showmessage(floattostr(sc(5)));

end;

1.3. Пример расширенной библиотеки DLL

library repa;

uses SysUtils, Classes, Windows, Registry, StdCtrls;

procedure Save1(edit1_text: pchar; mm1: pchar; scrollbar1_position: integer); export; stdcall;

// Сохранение данных в реестр

var nfile, s: string; t: tregistry; i,k: integer; m1: tstrings;

begin

  m1:=TStringList.Create; m1.Text:=mm1;

  t:=tRegistry.Create;

  t.RootKey:=HKEY_CURRENT_USER;

  t.OpenKey('\Software\is-302\tsn-12', true);

  t.writestring('', 'repa.dll');

  t.WriteString('Edit1_text', edit1_text);

  k:=m1.count;

  t.WriteInteger('memo1_count', k);

  for i:=0 to m1.Count-1 do begin

    s:=m1[i]; t.Writestring('memo1_L'+inttostr(i+1), s);

  end;

  t.WriteInteger('scrollbar1_position', scrollbar1_position);

  t.closekey; m1.Free;

  t.Free;

  end;

procedure Load1(var edit1_text: pchar; var mm1: pchar; var scrollbar1_position: integer); export; stdcall;

// Считывание данных из реестра

var path_pr, nfile, s,m: string; t: tregistry; i,k,l: integer; m1,edit: tstrings;

begin

 m1:=TStringList.Create;

  t:=tRegistry.Create;

  t.RootKey:=HKEY_CURRENT_USER;

  t.OpenKey('\Software\is-302\tsn-12', true);

   m1.text:='';

   try

    edit1_text:=pchar(t.Readstring('edit1_text'));

   except

    edit1_text:='????';

   end;

  try

  k:=t.readInteger('memo1_count');

  for i:=0 to k-1 do begin

    s:= t.readstring('memo1_L'+inttostr(i+1));

    m1.Add(s);

  end;

  except

  end;

  mm1:=pchar(m1.text);

  try

   l:= t.readInteger('scrollbar1_position'); scrollbar1_Position:=l;

  except

  end;

  t.closekey; m1.Free; t.Free;

end;

procedure Clear1(var edit1_text: pchar; var mm1: pchar; var scrollbar1_position: integer); export; stdcall;

// Очистка данных

begin

  edit1_text:=''; mm1:=''; scrollbar1_position:=0;

end;

exports Clear1, Save1, Load1;

begin

end.

1.4. Пример использования расширенной библиотеки DLL

unit Unit1;

…

var

  Form1: TForm1;

procedure Save1(edit1_text: pchar; mm1: pchar; scrollbar1_position: integer); stdcall; external 'repa.dll';

procedure Load1(var edit1_text: pchar; var mm1: pchar; var scrollbar1_position: integer); stdcall; external 'repa.dll';

procedure Clear1(var edit1_text: pchar; var mm1: pchar; var scrollbar1_position: integer); stdcall; external 'repa.dll';

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

// Запись данных

begin

   Save1(Pchar(edit1.text), Pchar(memo1.Lines.Text), scrollbar1.Position);

end;

procedure TForm1.Button2Click(Sender: TObject);

// Очистка данных

var e,m: pchar; k: integer;

begin

  clear1(e, m, k);

  edit1.text:=e; memo1.Lines.Text:=m; scrollbar1.Position:=k;

end;

procedure TForm1.Button3Click(Sender: TObject);

// Загрузка данных

var e,m: pchar; k: integer;

begin

  Load1(e, m, k);

  edit1.text:=e; memo1.Lines.Text:=m; scrollbar1.Position:=k;

end;

end.

ЛЕКЦИЯ №7

1. API – ФУНКЦИИ WINDOWS УПРАВЛЕНИЯ ВНЕШНИМИ ПРИЛОЖЕНИЯМИ

API-функции – это набор стандартных функций операционной системы Windows, через которые можно программно управлять всеми запущенными программами и ресурсами компьютера. API-функции являются некоторым современным аналогом функциям-прерываниям INT21h MS-DOS. Возможность использовать данные функции в Делфи организуется через автоматически подключаемый модуль «Windows».

Для получения справки по API-функциям из Делфи необходимо выбрать пункт «Help > Windows SDK (Win32 Developer's References)». Данный хелп содержит подробную информацию о правилах вызова основных API- функций (синтаксис языка «С»).

Все визуальные компоненты Делфи, например «Edit, Label, Button» и др. являются окнами, как и форма. Для универсальной работы с любыми окнами используются дескрипторы (handle) окон. Дескриптор окна – это указатель на окно в виде целого числа (аналог порядкового номера), типа «HWND» (прототип «Integer»). При открытии любого окна (видимого или невидимого, типа формы или кнопки), Windows присваивает ему уникальный дескриптор. Данный указатель действителен до закрытия окна или перезагрузки Windows. Любому окну Windows может присвоить любой дескриптор.

Для того, чтобы узнать дескрипторы окон какой-либо программы, применяется программа «WinSight32» из пакета программ Delphi или другая подобная программа.


ПРИМЕР ВЫЗОВА API-ФУНКЦИИПОЯСНЕНИЕ (VAR H,H2:HWND; I: LONGWORD; S: STRING;)
GetWindowText(h, pchar(s),I);Получение текста из окна «h» в переменную «s» длиной не более «i» символов
i:=GetWindowtextLength(h);Получение длины текста из окна «h» в переменную «i»
SetWindowText(h, pchar(s));Установка текста «s» в окне «h»
h:=FindWindow(pchar(s),nil);Поиск дескриптора окна с именем класса «s» в переменную «h»
h2:=GetWindow(h, GW_CHILD);Поиск подчиненного окна «h2» для окна «h»
h2:=GetWindow(h, GW_HWNDNEXT);Поиск следующего подобного окна «h2» для окна «h»
If h=0 then WinExec(‘calc.exe’, SW_SHOWMODAL);Если искомое окно не найдено, то запустить указанную программу «calc.exe»
ShowWindow(h, SW_HIDE);Установить для окна «h» заданный режим отображения
ShowWindow(h, SW_MINIMIZE);Установить для окна «h» заданный режим отображения
ShowWindow(h, SHOWNORMAL);Установить для окна «h» заданный режим отображения
SetForegroundWindow(h);Поместить видимое на экране окно «h» поверх всех окон
SendMessage(h, WM_LBUTTONDOWN,0,0);Посылка окну «h» сообщение с параметрами (эмуляция нажатия левой кнопки мыши)
MoveWindow(h, 210,38,30,20,true);Задать окну «h» координаты x и y верхнего левого угла, ширину, высоту и флаг автоматической перерисовки окна
CloseWindow(h);Сворачивание окна «h»
PostMessage(h, WM_QUIT,0,0);Посылка сообщения для закрытия окна «h»
Edit1.Perform(WM_CHAR, byte(“!”),0);Посылка компоненту формы сообщения (эмуляция ввода символа в компонент, эмуляция нажатия стрелки вниз). Используется в собственных программах на Delphi
Combobox1.Perform(Посылка компоненту формы сообщения (эмуляция ввода символа в компонент, эмуляция нажатия стрелки вниз). Используется в собственных программах на Delphi
WM_KEYDOWN, VK_DOWN,0);
ShellExecute( handle, ’open’, ’c:\’, nil, nil, sw_shownormal)Открывает нужную папку в Проводнике
ShellExecute( Открывает документ «test.doc». Папка для временных файлов «c:\temp»
application.MainForm.handle, ’open’, ’test.doc’,
nil, ’c:\temp’, sw_shownormal)
ShellExecute( handle, ’open’, ’mailto: tsn_prof@mail.ru’, nil, nil, sw_shownormal)Открывает почтовый клиент для создания письма для заданного электронного адреса
ShellExecute(handle, ’open’, ’http://www.pau.kz’, nil, nil, sw_shownormal)Открывает Интернет-браузер для просмотра указанной WWW-страницы

2. ПРИМЕР РАБОТЫ С API-ФУНКЦИЯМИ

function GetText1(Wnd: HWND): string;

{ Получение текста из окна, способ 1 (универсальный) }

var textlength: Integer; Text: PChar;

begin

  textlength := SendMessage(Wnd, WM_GETTEXTLENGTH, 0, 0);

  if textlength = 0 then Result := '' else begin

     GetMem(Text, textlength + 1);

     SendMessage(Wnd, WM_GETTEXT, textlength + 1, Integer(Text));

     Result := Text;

     FreeMem(Text);

  end;

end;

function GetText2(h: HWND): string;

{ Получение текста из окна, способ 2 }

var i:LongWord; s:string;

begin

  i:=GetWindowTextLength(h)+1; SetLength(s,i);

  GetWindowText(h,pchar(s),i); SetLength(s,i-1);

  GetText2:=s;

end;

procedure SetTxt1 (h: HWND; s: string);

{ Установка текста в окне (универсальный) }

begin

 SendMessage(h,WM_SETTEXT,0, longint(pchar(s)));

end;

procedure SetTxt2 (h: HWND; s: string);

{ Установка текста в окне }

begin

  SetWindowText(h,pansichar(s));

end;

Procedure ClickWnd(h: HWND);

{ "Нажатие" на окно левой кнопкой мыши }

begin

  SendMessage(h,WM_LBUTTONDOWN,0,0);

  SendMessage(h,WM_LBUTTONUP,0,0);

end;

procedure ClickTB(h: HWND; BTN_ID: integer);

{ "Нажатие" на кнопку тулбара }

begin

  SendMessage(h, WM_COMMAND, BTN_ID, 0);

end;

procedure Button3Click(Sender: TObject);

{ Клик на кнопку "Добавить" в архиваторе "7z" }

var h: hwnd;

begin

  h:=Findwindow('FM',nil);

  if h=0 then winexec('C:\Program Files\7-Zip\7zFM.exe',sw_show);

  h:=Findwindow('FM',nil); sleep(1000);

  if h=0 then exit;

  SetForeGroundWindow(h);

  SetTxt2 (h,’ok’);

  MoveWindow(h,210,38,30,20,true);

  h:=GetWindow(h,gw_child);

  h:=GetWindow(h,gw_child);

  h:=GetWindow(h,GW_HWNDNEXT);

  ClickTB(h, 2000);

end;

3. СОЗДАНИЕ ПРОГРАММНЫХ ЛОВУШЕК В DELPHI

unit Loader_DLL_TSN;

…

var

  Form1: TForm1;

  procedure hook(switch : Boolean); stdcall; external 'hook_dll_tsn.dll';

 const IDM_TSN=$C0;

implementation

{$R *.dfm}

procedure TForm1.FormActivate(Sender: TObject);

var h: HWND; p, pp: HMENU;

begin

   h:=FindWindow('SciCalc',nil); if h=0 then winexec('calc',SW_SHOW);

   h:=FindWindow('SciCalc',nil); if h=0 then exit else SetForegroundWindow (h);

   hook(true); // Устанавливаем наш перехватчик событий Windows

  p:=GetMenu(h); // Верхнее меню

  // Меняем название пункта в верхнем меню "Справка"

  ModifyMenu(p, 2, MF_BYPOSITION, GetMenuItemID(p,2), '-TSN-' );

  pp:= GetSubMenu(p,2); // Подпункты в верхнем меню (с нуля отсчет)

  // Меняем название подпункта в подменю "Справка -> О программе"

  ModifyMenu(pp, 2, MF_BYPOSITION, GetMenuItemID(pp,2) , 'About Sergius …' );

  // Добавляем новый элемент подменю с идентификатором IDM_TSN

  AppendMenu(pp, MF_STRING ,IDM_TSN, 'А это новый пункт !');

  DrawMenuBar(h); // Прорисовываем модифицированное меню

end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

{ при закрытии формы – освобождаем Hook }

var h: HWND;

begin

  hook(false); // Деактивизируем наш перехватчик событий Windows

  h:=FindWindow('SciCalc',nil);

  h:=FindWindow('SciCalc',nil); if h<>0 then Postmessage(h,WM_QUIT,0,0);

end;

end.

library HOOK_DLL_TSN;

uses Windows, Messages, SysUtils;

var SysHook: HHook = 0; Wnd: Hwnd = 0;

const IDM_TSN=$C0;

function SysMsgProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;forward;

{Процедура установки HOOK-а}

procedure hook(switch : Boolean) export; stdcall;

begin

  if switch=true then

    // Устанавливаем хук на сообщения после их обработки в приложении

    // Наша процедура захвата называется "SysHook", в данном модуле

    SysHook := SetWindowsHookEx(WH_GETMESSAGE, @SysMsgProc, HInstance, 0)

  else UnhookWindowsHookEx(SysHook);

end;

function SysMsgProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;

{ Обработчик перехвата }

label 1;

var dc: HDC; h, h2: HWND; x: cardinal; ss: string;

begin

  { Если нам не стоит обрабатывать это событие, то и не надо,

    передадим упраление следующиму хуку }

  if (code<0) or (code<>HC_ACTION) then goto 1;

  // Ищем калькулятор, если он не запущен, но отдыхаем …

  h:=FindWindow('SciCalc',nil); if h=0 then goto 1;

  h2:=GetWindow(h,GW_CHILD); // Нашли окно отображения (табло) у кальулятора

  // Если калькулятор не виден, то ничего не надо …

  if not IsWindowVisible(h) then goto 1;

   // Получаем указатель на текущее обрабатываемое окно, ждем калькулятор

   Wnd:=TMsg(Pointer(lParam)^).hwnd;

    // Механизм нашей прорисовки на калькуляторе для любого окна

     ss:='Кликни правой по калку …';

     dc:=GetDC(h); SetBkMode(dc, TRANSPARENT);

     TextOut(dc,15,4,pansichar(ss),length(ss));

     // –

     x:=TMsg(Pointer(lParam)^).message; // Получаем код сообщения окна

       // Запрещаем щелкать по окошку калькулятора

       if (wnd=h2) and (x=WM_LBUTTONDOWN) then begin

             MessageBox(0, 'Нельзя !!!', 'Щелкать по окошку',0 );

             TMsg(Pointer(lParam)^).message:=0; // Анулируем сообщение

          end;

        // Механиз обработки "нашего" пункта меню в калькуляторе

         if (wnd=h) and (x=WM_COMMAND)

             and (lo(TMsg(Pointer(lParam)^).wParam) = IDM_TSN)

             then MessageBox(0, 'Да!', 'Калькулятор говорит', 0);

  { Передаем сообщение дальше по цепочке hook-ов }

1: Result:=CallNextHookEx(SysHook, Code, wParam, lParam);

end;

exports hook;

begin

end.

ЛЕКЦИЯ №8

1. РАБОТА С ПРИЛОЖЕНИЕМ «MS WORD»

unit main;

uses … ComCtrls, WordXP, OleServer, Variants;

type TForm1 = class(TForm)

…

    wa: TWordApplication;

    wd: TWordDocument;

var Form1: TForm1; t, tt, vv: OleVariant; // параметры для передачи

implementation

…

procedure TForm1.Button1Click(Sender: TObject);

var i:integer;

begin

  wa := wa.Create(nil); // создаем экземпляр Word

  wa.Visible := true; // делаем его видимым

  t := 'Normal'; // шаблон

  tt := false; // не создавть шаблон

  wa.Documents.Add(t, tt, EmptyParam, EmptyParam); // добавляем документ

  // подключаем к объекту WordDocument созданный документ

  wd.ConnectKind := ckAttachToInterface; wd.ConnectTo(wa.ActiveDocument);

  t := wd.Range; // переменная – параметр, шаблон для нового абзаца

  // добавляем в документ 3 абзаца:

  wd.Paragraphs.Add(t); wd.Paragraphs.Add(t); wd.Paragraphs.Add(t); // абзац #3

    wd.Paragraphs.Item(1).Range.InsertBefore('Привет, TSN !!!'); // вставляем текст в абзац #1

  // вставляем текст в абзац #2

  wd.Paragraphs.Item(2).Range.InsertBefore('Переключившись в программу, можно программно менять текст ячеек !');

  wd.Paragraphs.Item(1).Range.Font.ColorIndex := 11; // цвет зеленый в абзаце #1

  wd.Paragraphs.Item(2).Range.Font.ColorIndex := 5; // цвет розовый в абзаце #2

  wd.Paragraphs.Item(3).Range.Font.Bold := 1; // шрифт – жирный

  wd.Paragraphs.Item(3).Range.Font.Italic := 1; // шрифт – рукописный

  // добавляем таблицу

  wd.Tables.Add(wd.Paragraphs.Item(3).Range, 5, 4, EmptyParam, EmptyParam); // 5-строк, 4- cтолбца

  wd.Tables.Item(1).Range.Font.ColorIndex := 2; // цвет синий в таблице

  // в цикле задаем значение ячеек, добавляем текст

  for i := 1 to 5 do wd.Tables.Item(1).Cell(i, 1).Range.Text := IntToStr(i);

end;

procedure TForm1.FormDestroy(Sender: TObject);

var s: OleVariant; // для параметров

begin

  try

    s:=False; //изменения не сохранять

    wd.Close(s,EmptyParam,EmptyParam); // закрыть сначала документ

    wa.Quit(s,EmptyParam,EmptyParam); // а потом и ворд

  except end; // ничего не предпринимаем, если ворд уже закрыт

end;

procedure TForm1.BitBtn1Click(Sender: TObject);

begin

  // в соотв ячейку ставим соотв значение, а можно и наоборот

  wd.Tables.Item(1).Cell(UpDown2.Position,UpDown1.Position).Range.Text:=Edit3.Text;

end;

end.

2. РАБОТА С ПРИЛОЖЕНИЕМ «MS EXCEL»

unit Main;

….

  private

    XLApp: Variant;

  public

implementation

uses … ComObj, Variants;

const cXL1 = -4167; cXL2 = 1;

procedure TForm1.FormDestroy(Sender: TObject);

{ Уничтожение формы }

begin

  { Если открыт нужный лист Excel, то … }

  if not VarIsEmpty(XLApp) then begin

    XLApp.DisplayAlerts := False; // если True – то спрашивает о сохр.

    XLApp.Quit; // Закрытие Excel'a

  end;

end;

procedure TForm1.Button1Click(Sender: TObject);

var R, C, S: Variant; i: Integer;

begin

  XLApp:= CreateOleObject('Excel.Application'); // Подключение к Excel

  XLApp.Visible := True; // Включение Excel на экран

  XLApp.Workbooks.Add(cXL1); // Добавляем новый лист

  // Задаем листу название

  XLApp.Workbooks[1].WorkSheets[1].Name := 'Delphi Data';

  // Вставка данных в лист

  S := XLApp.Workbooks[1].WorkSheets['Delphi Data'];

  for i := 1 to 10 do S.Cells[i, 1] := i;

  S.Cells[i, 1] := '=Sum(A1:A10)'; // Вставка формулы

  // Работа с областью (рангом)

  R:=XLApp.Workbooks[1].WorkSheets['Delphi Data'].Range['C1:F25'];

  R.Formula := '=RAND()'; // Вставка формулы в ранг

  R.Columns.Interior.ColorIndex := 3; // Цвет закраски фона

  R.Font.Color := clGreen; // Цвет ранга

  R.Borders.LineStyle := cXL2; // Ячейки обрамленные

  // Работа с колонкой и шрифтом

  C:=XLApp.Workbooks[1].WorkSheets['Delphi Data'].Columns;

  C.Columns[1].ColumnWidth := 5; C.Columns.Item[1].Font.Bold := True;

  C.Columns[1].Font.Color := clBlue;

end;

end.

3. ИМПОРТ/ЭКСПОРТ ДАННЫХ ИЗ EXCEL

unit Unit1;

interface

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Grids, StdCtrls, OleServer, ExcelXP, comobj;

type

  TForm1 = class(TForm)

    ee: TExcelApplication;

    Button1: TButton;

    StringGrid1: TStringGrid;

    Button2: TButton;

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

  private

    { Private declarations }

  public

    { Public declarations }

  end;

var Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

// Импорт данных из Excel в StringGrid

var i: integer; s1,s2: string;

begin

  StringGrid1.ColWidths[0]:=120; StringGrid1.ColWidths[1]:=320;

  ee.Workbooks.Add('D:\Report11.xls ', 0);

  ee.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;

  StringGrid1.RowCount:=ee.ActiveCell.Row;

  for i:=0 to ee.ActiveCell.Row do begin

    s1:=ee.Cells.Item[8+i, 2]; s2:=ee.Cells.Item[8+i, 3];

    if s1='' then break;

    StringGrid1.Cells[0, i]:=s1; StringGrid1.Cells[1, i]:=s2;

  end; StringGrid1.RowCount:=i; ee.Disconnect;

end;

procedure TForm1.Button2Click(Sender: TObject);

// Экспорт данных из StringGrid в Excel

var e,r: Variant; i: integer;

begin

  e:=CreateOleObject('Excel.Application');

  e.Visible:=true; e.WorkBooks.Add;

  r:=e.Workbooks[1].WorkSheets[1];

  r.Columns[1].ColumnWidth := 12;

  r.Columns[2].ColumnWidth := 22;

  for i:=0 to StringGrid1.RowCount-1 do begin

    e.Cells.Item[i+1, 2]:=StringGrid1.Cells[0, i];

    e.Cells.Item[i+1, 3]:=StringGrid1.Cells[1, i];

  end;

  //e.Quit;

end;

end.

Janrlar va teglar

Yosh cheklamasi:
12+
Litresda chiqarilgan sana:
11 iyun 2021
Yozilgan sana:
2012
Hajm:
27 Sahifa 4 illyustratsiayalar
Mualliflik huquqi egasi:
Автор
Yuklab olish formati:

O'xshash kitoblar