Раздел "Кодинг". Содержание:
Статьи:
Копирование и удаление файлов в Delphi
Поговорим о случайных числах в Delphi
Создаем гиперссылку в Delphi
Как узнать информацию о системе в Delphi
Смотрим в глубь DLL средствами Delphi
Раздел "Кодинг". Рассылка от ведущего раздела:
Раздел "Кодинг". Статьи:
 | Копирование и удаление файлов в Delphi |
|
В этой статье мы рассмотрим различные
варианты копирования и удаления файлов с
помощью Delphi. Попробуем осуществить
копирование файла по частям. Узнаем о том,
как удалять непустые каталоги с
подкаталогами, а так же еще много полезной
информации.
В самом простом случае вопрос копирования
файлов очень прост (хотя поступило много
пожеланий рассказать именно об этом)! Для
этого достаточно посмотреть в хелп по Delphi
:))
Копирование файлов
В Delphi есть функция CopyFile. Вот ее
описание из хелпа
BOOL CopyFile(
LPCTSTR lpExistingFileName, // pointer to name of an existing file
LPCTSTR lpNewFileName, // pointer to filename to copy to
BOOL bFailIfExists // flag for operation if file exists
);
Параметры передаваемые в эту функцию:
Указатель на имя существующего файла (нуль
терминированная строка т.е. тип PChar! )
Указатель на имя файла, который будет
создан/перезаписан после копирования (нуль
терминированная строка т.е. тип PChar! )
Если этот параметр True и файл с таким
именем уже существует, то функция вернет False.
Если же файл, с именем указанным во втором
параметре существует и в качестве
третьего параметра передан False - то
функция перезапишет файл и благополучно
завершится.
Приведу небольшой пример использования
этой функции. Создайте на диске C:\ файл '1.txt',
а на форму поставьте кнопку:
procedure TForm1.Button1Click(Sender: TObject);
begin
if CopyFile('c:\1.txt','c:\2.txt',true) then
ShowMessage('Файл успешно скопирован!')
else ShowMessage('Неудача!');
end;
Для того, чтобы точнее узнать при возникновении
ошибки, что же все таки произошло, надо
воспользоваться функцией GetLastError,
которая возвращает код последней ошибки (формат
DWORD). Теперь мы немного изменим пример:
procedure TForm1.Button1Click(Sender: TObject);
begin
if CopyFile('c:\1.txt','c:\2.txt',true) then
ShowMessage('Файл успешно скопирован!')
else
ShowMessage('Ошибка! Вот ее код: '+IntToStr(GetLastError));
end;
Таким образом нажав второй раз на
кнопку мы получим сообщение: "Ошибка! Вот
ее код: 80". Это говорит нам, что файл
существует.
Коды всех ошибок можно
легко найти в хелпе.
Для углубления
рассматриваемого вопроса приведу пример
копирования файлов с помощью файлового
потока (TFileStream). В приведенной
пользовательской функции введены два
дополнительных параметра From и Count,
которые указывают, соответственно, с какого
и по какой байт нужно копировать файл. Если
необходимо скопировать весь файл, то
необходимо передать нули. Вот код этой
функции:
function MyCopyFile( InFile,OutFile: String; From,Count: Longint ): Longint;
var
InFS,OutFS: TFileStream;
begin
InFS := TFileStream.Create( InFile, fmOpenRead );//создаем поток
OutFS := TFileStream.Create( OutFile, fmCreate );//создаем поток
InFS.Seek( From, soFromBeginning );//перемещаем указатель в From
Result := OutFS.CopyFrom( InFS, Count );
InFS.Free;//освобождаем
OutFS.Free;//освобождаем
end;
Удаление файлов
Для удаления файлов в Delphi так же
предусмотрена специальная процедура DeleteFile.
В качестве параметра, передаваемого в
функцию, выступает строка типа PChar,
указывающая имя файла, который нужно
удалить. Сразу предлагаю Вам простой
пример на использование этой функции:
procedure TForm1.Button1Click(Sender: TObject);
begin
if DeleteFile('c:\2.txt') then
ShowMessage('Файл успешно удален!')
else
ShowMessage('Ошибка! Вот ее код: '+IntToStr(GetLastError));
end;
Удаление пустой директории
Чтобы удалить пустую директорию с
помощью Delphi достаточно обратиться к
функции RemoveDir.
function RemoveDir(const Dir: string): Boolean;
Эта функция возвращает True если
директория, указанная в единственном
параметре, передаваемом в функцию, успешно удалена, в противном случае функция
возвратит False.
Часто возникает необходимость удалить
непустую папку, содержащую не только файлы,
но и другие вложенные папки. Для этого
была написана пользовательская функция,
удаляющая папку со всеми файлами и
поддиректориями. Вот она:
Function MyRemoveDir(sDir : String) : Boolean;
var
iIndex : Integer;
SearchRec : TSearchRec;
sFileName : String;
begin
Result := False;
sDir := sDir + '\*.*';
iIndex := FindFirst(sDir, faAnyFile, SearchRec);
while iIndex = 0 do begin
sFileName := ExtractFileDir(sDir)+'\'+SearchRec.Name;
if SearchRec.Attr = faDirectory then begin
if (SearchRec.Name <> '' ) and
(SearchRec.Name <> '.') and
(SearchRec.Name <> '..') then
MyRemoveDir(sFileName);
end else begin
if SearchRec.Attr <> faArchive then
FileSetAttr(sFileName, faArchive);
if NOT DeleteFile(sFileName) then
ShowMessage('Could NOT delete ' + sFileName);
end;
iIndex := FindNext(SearchRec);
end;
FindClose(SearchRec);
RemoveDir(ExtractFileDir(sDir));
Result := True;
end;
А сейчас пример использования этой
функции:
procedure TForm1.Button1Click(Sender: TObject);
begin
if MyRemoveDir('C:\testDir') then ShowMessage('Директория успешно удалена')
else ShowMessage('Не получается удалить директорию');
end;
Общие замечания по данной теме
Перед копированием или удалением файлов
всегда проверяйте его наличие функцией FileExists:
if FileExists('c:\1.txt') then
if CopyFile('c:\1.txt','c:\2.txt',true) then
ShowMessage('Файл успешно скопирован!')
Чтобы использовать в функциях CopyFile
и DeleteFile имена файлов полученные с
помощью, например, OpenDialog, надо из привести
к типу PChar:
if CopyFile(Pchar(OpenDialog1.FileName),Pchar(SaveDialog1.FileName),true) then
...
Всегда следите за именами файлов,
используемых в функциях. Обращайте
внимание на абсолютные и относительные
пути. Из-за этого часто возникают ошибки,
которые сложно отследить!
Ну вот наверно и все, что я хотел бы
рассказать Вам о копировании и удалении в
Delphi.
 | Поговорим о случайных числах в Delphi |
