動態調用dll遇到的問題
問題:動態調用第三方提供的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遇到的問題