程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi函數參數中的陷阱

Delphi函數參數中的陷阱

編輯:Delphi

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;
}


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved