1

我一直在尝试根据此文档在 delphi 中重用 C dll 文件。

服务器运行良好,我可以通过 java 和 php 访问和使用本地服务器上的数据库。

在 delphi 上,我使用了动态加载,并且在所有返回变量的函数上运行良好,但在返回接口的函数上失败了。

unit for library :
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>=23 then begin
     @getSDKVersion:=GetProcAddress(libhandle,'getSDKVersion');
     @ClientRuntime_GetClientRuntime:=
        GetProcAddress(libhandle,'ClientRuntime_GetClientRuntime');
  end;
end;

initialization
begin
  initLibrary;
end;

finalization
begin
  if libhandle>=32 then
    FreeLibrary(libhandle);
end;

end.

这是测试程序:

procedure TForm1.Button1Click(Sender: TObject);
var
  err : array [0..200] of char;
  rt : SQLDBC_IRuntime;

begin
  Memo1.Clear;
  FillChar(err, sizeof(err), 0);
  Memo1.Lines.Add(getSDKVersion); //this function successed

  rt := ClientRuntime_GetClientRuntime(@err,200); 
  //this function had no return value, (rt always nil) but no error return at err variable
  if assigned(rt) then begin
    ......
  end;
end;

我读过geskillDan HackermaxRon提出的类似问题,但它无法解决我的问题。

谁能告诉我这里有什么问题?

4

2 回答 2

3

我无法测试它,因为我没有libSQLDBC_C.dll.

问题已经解释过了。作为您的案例的解决方法,您可以在 DelphiClientRuntime_GetClientRuntime声明中返回一个指针

ClientRuntime_GetClientRuntime: function (errorText:Pchar;
                                errorTextSize:Integer): Pointer; stdcall;

并将其转换为SQLDBC_IRuntime接口:

var
  err : array [0..200] of char;
  rt : SQLDBC_IRuntime;

begin
  Pointer(rt):= ClientRuntime_GetClientRuntime(@err,200); 
于 2012-09-29T04:45:52.487 回答
3

返回接口的 C++ 函数不容易映射到 Delphi 函数。Delphi 中托管类型的返回值的调用约定与 C++ 使用的不匹配。

为了说明,我创建了一个导出此函数的简单 C++ 测试 DLL:

extern "C" __declspec(dllexport) IUnknown* __stdcall GetInterface()
{
    CoInitialize(NULL);
    IUnknown* result;
    CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, 
      IID_IUnknown, (void**) &result);
    return result;
}

将其映射到 Delphi 的明显方法是这样的:

function GetInterface: IUnknown; stdcall; external DLL name '_GetInterface@0';

但是,当我们调用此函数时,它总是返回nil.

解决方法完全按照 Serg 的建议:

function GetInterface: Pointer; stdcall; external DLL name '_GetInterface@0';

然后我们可以这样称呼它:

var
  intf: IUnknown;
....
Pointer(intf) := GetInterface;

当我们这样做时,intf不是nil,我们可以很高兴地调用它的方法。

所以,我们在这里了解到的是,Delphi 不能轻易调用返回接口的外部函数,除非这些外部函数也在 Delphi 中实现。但至少我们有一个可行的解决方法。


不幸的是,这种解决方法对您没有立即用处。那是因为 SQLDBC_IRuntime它是一个 C++ 类。它不是 COM 兼容接口。注意SQLDBC_IRuntime不实现IInterface。所以它不提供_AddRef,_ReleaseQueryInterface。Delphi 的接口支持基于IInterface. 这意味着您不能SQLDBC_IRuntime从 Delphi 使用。

您将需要创建一个 C++ 桥 DLL,以 Delphi 可以调用的方式公开功能。例如,通过公开调用SQLDBC_IRuntime.

于 2012-09-29T08:08:41.870 回答