При работе с библиотеками, написанными на C++, в среде Delphi могут возникнуть трудности, особенно когда функции из DLL возвращают интерфейсы. В этом руководстве мы рассмотрим, как можно решить проблему, связанную с возвращением интерфейсов из DLL на C++ в приложениях на Delphi.
Описание проблемы
Пользователь столкнулся с проблемой при использовании DLL на C++ в среде разработки Delphi. Несмотря на успешную работу сервера и возможность доступа к базе данных через Java и PHP, при использовании динамической загрузки в Delphi функции, возвращающие интерфейсы, не работали корректно. Функции, возвращающие переменные, функционировали нормально.
Пример кода
unit SQLDBC_C;
interface
uses
Windows, Classes, SysUtils;
type
SQLDBC_IRuntime = interface
end;
var
getSDKVersion: function: PChar; stdcall;
ClientRuntime_GetClientRuntime: function(ErrorText: PChar; ErrorTextSize: Integer): SQLDBC_IRuntime; stdcall;
implementation
var
libHandle: THandle;
procedure InitLibrary;
begin
libHandle := LoadLibrary('libSQLDBC_C.dll');
if libHandle >= Handle(23) then
begin
@getSDKVersion := GetProcAddress(libHandle, 'getSDKVersion');
@ClientRuntime_GetClientRuntime :=
GetProcAddress(libHandle, 'ClientRuntime_GetClientRuntime');
end;
end;
initialization
begin
InitLibrary;
end;
finalization
begin
if libHandle >= Handle(32) then
FreeLibrary(libHandle);
end;
В тестовой процедуре Button1Click пользователь пытается вызвать функцию ClientRuntime_GetClientRuntime, которая должна возвращать интерфейс SQLDBC_IRuntime, но получает в результате nil, хотя переменная ошибок err не содержит сообщений об ошибках.
Анализ проблемы
Проблема заключается в несоответствии между соглашениями о вызовах функций в C++ и Delphi. В C++ для возврата интерфейсов часто используется соглашение о вызовах stdcall, однако Delphi ожидает, что интерфейсы будут возвращаться в соответствии с COM-стандартами, что предполагает наличие методов QueryInterface, _AddRef и _Release.
Подтвержденное решение
Пользователь нашел решение, которое заключается в использовании указателя вместо интерфейса. В объявлении функции ClientRuntime_GetClientRuntime в Delphi используется тип Pointer вместо SQLDBC_IRuntime. Таким образом, функция вызывается, и указатель на результат сохраняется в переменной rt. Затем этот указатель можно использовать для доступа к методам, обходящимся без вызовов через интерфейс.
Альтернативное решение
Если SQLDBC_IRuntime не является COM-совместимым интерфейсом, то потребуется создать промежуточный слой (bridge) в виде дополнительной DLL на C++, которая будет предоставлять функции, совместимые с Delphi. Эти функции будут общаться с оригинальным C++ кодом через объекты SQLDBC_IRuntime.
Заключение
При работе с DLL на C++ в Delphi важно учитывать различия в соглашениях о вызовах и типизации. В случае возвращения интерфейсов может потребоваться использование указателей или создание промежуточного слоя для обеспечения корректной работы функций.
Проблема заключается в несоответствии соглашений о вызовах и типизации между C++ и Delphi при работе с интерфейсами в DLL.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS