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;
begin
end.
調用方用C++編寫
#include "stdafx.h" #include#include 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#include 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; }