如何从C dll到 Delphi 获取接口?

x759pob2  于 2022-11-29  发布在  其他
关注(0)|答案(1)|浏览(130)

我有一个用C写的库,我有一个头文件,里面有用C写的接口的描述。DLL有一个函数来获取这个接口。如何正确地描述它,并在 Delphi 应用程序中获取它?

using DllCallbackClassPtr = void*;
    using DllCallbackFunction = void(*)(const char *, DllCallbackClassPtr);

    #ifdef _WIN32

    #include <Windows.h>

    __interface IXeoma
    {

    public:
        enum ConnectErrorCode {
            OK = 0,
            SERVER_NOT_FOUND,
            WRONG_PASSWORD,
            UNKNOWN
        };

        // return ConnectErrorCode
        virtual int start(const char* connectionString) = 0;
        virtual bool isConnected() = 0;
        virtual void stop() = 0;

        virtual void requestData(const char* request, const char* additionalData, DllCallbackClassPtr classPtr, DllCallbackFunction callbackFunc) = 0;
        virtual const char* getRequestResult(const char* request) = 0;

        virtual void setCameraRenderHandle(const char* previewId, HWND hWnd) = 0;

    };

库已加载,但函数返回nil。

type
       IXeoma = interface
         function Start(connectionString: PChar): integer;
       end;

    type
        TCreateXeomaInterface = function() : IXeoma; stdcall;

    var
        Form1: TForm1;
        CreateXeomaInterface: TCreateXeomaInterface;

    implementation

    {$R *.dfm}

    var
        LibraryHandle: THandle;

     procedure TForm1.Button1Click(Sender: TObject);
    var
        XeomaInt: IXeoma;
        i: integer;
    begin
        LibraryHandle := LoadLibrary(PChar('D:\Projects\XeomaSDK\Win32\Debug\xeomaclientdll.dll'));
        if LibraryHandle >= 32 then
        begin
            @CreateXeomaInterface := GetProcAddress(LibraryHandle, 'createXeomaInterface');
        end;
        XeomaInt := CreateXeomaInterface();
        // Here XeomaInt = nil
    end;
7uzetpgm

7uzetpgm1#

Visual C中的__interface扩展和 Delphi 中的interface关键字不是一回事,彼此不兼容。
C
代码中的IXeoma只是一个普通的类类型,而不是COM接口。但是在 Delphi 中,所有的interface都是从IUnknown派生的,所有的class都是从TObject派生的,在这种情况下,这两个都不是你想要的。所以,你将不得不使用一个普通的record来代替。并声明TCreateXeomaInterface作为返回指向该记录 * 指针 *。
另外,请注意, Delphi record不能有virtual方法,但C类有它们,所以您必须在Delphi中手动说明C类的vtable。
请尝试以下操作:

type
  DllCallbackClassPtr = Pointer;
  DllCallbackFunction = procedure(Param1: PAnsiChar; Param2: DllCallbackClassPtr); cdecl;

  IXeomaPtr = ^IXeoma; 

  IXeomaVTable = record
    start: function(_Self: IXeomaPtr; connectionString: PAnsiChar): Integer; cdecl;
    isConnected: function(_Self: IXeomaPtr): Boolean; cdecl;;
    stop: procedure(_Self: IXeomaPtr); cdecl;
    requestData: procedure(_Self: IXeomaPtr; request: PAnsiChar; additionalData: PAnsiChar; classPtr: DllCallbackClassPtr; callbackFunc: DllCallbackFunction); cdecl;
    getRequestResult: function(_Self: IXeomaPtr; request: PAnsiChar): PAnsiChar; cdecl;
    setCameraRenderHandle: procedure(_Self: IXeomaPtr; previewId: PAnsiChar; hWnd: HWND); cdecl;
  end;

  ConnectErrorCode = (
    OK = 0,
    SERVER_NOT_FOUND,
    WRONG_PASSWORD,
    UNKNOWN
  ); 

  IXeoma = record
    vtable: ^IXeomaVTable:
  end;

type
  TCreateXeomaInterface = function() : IXeomaPtr; stdcall;

var
  Form1: TForm1;
  CreateXeomaInterface: TCreateXeomaInterface;

implementation

{$R *.dfm}

var
  LibraryHandle: THandle;

procedure TForm1.Button1Click(Sender: TObject);
var
  XeomaInt: IXeomaPtr;
  i: integer;
begin
  XeomaInt := nil;
  LibraryHandle := LoadLibrary('D:\Projects\XeomaSDK\Win32\Debug\xeomaclientdll.dll');
  if LibraryHandle >= 32 then
  begin
    @CreateXeomaInterface := GetProcAddress(LibraryHandle, 'createXeomaInterface');
    XeomaInt := CreateXeomaInterface();
    if XeomaInt <> nil then
      XeomaInt^.vtable^.start(XeomaInt, '123:123@localhost:8090'); 
  end;
  ...
end;

相关问题