今天遇到一段代码,
C++的写法是
IClassFactory* pFactory = NULL;
pFactory->CreateInstance( NULL, riid, ppv);这里的IClassFactory这个interface在c++和delphi里都有定义,createinterface的三个参数具体是什么东西可以不用管它我翻译成delphi如下:
type piclassfactory=^iclassfactory;
var pfactory:piclassfactory;
pfactory.CreateInstance(nil,riid,ppv); 或 pfactory^.CreateInstance(nil,riid,ppv)这两种写法在用反汇编软件看的时候,结果是一样的。但是实际调试时发现
delphi的写法有问题
如c++的代码编译完后应该是
.text:004F1728 10C mov     esi, esp
.text:004F172A 10C mov     eax, [ebp+arg_C]
.text:004F172D 10C push    eax
.text:004F172E 110 mov     ecx, [ebp+arg_8]
.text:004F1731 110 push    ecx
.text:004F1732 114 push    0
.text:004F1734 118 mov     edx, [ebp+pfactory]
.text:004F1737 118 mov     eax, [edx]
.text:004F1739 118 mov     ecx, [ebp+pfactory]
.text:004F173C 118 push    ecx
.text:004F173D 11C mov     edx, [eax+0Ch]
.text:004F1740 11C call    edx        
但是delphi编译出来的确是
.text:0045A20A 020 lea     eax, [ebp+arg_0] ; Load Effective Address
.text:0045A20D 020 push    eax
.text:0045A20E 024 mov     eax, [ebp+var_8]
.text:0045A211 024 push    eax
.text:0045A212 028 push    0
.text:0045A214 02C mov     eax, [ebp+pfactory]
.text:0045A217 02C mov     eax, [eax]          //这句多余
.text:0045A219 02C push    eax
.text:0045A21A 030 mov     eax, [eax]          //这句多余
.text:0045A21C 030 call    dword ptr [eax+0ch]其中delphi带不带^运算符编译出来的是一样的,十分奇怪,也就是说delphi多了一次多余的[eax]操作,不知我翻译的写法问题出在哪?