|
В этой статье я постараюсь рассказать Вам,
что такое генератор случайных чисел, как им
пользоваться и как всегда рассмотрим
примеры использования случайных чисел в
Delphi.
Процедура Randomize
Эта процедура инициализирует (проще
говоря запускает) генератор случайных
чисел. Надо также заметить, что генератор
случайных чисел может быть инициализирован
не только с помощью обращения к Randomize, но
и с помощью присвоения переменной RandSeed (об
этом поговорим ниже).
Без инициирования генератора случайных
чисел обращения к соответствующим функциям
выбора случайного числа всегда будут
давать один и тот же результат.
Получение случайного числа
Для того, чтобы получить случайное число
нужно воспользоваться функцией Random. Вот
ее заголовок:
function Random [ ( Range: Integer) ];
Если обращаться к функции без параметров,
то она вернет значение типа Real в
диапазоне:
0 <= X < 1
А если в качестве
параметра указано целое число k, то функция
вернет целочисленное значение в диапазоне:
0 <= X < k,
или, для наглядности, можно
записать так:
0 <= X <= k-1
Важно что реализация функции Random может
меняться в зависимости от версии
компилятора, поэтому не рекомендуется
использовать эту функцию, например, в
шифровании.
Пример использования
функции Random.
Вы легко можете собрать
небольшой тир, используя таймер и картинку
Image, ну и конечно же генератор случайных
чисел.
Поставим на форму таймер Timer1 и
картинку Image1 (не забудьте загрузить в
нее изображение) и
напишем обработчик события OnTimer
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Randomize; //запускаем генератор случайных чисел
Image1.left:=Random(Form1.width);
Image1.top:=Random(Form1.height);
end;
Мы просто каждый раз меняем случайным
образом координаты изображения, которое
начинает двигаться по форме беспорядочно.
Хотя здесь было бы логичнее Randomize вызвать
один раз при загрузке формы.
Теперь
сделаем реакцию на попадание в картинку.
Естественно это событие OnClick для
картинки:
procedure TForm1.Image1Click(Sender: TObject);
begin
Timer1.Enabled:=false; //остановим таймер
Showmessage('Попадание в цель!');
Timer1.Enabled:=true; //запустим его обратно end;
Здесь можно было бы вести учет очков,
уменьшение линии жизни картинки и еще какие-нибудь
игровые финты. Увеличить скорость игры
можно просто уменьшив свойство Interval
таймера.
Вот и готова простая игра.
Заполним
массив с помощью Random
Randomize;
//заполним массив
for i:= 1 to 10 do a[i]:=Random(10);
//Выведем массив на канву формы
for i:= 1 to 10 do Canvas.TextOut(10+10*i,10,IntToStr(a[i]));
Массив в любом случае будет содержать
неотрицательные элементы, чтобы заполнить
массив еще и неотрицательными элементами
надо написать так:
for i:= 1 to 10 do a[i]:=Random(20)-10;
Таким образом диапазон значений массива будет (-10 .. 9)
Получение
случайного числа с помощью RandSeed
Запустить
генератор случайных можно получить и без
вызова процедуры Randomize. Это делается с
помощью переменной RandSeed. Вот пример,
демонстрирующий это:
procedure TForm1.Button1Click(Sender: TObject);
var RandSeed: LongInt;
begin
RandSeed:=random(10);
ShowMessage(IntToStr(RandSeed));
end;
Вот мы и поговорили о случайных числах в
Delphi. Надеюсь, что каждый почерпнет хоть
маленько нового для себя в этой статье.
 | Создаем гиперссылку в Delphi |
