1. 程式人生 > >動態調用dll遇到的問題

動態調用dll遇到的問題

call _stdcall cde advance 默認 turn 三方 cad tox

問題:動態調用第三方提供的dll報錯。

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

調用源碼:

typedef bool (WINAPI *SEALPARSE)(unsigned char*, int, char*);
static int ConvertAsnToXml(unsigned char* asnBuffer, int bufferLen, char** xmlData)
{
	HINSTANCE hDllInst = LoadLibrary("DllSESealParse.dll");
	if(hDllInst == NULL){
		::MessageBox(NULL,"DllSESealParse.dll加載失敗!","錯誤",IDOK);
		return -1;
	}else{
		SEALPARSE asnToXml = NULL; 
		asnToXml = (SEALPARSE)GetProcAddress(hDllInst, "SESealParse_SESealDataASNToXml");

		if(asnToXml)
		{
			*xmlData = (char*)malloc(40*1024);
			bool bRet = asnToXml(asnBuffer, bufferLen, *xmlData);
		}
		FreeLibrary(hDllInst);
	}
	return 0;
}

  


錯誤原因:

定義函數指針原型時出錯。

其實定義的沒有錯,但是編譯器不認識而已,因為調用的dll函數是一個遠函數,而且是一個C函數,必須告訴編譯器它是個c函數才行。那麽就可以在定義該函數的時候加上一句話,

FAR PASCAL 或者 __stdcall 這個就OK了。

具體做法:

比如說你要定義一個 返回類型為空,參數為空的函數指針:

typedef void (*LPFUN)(void);

這樣確實跟我們dll裏的函數匹配了,上面也說了,我們應該添上幾個字,告訴編譯器這個是一個遠的C函數。

typedef void (WINAPI *LPFUN)(void);

typedef void (__stdcall *LPFUN)(void);


typedef void (FAR PASCAL *LPFUN) (void);

像上面這樣定義就OK了,如果用的是VC++,那麽直接用第一種定義就ok了。

註意,上面是使用 MFC (DLL)的做法。

如果是WIN32 DLL,得相應的去掉WINAPI ,__stdcall ,FAR PASCAL 這幾個參數。因為WIN32 DLL 默認的入棧方式為 __cedcall方式,不是__stdcall方式。


具體的組合方式太多了,反正知道錯誤的原因是聲明相應的函數未匹配就行了。實在不行,一個一個的試吧

解決方法:

查看:Project->Properties->Configuration Properties->C/C++->advanced->calling Convention 為 __cdecl

將代碼中的

typedef bool (WINAPI *SEALPARSE)(unsigned char*, int, char*);

修改為typedef bool (__cdecl *SEALPARSE)(unsigned char*, int, char*);

動態調用dll遇到的問題