Программирование: Использование DLL и .NET сборок

При помощи Pascal-сценариев можно вызывать функции из внешних библиотек DLL. Сюда относятся как стандартные функции API Win32 из системных библиотек Windows, так и пользовательские функции из пользовательских библиотек DLL. Кроме того, поддерживается вызов .NET сборок.

Пример использования внешних библиотек DLL показан в файле сценария "CodeDll.iss" из папки "Examples" по месту установки Inno Setup.

Папка "Examples" также содержит три примера проекта создания пользовательских DLL: один для Microsoft Visual C++, один для Microsoft Visual C# и один для Borland Delphi. Проект для C# демонстрирует пример создания .NET сборки, совместимой с Pascal-сценарием.

Для вызова функции из библиотеки DLL сначала, как обычно, следует записать прототип функции, но вместо тела функции необходимо использовать ключевое слово 'external' и указать DLL. Если, к примеру, функция имеет прототип function A(B: Integer): Integer;, то для неё поддерживаются следующие три формы:

[Code]
function A(B: Integer): Integer;
external '<dllfunctionname>@<dllfilename>';

function A(B: Integer): Integer;
external '<dllfunctionname>@<dllfilename> <callingconvention>';

function A(B: Integer): Integer;
external '<dllfunctionname>@<dllfilename> <callingconvention> <options>';

Первая форма определяет вызов DLL-функции с использованием соглашения о вызовах по умолчанию, т.е. 'stdcall'. Все стандартные функции API Win32 и большинство пользовательских DLL-функций используют 'stdcall'.

Вторая форма определяет вызов DLL-функции с использованием специального соглашения о вызовах. Допустимыми соглашениями о вызовах являются: 'stdcall' (по умолчанию), 'cdecl', 'pascal' и 'register'.

Третья форма определяет один или несколько параметров загрузки DLL, разделённых пробелами:

delayload

Определяет отложенную загрузку библиотеки DLL. Как правило, при запуске Pascal-сценарий проверяет доступность вызываемых DLL-функций и в случае отсутствия одной из них прекращает свою работу. Этого не произойдёт, если указать отложенную загрузку 'delayload': библиотека будет загружена не сразу, а только при первом обращении к функции. Используйте отложенную загрузку, когда не знаете, что при выполнении вызываемая DLL-функция будет фактически доступной. В случае невозможности её вызова Pascal-сценарий продолжит свою работу, но вызовет исключение, которое можно перехватить и корректно обработать отсутствие DLL-функции.

loadwithalteredsearchpath

Определяет загрузку библиотеки DLL с флагом LOAD_WITH_ALTERED_SEARCH_PATH, который, по сути, заставляет загрузчик выполнять поиск зависимых DLL, начиная с каталога, в котором находится DLL.

setuponly

Определяет загрузку библиотеки DLL только при выполнении сценария из программы установки.

uninstallonly

Определяет загрузку библиотеки DLL только при выполнении сценария из программы удаления.

Например (вторая форма), если в библиотеке DLL функция называется 'A2', файл DLL имеет имя 'MyDll.dll' и DLL-функция использует соглашение о вызовах 'stdcall', то код записывается следующим образом:

[Code]
function A(B: Integer): Integer;
external 'A2@MyDll.dll stdcall';

Имя файла DLL может содержать константы.

При установке можно использовать специальную приставку 'files:', чтобы инструктировать программу установки автоматически извлекать один или более файлов DLL, указанных в секции [Files], до загрузки первой библиотеки DLL. Например:

[Files]
Source: "MyDll.dll"; Flags: dontcopy
Source: "A.dll"; Flags: dontcopy
Source: "B.dll"; Flags: dontcopy

[Code]
procedure MyDllFunc(hWnd: Integer; lpText, lpCaption: AnsiString; uType: Cardinal);
external 'MyDllFunc@files:MyDll.dll stdcall';

procedure ADllFunc(hWnd: Integer; lpText, lpCaption: AnsiString; uType: Cardinal);
external 'ADllFunc@files:A.dll,B.dll stdcall loadwithalteredsearchpath'; //A.dll зависит от B.dll   

Когда используется приставка 'files:' и включено непрерывное сжатие, постарайтесь разместить все файлы DLL в начале списка файлов секции [Files]. Чтобы извлечь произвольный файл в инсталляторе с непрерывным сжатием, программа установки должна будет сперва распаковать все предыдущие файлы, используя временный буфер в памяти. Это может привести к существенной задержке в работе инсталлятора, если перед необходимым файлом DLL перечислен ряд других файлов.

Используйте CreateCallback для выполнения вызова из DLL-функций напрямую в функции вашего сценария (подобно функциям API Windows).