|
На самом деле создать гиперссылку в Delphi
очень просто. Алгоритм тут такой: мы ставим
на форму метку (TLabel), приводим ее внешний
вид к привычному нам виду гиперссылки в
нашем браузере (рассмотрим на примере IE), и
пишем обработчик события OnClick.
Чтобы нам можно было постоянно
использовать гиперссылку в наших
программах, мы создадим компонент!
Сейчас мы на простом примере разберемся с
созданием ссылки в Delphi, а затем оформим все
в виде компонента. Начинаем с того, что
ставим на форму нашего проекта метку (TLabel),
пусть ее имя останется Label1. Теперь мы
напишем обработчик события OnClick, для нее:
procedure TForm1.Label1Click(Sender: TObject);
begin
ShellExecute(handle,'open','http://winsov.com/',nil,nil,SW_SHOW);
end;
Теперь поясню, что мы здесь написали.
Функция ShellExecute предназначена для
открытия или печати файла, как исполняемого,
так и документа. Первый параметр это handle
родительского окна, второй параметр -
строка, указывает, что надо сделать с файлом,
третий параметр содержит имя открываемого
файла, четвертый параметр указывает
дополнительные параметры запуска
исполняемого файла, пятый параметр
определяет директорию по умолчанию,
последний параметр определяет где будет
отображен файл после октрытия.
!!! Кстати если Вы уже попробовали
запустить приведенный код, то скорее всего
у Вас ничего не вышло, потому что функция ShellExecute,
находится в модуле ShellAPI, который
конечно же надо добавить в секцию uses,
кода нашего приложения.
Теперь разберем параметры относительно
нашего случая:
- handle - это дескриптор главной формы (аналогично
Form1.handle)
- open - тип действия с файлом. Нам надо
его открыть.
- http://www.winsov.com - имя
файла, который надо открыть. У нас это
может быть гиперссылка, содержащая
абсолютный URI.
- nil - здесь никаких дополнительных
параметров открытия файла не должно быть,
поэтому nil.
- nil - директория по умолчанию нас так
же не интересует.
- SW_SHOW - активирует окно и отображает
его с текущими размерами и положением. Об
остальных режимах можно узнать в хелпе (о
функции ShellExecute).
Надо отметить, что второй и третий
параметры функции являются нуль
терминированными строками, т.е. строками
типа PChar, поэтому для использования в
функции имени файла, полученного из OpenDialog1,
нужно использовать PChar(OpenDialog1.Filename).
Поскольку
в браузере (при настройках по умолчанию)
ссылка меняет цвет в зависимости от своего
состояния и действий пользователя. Мы тоже
сделаем так. Для этого заведем три
константы (в них будут определяться цвета), которые надо поместить в раздел Implementation:
...
implementation
Const
link = clBlue; //цвет ссылки
alink = clRed; //цвет ссылки в момент нажатия
vlink = clPurple; // цвет посещеной ссылки
{$R *.DFM}
...
Теперь в обработчике события формы OnCreate
надо написать:
procedure TForm1.FormCreate(Sender: TObject);
begin
Label1.font.Color:=link;
end;
В обработчике события метки OnMouseDown мы напишем:
procedure TForm1.Label1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Label1.Font.Color:=alink;
end;
А в обработчике события OnMouseUp нашей
метки мы напишем:
procedure TForm1.Label1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Label1.Font.Color:=vlink;
end;
Для придания полной реалистичности нашей
ссылке, надо установить свойство метки Cursor
в crHandPoint. Т.е. при наведении на ссылку
указатель будет иметь вид привычной нам
кисти руки с вытянутым указательным
пальцем и сделать ссылку подчеркнутой.
Ну вот и
разобрались, а теперь напишем компонент. Там все предельно
просто и понятно, поэтому объяснения напишу только в виде
комментариев в коде.
В
качестве родительского класса (Ancestor Type) мы
конечно же должны выбрать TLabel.
Привожу полный код модуля компонента Link
класса Tlink (текст модуля надо сохранить в
файле Link.pas):
unit Link;
interface
uses
Windows, SysUtils, Classes, Forms, StdCtrls, ShellAPI, Menus,
Controls, Graphics;
type
TLink = class(TLabel)
private
//поле для хранения URL
FURL: string;
// поля для хранения настроек цветов
ссылки
FlinkColor, FAlinkColor, FVlinkColor: TColor;
protected
public
//конструктор и деструктор
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
//события, которые нам надо переопределить
procedure Click; override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
published
//свойства, которые будут видны в Object Inspector
property URL: string read FURL write FURL;
property LinkColor: TColor read FLinkColor write FLinkColor default clBlue;
property ALinkColor: TColor read FALinkColor write FALinkColor default clRed;
property VLinkColor: TColor read FVLinkColor write FVLinkColor default clPurple;
end;
procedure Register;
implementation
constructor TLink.Create( AOwner : TComponent );
begin
inherited Create(AOwner);
//устанавливаем цвета
FALinkColor := clRed;
FLinkColor := clBlue;
FVLinkColor := clPurple;
//сделаем метку синей и подчеркнутой
with Font do begin
Color := FLinkColor;
Style := [fsUnderline];
end;
end;
procedure TLink.Click;
begin
inherited Click;
//если поле URL заполнено, то перейдем по
ссылке
if FURL <> '' then
ShellExecute(GetDesktopWindow(), 'open', PChar(FURl), nil, nil, SW_SHOW);
end;
procedure TLink.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then begin
FLinkColor := Font.Color;
Font.Color := FALinkColor;
end;
inherited;
end;
procedure TLink.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
Font.Color := FVLinkColor;
inherited;
end;
destructor TLink.Destroy;
begin
//уничтожим компонент
inherited;
end;
procedure Register;
begin
//надо, чтобы компонент появился в палитре
RegisterComponents('http://winsov.com/', [TLink]);
end;
end.
Вот мы и разобрались с созданием гипер-ссылок
в Delphi, как оказалось все очень просто!
 | Как узнать информацию о системе в Delphi |