解决方案 »

  1.   

    Delphi的反汇编代码完全正确!与C++反汇编代码的区别在于你在Delphi中定义的类型问题。
    接口Iclassfactory类型在Delphi中本身就是指针类型,相当于C++的IClassFactory*,你再定义:
    piclassfactory=^iclassfactory;
    就是指针的指针了,既然是指针的指针类型,肯定要多取一次值了:
    .text:0045A214 02C mov     eax, [ebp+pfactory]
    .text:0045A217 02C mov     eax, [eax]
      

  2.   

    谢谢楼上,试了一下,的确是这个问题、
    另外问一下是vc里面可以用这种方法去定义并访问一个借口,以itest为例
    CComPtr<Itest> m_test;
    CreateInstance( NULL, riid, (void**)&m_test);那么转成delphi该是什么呢?
    这里的Itest是个接口名,riid可以不管我写成
    var
    m_test:itest;
    CreateInstance(nil,riid,@m_test);
    不知道对不对
    还有就是上面vc的那种定义方法
    CComPtr<Itest> m_test;
    实际上是生成了itest接口的一个实例对象
    而delphi的var m_test:itest呢?是定义了一个指针但是没有内容?
    这两种语言生成的m_test是一样的么?
      

  3.   

    Delphi接口的访问是借助Delphi类访问的,比如你说的Itest接口,就必须用Delphi类来实现它:TTest = class(TInterfacedObject, Itest)
    ....
    end;使用接口时:
    var
      test: Itest;
    begin
      test := TTest.Create;
      test.xxxx
    end;
    如果事先不知道TTest是否有Itest的实现代码,可以进行判断:
    var
      Obj: TTest;
      test: Itest;
    begin
      Obj := TTest.Create;
      if Supports(Obj, Itest, test) then
        test.xxxx
    end; 
      

  4.   

    接口对应有个类我知道,但是如果直接用这个类去create对象,会要求dll必须是注册过的,而vc里面可以直接调用非注册的dll,通过Createinstancefromdll函数去调用,我的目的是将这个函数重写成delphi的。
    但是重写过程中发现很多不好实现的地方
    例如vc的interface实际上就是class,而delphi的接口就是指针。等等这是Createinstancefromdll的代码
    HINSTANCE CreateInstanceFromDll(LPCTSTR lpDllName, REFCLSID rclsid, REFIID riid, LPVOID * ppv)
    {
    (*ppv) = NULL; HINSTANCE hDll = LoadLibrary( lpDllName );
    if ( NULL == hDll )
    {
    return NULL;
    } typedef HRESULT (__stdcall *GETCLASS_PROC)(REFCLSID,REFIID,LPVOID*); GETCLASS_PROC procGetClassObject = (GETCLASS_PROC)GetProcAddress( hDll, "DllGetClassObject" );  if( procGetClassObject )
    {
    IClassFactory* pFactory = NULL; HRESULT hr = procGetClassObject(rclsid, IID_IClassFactory, (void**)&pFactory);
    if( pFactory )
    {
    hr = pFactory->CreateInstance( NULL, riid, ppv); pFactory->Release();
    pFactory = NULL; if( NULL == *ppv )
    {
    FreeLibrary( hDll );
    return NULL;
    }
    }
    else
    {
    FreeLibrary( hDll );
    return NULL;
    }
    }
    else
    {
    FreeLibrary( hDll );
    return NULL;
    } return hDll;
    }
    调用的时候
     CreateInstanceFromDll(_T("test.dll"),  CLSID_test, IID_Itest, (void**)&m_test);
    其中m_test就是itest类型的实例
    这是vc的做法,转成delphi,我发现问题多多
      

  5.   

    Delphi接口的实现,不必再写QueryInterface,AddRef,Release,使用接口对象的方法时,一般情况下,也不必调用这3个方法。另外,接口对象不需要释放,如果非要释放,不能用Free,而直接:
    test := nil;即可
      

  6.   

    从Dll中获取接口对象也可以的,CreateInstanceFromDll的ppv参数本身就是指针的指针类型,直接将如前面定义的Itest变量test的地址传过去就行了
      

  7.   

    不行,实际测试的时候会出错,
    以下是我的翻译后的delphi代码
    function CreateInstanceFromDll(lpDllname:pansichar;var rclsid:TGUID;var riid:TGUID;ppv:PPointer):hwnd;
    var
    hDll:hwnd;
    pFactory:iclassfactory;
    hr:hresult;
    procGetClassObject:function (var rclsid:TGUID;var riid:TGUID;ppv:PPointer):hresult;stdcall;
    begin
      ppv:=nil;
      hdll:=loadlibrary(lpdllname);
      if 0=hdll then
      begin
        result:=0;
      end;
      @procGetClassObject:=GetProcAddress(hdll,'DllGetClassObject');
      if not(@procGetClassObject = nil) then
      begin
        pfactory:=nil;
        hr:=procgetclassobject(rclsid,IID_IClassFactory,ppointer(@pfactory));
        if pfactory<>nil then
        begin
          hr:=pfactory.CreateInstance(nil,riid,ppv);  //这里的函数调用结果不对,vc下ppv调用后是获得了返回值的,而delphi这个翻译代码获得的是nil
          pfactory:=nil;
          if ppv=nil then
          begin
            freelibrary(hdll);
            result:=0;
          end;
        end
        else
        begin
          freelibrary(hdll);
          result:=0;
        end;
      end
      else
      begin
        freelibrary(hdll);
        result:=0;
      end;
    end;调用的时候采用
    Createinstancefromdll(testdll',CLSID_test,IID_Itest,ppointer(&m_test));
    但是在我标注的那个地方出错了
      

  8.   

    额,那是往bbs上贴的时候的笔误,实际上写的是@
      

  9.   

    函数中ppv使用不正确。如ppv:=nil;应该是ppv^ := nil;
    如果你不想动里面的代码,把函数说明改一改:
    function CreateInstanceFromDll(lpDllname:pansichar;var rclsid:TGUID;var riid:TGUID;var ppv:Pointer):hwnd;procGetClassObject:function (var rclsid:TGUID;var riid:TGUID;var ppv:Pointer):hresult;stdcall;