Предлагаю вашему вниманию очередной выпуск рассылки, в котором я продолжаю обсуждать

вопросы разработки и использования DLL в Borland Delphi. Для новых подписчиков сообщаю,

что первую часть статьи они могут посмотреть в архиве рассылки, выпуск номер 13.

Прошу прощения у тех, кто писал мне, но не получил ответа. В ближайшее время постараюсь это исправить.

 

Итак, продолжим.

 

Существует два метода для импорта и загрузки функций из Dynamic Link Library (DLL). Первый метод (который широко обсуждается в данном документе), называется "неявной" (Implicit) загрузкой. Неявная загрузка включает в себя статическую загрузку DLL при запуске программы, и получение доступа к функциям через интерфейс объектного Паскаля. Данный метод должен использоваться в случае, если приложение полностью зависит от загрузки DLL для соответствующего функционирования. Другой метод доступа называется "явной" загрузкой, поскольку DLL загружается динамически по требованию. Этот метод требует дополнительного кодирования и должен использоваться, если приложению нужно работать в случае, даже если DLL не смогла правильно загрузиться.

 

Вы должны определить в программе вызываемую снаружи функцию.

 

Функция должна быть __stdcall (или WINAPI, что то же самое ;)) и иметь

четыре аргумента. Первый - HWND окна, порождаемого rundll32 (можно

использовать в качестве owner'а своих dialog box'ов), второй - HINSTANCE

задачи, третий - остаток командной строки (LPCSTR, даже под NT),

четвертый - не знаю ;).

В темах для написания статей раздела "Hello World" присутствует вопрос о динамических библиотеках и модуле ShareMem. Я хотел бы несколько расширить постановку вопроса: Пусть нам надо построить систему безболезненно расширяемую функционально. Напрашивающее ся само собой решение библиотеки динамической компоновки. И какие же грабельки разбросаны на этой тропинке?

 Грабли

 

 

Code:

procedure GetFileVersion(FileName: string; var Major1, Major2,

   Minor1, Minor2: Integer);

var

   Info: Pointer;

   InfoSize: DWORD;

   FileInfo: PVSFixedFileInfo;

   FileInfoSize: DWORD;

   Tmp: DWORD;

begin

   InfoSize := GetFileVersionInfoSize(PChar(FileName), Tmp);

   if InfoSize = 0 then

     //Файл не содержит информации о версии

   else

   begin    

     GetMem(Info, InfoSize);

     try

       GetFileVersionInfo(PChar(FileName), 0, InfoSize, Info);

       VerQueryValue(Info, '\', Pointer(FileInfo), FileInfoSize);

       Major1 := FileInfo.dwFileVersionMS shr 16;

       Major2 := FileInfo.dwFileVersionMS and $FFFF;

       Minor1 := FileInfo.dwFileVersionLS shr 16;

       Minor2 := FileInfo.dwFileVersionLS and $FFFF;

     finally

       FreeMem(Info, FileInfoSize);

     end;

   end;

end;

 

Если динамическая библиотека в процессе работы использует переменные или функции, осуществляющие динамическое выделение памяти под собственные нужды (длинные строки, динамические массивы, функции New и GetMem), а также, если такие переменные передаются в параметрах и возвращаются в результатах, то в таких библиотеках обязательно должен использоваться модуль ShareMem. При этом в секции uses модуль должен располагаться на первом месте. Об этом напоминает комментарий, автоматически добавляемый в файл динамической библиотеки при создании.

 

Управление этими операциями осуществляет специальный диспетчер печати BORLANDMM.DLL. Он должен распространяться вместе с динамическими библиотеками, использующими модуль ShareMem.

 

 

Создайте и откомпилируйте пустой проект DLL, который содержит ссылку на файл ресурсов .res, который содержит Ваши ресурсы.

 

Code:

function KillDll(aDllName: string): Boolean;

var

hDLL: THandle;

aName: array[0..10] of char;

FoundDLL: Boolean;

begin

StrPCopy(aName, aDllName);

FoundDLL := False;

repeat

   hDLL := GetModuleHandle(aName);

   if hDLL = 0 then

     Break;

   FoundDLL := True;

   FreeLibrary(hDLL);

until False;

if FoundDLL then

   MessageDlg('Success!', mtInformation, [mbOK], 0)

else

   MessageDlg('DLL not found!', mtInformation, [mbOK], 0);

end;

 

 

Пример использования:

Code:

// Закодированные MakeVersion версии можно просто сравнивать

if GetDLLVersion('SHELL32.DLL') > MakeVersion(5, 0) then

...

 // Вот так можно вывести версию DLL

 var

V: Integer;

begin

V := GetDLLVersion('SHLDOC32.DLL');

ShowMessage(IntToStr(HIWORD(V)) + '.' + IntToStr(LOWORD(V)));

end;

 

 

Code:

uses Windows;

 

procedure ShowDllPath stdcall;

var

TheFileName: array[0..MAX_PATH] of char;

begin

FillChar(TheFileName, sizeof(TheFileName), #0);

GetModuleFileName(hInstance, TheFileName, sizeof(TheFileName));

MessageBox(0, TheFileName, 'The DLL file name is:', mb_ok);

end;

 Автор: Олег Кулабухов

Следующий пример демонстрирует функцию, которая позволяет определить полный путь откуда была загружена dll:

Code:

uses Windows;

 

procedure ShowDllPath stdcall;

var

TheFileName : array[0..MAX_PATH] of char;

begin

FillChar(TheFileName, sizeof(TheFileName), #0);

GetModuleFileName(hInstance, TheFileName, sizeof(TheFileName));

MessageBox(0, TheFileName, 'The DLL file name is:', mb_ok);

end;