Delphi: два способа вызвать функцию из DLL
Delphi может вызывать экспортированные функции Windows DLL. Есть два разных способа: объявление external и явная загрузка через API Windows. Это альтернативы: после external не требуется вручную получать адрес той же функции.
Статический импорт через external
Для консольного проекта Windows объявите импорт до основного begin. В примере ReadSystemTicks — локальное имя функции, GetTickCount64 — имя экспорта в системной DLL.
program StaticDllDemo;
{$APPTYPE CONSOLE}
function ReadSystemTicks: UInt64; stdcall;
external 'kernel32.dll' name 'GetTickCount64';
begin
Writeln(ReadSystemTicks);
end.Программа выводит число миллисекунд с запуска Windows. Оно меняется; это не календарная дата. При обычном external загрузчик разрешает импорт при старте. Если библиотека или экспорт отсутствуют, программа может не запуститься.
Явная загрузка и проверка ошибки
Этот отдельный консольный пример рассчитан на современную Windows и Delphi с Winapi.Windows. Загрузка ограничена системным каталогом; функция вызывается только при успешном получении адреса.
program DynamicDllDemo;
{$APPTYPE CONSOLE}
uses System.SysUtils, Winapi.Windows;
type
TReadTicks = function: UInt64; stdcall;
var
Lib: HMODULE;
ReadTicks: TReadTicks;
begin
Lib := LoadLibraryEx('kernel32.dll', 0,
LOAD_LIBRARY_SEARCH_SYSTEM32);
if Lib = 0 then
RaiseLastOSError;
try
@ReadTicks := GetProcAddress(Lib, 'GetTickCount64');
if not Assigned(ReadTicks) then
RaiseLastOSError;
Writeln(ReadTicks());
finally
FreeLibrary(Lib);
end;
end.После FreeLibrary вызывать сохранённый указатель нельзя. Для сторонней DLL выбирайте доверенный путь и учитывайте загрузку зависимостей. Наличие DLL не означает безопасность её кода.
Почему правильная сигнатура важнее приведения типа
- Разрядность DLL и процесса должна совпадать.
- Тип результата, порядок и типы параметров, соглашение о вызовах должны соответствовать объявлению экспорта.
- Имя для GetProcAddress чувствительно к регистру; внутреннее имя функции может отличаться от экспортированного.
- Строки, память и объекты через границу DLL требуют явного соглашения о владении; не передавайте Delphi-объекты в произвольный C API.
Сначала проверьте простой вызов с известным результатом. Падение после возврата часто связано с несовместимой сигнатурой; повторная загрузка библиотеки эту ошибку не исправляет.