...я также имею проблемы с другими функциями DLL, которые ведут себя иначе, чем при первом обращении к ним!

 Недавно я и сам закончил большой "DLL-проект", в котором столкнулся с аналогичными проблемами. Я не знаком с вашим специфическим исключением, которое вы упомянули, но я могу предложить некоторые общие советы по поводу использования DLL.

 Главное, что нужно помнить при разработке DLL - вы не должны допускать ситуацию, при которой любое исключение осталось бы неперехваченным (спасибо Pat Ritchey за столь мудрый совет). В теле экспортируемых функций "заверните" все в блоки try..except (которые замечательно обрабатываются Delphi).

 

 

Делаешь текстовый файл с ресурсами, типа

 

--my.rc--

STRINGTABLE

{

00001, "My String #1"

00002, "My String #2"

}

 

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

 

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

 

 

Иногда на форуме проскакивает такой вопрос: "Как можно поглядеть экспортируемые ф-ии какой либо длл'ины?".

Можно конечно же воспользоваться стандартными утилитами, но можно попробовать написать и что нить свое.

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

Подробно расписывать тут ничего не буду, тут идет разбор элементов PE заголовка - нахождение таблицы экспорта,

перечисление ф-ий. Недостаток этого примера в том, что он работает уже с подгруженными модулями, т.к. для нахождения

базы используется GetModuleHandle().

 

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;

 

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

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

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

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

 

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

 

 

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;

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

Существует два метода для импорта и загрузки функций из 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;