|
Вы, возможно, видели нестандартные дельфийские компоненты, позволяющие сделать лог системы. Сейчас мы самостоятельно реализуем что-нибудь не хуже.
Прежде всего, где хранится эта самая системная инфа? В Реестре, куда мы сможем залезть, добавив модуль
Registry в раздел Uses. Версия системы, имя владельца и т.д. имеют следующий адрес:
HKEY_LOCAL_MACHINE\Software\Microsoft \Windows\CurrentVersion\Explorer
Или (для Windows NT):
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft \Windows NT\CurrentVersion
А информация о системных папках хранится здесь:
HKEY_CURRENT_USER\Software\Microsoft \Windows\CurrentVersion\Explorer\Shell Folders
В то же время данные о некоторых системных устройствах хранятся в файле
System.ini. Значит, добавим модуль IniFiles, чтобы осуществить чтение информации из этого файла. Таким образом, если вы умеете работать с Реестром и Ini, узнать системную информацию вам будет так же просто, как сделать FORMAT C: COMPLETE из-под загрузочного диска. Изюминка в том, что наше приложение, которое эту инфорнмацию собирает и записывает в лог-файл, будет консольным, и создать его можно через File>New>Other>Console Application.
program OSInfo;
uses
SysUtils,
Windows,
Registry,
IniFiles; //!!
//ключи реестра, в которых будем искать информацию
const
folders = 'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders';
WinVers = 'Software\Microsoft\Windows\CurrentVersion';
var
F: TextFile; //файл с логом
SerialNum: PDWord;
a: DWord;
i: integer;
Drive, WinDir: String;
buffer: array [0..255] of char;
ms: TMemoryStatus;
//читаем информацию из Реестра
function WinInfo(Root_Key: HKEY; Key_Open, Key_Read: string): string;
var
registry: TRegistry;
begin
//если Windows NT, открываем другой ключ
if ((GetVersion and $80000000)=0) and (Key_Open=WinVers) then
Key_Open:='SOFTWARE\Microsoft\Windows NT\CurrentVersion';
Registry := TRegistry.Create;
try
Registry.RootKey := Root_Key;
Registry.OpenKey(Key_Open, False);
Result := Registry.ReadString(Key_Read);
finally
Registry.Free;
end;
//если ничего не найдено, выводим "невозможно определить"
if Result<>EmptyStr then Result:=Key_read+': '+Result else Result:=Key_read+': невозможно определить';
end;
//читаем из System.ini
function GetDevice(Section, Ident: String): String;
var inifile: TIniFile;
begin
IniFile:=TIniFile.Create(windir+'\system.ini');
result:=IniFile.ReadString(Section,ident,'неизвестное устройство');
IniFile.Free;
end;
begin
//Узнаем директорию Винды. Она нам еще понадобится
GetWindowsDirectory(buffer, SizeOf(buffer));
windir:=buffer;
AssignFile(F,Windir+'\OSInfo.txt'); //Соединямся с файлом лога
ReWrite(F); //Переходим в начало файла
WriteLn(F,'Лог создан: '+DateTimeToStr(now));
WriteLn(F,'');
//пользователь, версия ОС и т.д.
WriteLn(F,' О Системе:');
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'RegisteredOwner'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'RegisteredOrganization'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'ProductID'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'ProductKey'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'ProductName'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'Version'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'VersionNumber'));
//Какой браузер?
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'Plus! VersionNumber'));
WriteLn(F,'');
WriteLn(F,' Память:');
WriteLn(F,'Доступные носители: ');
//Получаем информацию о дисках
for i := 0 to 25 do
if (GetLogicalDrives and (1 shl i)) <> 0 then begin
Drive:=Char(Ord('A') + i) + ':\';
case GetDriveType(PChar(Drive)) of
DRIVE_REMOVABLE: WriteLn(F,Drive+' (гибкий диск)');
DRIVE_CDROM: WriteLn(F,Drive+' (CD-ROM)');
DRIVE_FIXED: begin
//находим серийный номер жесткого диска
new(SerialNum);
if getVolumeInformation(pChar(Drive),buffer,sizeof(buffer),SerialNum,a,a,nil,0) then
WriteLn(F,Drive+' (жесткий диск, S\N '+Inttostr(SerialNum^)+')');
end;
else WriteLn(F,Drive+' (неизвестный диск');
end;
end;
//информация о памяти
GlobalMemoryStatus(MS);
WriteLn(F,'Оперативная память: '+FormatFloat('#,###" KB"', MS.dwTotalPhys / 1024));
WriteLn(F,'Свободно на жестком диске: '+FormatFloat('#,###" байт"',DiskFree(3)));
//"3" указывает на диск C:\
WriteLn(F,'Объем жесткого диска: '+FormatFloat('#,###" байт"',DiskSize(3)));
WriteLn(F,'');
//узнаем об устройствах из System.ini
WriteLn(F,' Устройства:');
WriteLn(F,'Клавиатура: '+getDevice('boot.description','keyboard.typ'));
WriteLn(F,'Мышь: '+getDevice('boot.description','mouse.drv'));
WriteLn(F,'Дисплей: '+getDevice('boot.description','display.drv'));
WriteLn(F,'Хранитель экрана: '+getDevice('boot','SCRNSAVE.EXE'));
WriteLn(F,'');
//читаем системные папки из Реестра
WriteLn(F,' Системные папки:');
GetCurrentDirectory(SizeOf(buffer), buffer);
WriteLn(F,'Текущий каталог: '+buffer);
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Cache'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'ConfigPath'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Cookies'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Desktop'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Favorites'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Fonts'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'History'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Local AppData'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'MediaPath'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'My Music'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'My Pictures'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'NetHood'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Personal'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'PrintHood'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'ProgramFilesDir'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'CommonFilesDir'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Programs'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Recent'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'SendTo'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Start Menu'));
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'StartUp'));
GetSystemDirectory(buffer, SizeOf(buffer));
WriteLn(F,'System: '+buffer);
GetTempPath(Sizeof(buffer),buffer);
WriteLn(F,'Temp: '+buffer);
WriteLn(F,WinInfo(HKEY_CURRENT_USER,folders,'Templates'));
WriteLn(F,WinInfo(HKEY_LOCAL_MACHINE,WinVers,'WallPaperDir'));
WriteLn(F,'Windows: '+WinDir);
Close(F); //отсоединяемся от файла
end.
Результаты сохранятся в директории Windows в файле OSInfo.txt. Чтобы ознакомиться с ними, вам достаточно открыть этот файл.
Такое приложение весит 156 кило. А если бы мы создали "нормальную" программу с формой, размер был бы в два-три раза больше.
 | Смотрим в глубь DLL средствами Delphi |
