在delphi中使用C dll什么都不返回

时间:2012-09-28 22:57:56

标签: delphi dll dllimport

我一直在尝试根据这个documentation在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提出的类似问题,但它无法解决我的问题。

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

2 个答案:

答案 0 :(得分:3)

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

问题是already explained。作为您的案例的解决方法,您可以在Delphi ClientRuntime_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); 

答案 1 :(得分: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的可用性。这意味着你不能使用Delphi的SQLDBC_IRuntime

您需要创建一个C ++桥DLL,以Delphi可以调用的方式公开该功能。例如,通过公开调用SQLDBC_IRuntime的C ++方法的普通旧函数。