function abc(A: Integer): Integer; 这是一个Delphi的函数声明,看上去很简单,只有一个参数而已,但是真实情况呢?在编译成二进制代码后,实际上函数的参数已经有3个了! 为了更详细的说明问题,先用Delphi写一个DLL,导出一个接口,接口有一个Show方法。
function abc(A: Integer): Integer;
这是一个Delphi的函数声明,看上去很简单,只有一个参数而已,但是真实情况呢?在编译成二进制代码后,实际上函数的参数已经有3个了!
为了更详细的说明问题,先用Delphi写一个DLL,导出一个接口,接口有一个Show方法。
library Project1;uses Windows;{$R *.res}type ITest = interface procedure Show(); stdcall; end; TTest = class(TInterfacedObject, ITest) public procedure Show(); stdcall; end;function GetTest: ITest; stdcall;begin Result := TTest.Create;end;exports GetTest;{ TTest }procedure TTest.Show;begin OutputDebugString('Hello World');end;beginend.
调用方用C++编写
#include "stdafx.h"#include<iostream>#include<Windows.h>interface ITest : public IUnknown{ virtual void __stdcall show() = 0;};typedef ITest* (WINAPI *GetITest)();int _tmain(int argc, _TCHAR* argv[]){ HMODULE h = LoadLibrary(TEXT("Project1.dll")); if (h != 0) { GetITest get = (GetITest)GetProcAddress(h, "GetTest"); ITest *test = get(); test->show(); test->Release(); } system("pause"); return 0;}
运行后直接弹出一个内存错误
出错语句在DLL中
function GetTest: ITest; stdcall;begin Result := TTest.Create;end;
以反汇编代码的形式查看这个函数就能发现问题
可以看到,函数返回值实际上是一个隐式的参数,是一个二级指针。在Dephi中使用不会发现问题,因为它自动作出了优化。
而在混合编程中,这样直接返回一个接口或对象的时候就会出现内存为空的错误。
修改后的调用代码
#include "stdafx.h"#include<iostream>#include<Windows.h>interface ITest : public IUnknown{ virtual void __stdcall show() = 0;};// 正确的函数原型typedef VOID (WINAPI *GetITest)(ITest**);int _tmain(int argc, _TCHAR* argv[]){ HMODULE h = LoadLibrary(TEXT("Project1.dll")); if (h != 0) { GetITest get = (GetITest)GetProcAddress(h, "GetTest"); // 修改后的调用方法 ITest *test = nullptr; get(&test); test->show(); test->Release(); } system("pause"); return 0;}