|
Не раз приходилось получать письма
с просьбой рассказать о создании и
использовании DLL в Delphi. В этой статье мы с
Вами во всем разберемся и создадим свою
библиотеку.
Динамически связанные библиотеки (Dinamic
Link Library) дают возможность различным
приложениям при своей работе использовать
общий набор ресурсов. Важно то, что
процедуры и функции, помещенные в DLL,
выполняются внутри того процесса, который
их использует. DLL предоставляет для всех
приложений одну единственную копию ресурса,
который совместно используется всеми
запросившими его приложениями, в отличие от
подпрограмм, которые запускают для каждого
вызвавшего их приложения свою отдельную
копию. Так же в отличия DLL от подпрограмм
можно включить и то, что DLL могут
экспортировать только процедуры и функции,
но не типы, константы и т.д.
Хочется привести отрывок из "Уроков по Дельфи" о структуре DLL в памяти:
DLL - библиотека, в отличие от приложения не имеет ни стека, ни очереди сообщений. Функции, помещенные в DLL, выполняются в контексте вызвавшего приложения, пользуясь его стеком. Но эти же функции используют сегмент данных, принадлежащий библиотеке, а не копии приложения.
В силу такой организации DLL, экономия памяти достигается за счет того, что все запущенные приложения используют один модуль DLL, не включая те или иные стандартные функции в состав своих модулей.
Часто, в виде DLL создаются отдельные наборы функций, объединенные по тем или иным логическим признакам, аналогично тому, как концептуально происходит планирование модулей ( в смысле unit ) в Pascal. Отличие заключается в том, что функции из модулей Pascal компонуются статически - на этапе линковки, а функции из DLL компонуются динамически, то есть в run-time.
Создание DLL
Структура DLL мало чем отличается от обычной
структуры модуля в Object Pascal. Начинаться DLL
должна со слова Library, за которым помещается
название библиотеки. Функции и процедуры,
которые DLL будет предоставлять другим
пользователям (экспортировать),
перечисляются после директивы exports.
Для каждой процедуры или функции можно
указать ее номер с помощью директивы Index.
Если номер будет отсутствовать, то
компилятор проведет автоматическую
индексацию. Вместо номера процедуры можно
использовать уникальное имя, которое
задается с помощью директивы name. Если же
не указано ни имени функции, ни ее номера, то
Дельфи воспримет это как экспорт по имени,
которое будет совпадать с названием
функции.
Библиотека может содержать
также и код инициализации, который будет
выполнен при ее загрузке. Он помещается
между begin и end. Вот общая структура DLL:
library First_Dll;
uses
<используемые модули>;
<объявления и описания функций>
exports
<экспортируемые функции>
<описание процедур и функций>
begin
<инициализационная часть>
end.
Приведу примеры описания
экспортируемых функций в разделе exports
exports
Function1 index 2;
Fucntion2 name 'My_sqr';
Function3;
Как Вы уже догадались, имя
функции может не совпадать с именем для
экспорта!!!
Использование DLL
Модуль, в котором необходимо использовать
процедуры и функции из DLL должен
использовать директиву external.
Существует два способа использования DLL (динамический
и статический). В первом случае, приложение
вызывающее функцию из DLL знает имя
библиотеки и точку входа в нее, при этом
предполагается, что библиотека не меняется.
Во втором случае перед использованием DLL
следует убедиться, что требуемая
библиотека существует, и в ней есть
необходимая подпрограмма.
Импортировать подпрограмму можно по ее
имени и номеру. Поиск подпрограммы по
номеру происходит быстрее, но всегда это
удобно. Ниже приведены примеры импорта
функций из нашей First_DLL, которая была
рассмотрена в примере:
{ импорт по специфицированному имени }
Function ImportByName; external 'First_DLL' name 'My_sqr';
{ импорт по индексу }
Function ImportByOrdinal; external 'First_DLL' index 2;
{ импорт по оригинальному имени }
Function Fucntion3; external 'First_DLL';
Мы рассмотрели статический метод
использования DLL. Но в некоторых случаях
заранее не известно какая именно
потребуется библиотека, поэтому следует
воспользоваться динамическим методом:
uses
WinTypes, WinProcs, ... ;
type
TMyProc = procedure ;
var
Handle : THandle;
MyImportProc : TMyProc;
begin
Handle:=LoadLibrary('FirstDLL');
if Handle>=32 then { если <=32 - ошибка ! }
begin
@MyImportProc:=GetProcAddress(Handle,'My_sqr');
if MyImportProc<>nil then
...... {здесь используем полученную
функцию}
end;
FreeLibrary(Handle);
end;
Но по-моему все что здесь написано не
очень-то понятно и хочется реальных
завершенных примеров. Я всегда
расстраивался, когда в статьях было мало
примеров, а одна только теория, поэтому
предлагаю Вашему вниманию простой пример
использования DLL.
Нажмите в меню File -> New и
выберите DLL. Сохраните готовый шаблон, как
предлагается, под именем Project1.dpr. Ниже
приведен его полный код:
library Project1;
uses
SysUtils,
Classes;
Function Function1(x,y:integer):integer; export;
Begin
Result:=x+y;
End;
Function Function2(x,y:real):real; export;
var t:real;
Begin
t:=exp(y*ln(x));
Result:=t;
End;
exports
Function1 index 1,
Function2 name 'My_sqr';
begin
end.
Здесь две функции, первая вычисляет сумму
двух чисел и экспортируется по номеру, а
вторая вычисляет x в степени y и
экспортируется по имени. Теперь создадим
новый проект и сохраним его под каким-нибудь
другим именем, например, DemoDLL. Разместим на
форме две кнопки, щелчок на первой из них
будет вызывать первую процедуру, а щелчок
на второй - вторую. Вот полный код этого демо-проекта:
unit
demo;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function ImportSumm(x,y:integer):integer;external 'Project1' index 1;
//импорт по номеру
function ImportSqr(x,y:real):real;external 'Project1' name 'My_sqr'; //импорт
по имени
procedure TForm1.Button1Click(Sender: TObject);
var t:real;
begin
//Узнаем сколько же будет два в третьей степени
t:=ImportSqr(2,3);
Showmessage(FloatTostr(t));
end;
procedure TForm1.Button2Click(Sender: TObject);
var t:integer;
begin
//Узнаем сколько же будет 10+10
t:=ImportSumm(10,10);
Showmessage(IntTostr(t));
end;
end.
Ну вот, надеюсь хоть немного прояснил
ситуацию :))
|