動態調用DLL函數有時正常,有時報Access violation的異常

動態調用DLL函數有時正常,有時報Access violation的異常

動態調用DLL函數有時正常,有時報Access violation的異常


typedef int (add *)(int a,int b);


void test()
{
    hInst=LoadLibraryA("aimdtl.dll");
   (FARPROC &)add=GetProcAddress(hInst,"add");
    add(1,2);
}


按這個代碼執行,add函數有時OK,有時報Access violation的異常。看到提示,第一反應就是內存異常了,但是這是什麼引起了內存異常呢?
於是想着用一個變量來接收add的返回值看看。


void test()
{
    hInst=LoadLibraryA("aimdtl.dll");
   (FARPROC &)add=GetProcAddress(hInst,"add");
   int sum=add(1,2);
}
結果,add函數執行了之後,還是有時OK,有時報Access violation的異常。這會是什麼原因?於是谷歌了下,有人提到,可能要加__cdecall。於是我果斷修改代碼。新代碼如下:


typedef int __cdecall (add *)(int a,int b);


void test()
{
    hInst=LoadLibraryA("aimdtl.dll");
   (FARPROC &)add=GetProcAddress(hInst,"add");
    add(1,2);
}


結果,add函數執行了之後,還是有時OK,有時報Access violation的異常。糾結了!爲什麼 !!這時,想起在C中調用DLL函數時,需要用__stdcall,那是不是這裏也要?立即改之!




typedef int __stdcall (add *)(int a,int b);


void test()
{
    hInst=LoadLibraryA("aimdtl.dll");
   (FARPROC &)add=GetProcAddress(hInst,"add");
    add(1,2);
}




運行後,一切OK。問題至此已經解決。可這是爲什麼呢?於是回過頭來看了看__stdcall和__cdecall的說法。


_stdcall:Win32 API的調用協議,由被調用的函數清理堆棧,所有參數自右至左入棧,生成的代碼中函數名有一個_做前綴和一個@和參數的總字節數(十進制)作後綴。它不支持可變參數,但它產生的代碼比_cdecl短,因爲沒有每次調用後的清理堆棧的代碼。


_cdecl:C\C++的缺省調用協議,由調用者清理堆棧,這就是C\C++中可以使用可變參數的函數的原因,所有參數自右至作入棧,生成的代碼中函數名有一個_做前綴.


至此算是明白過來了,一般dll中的函數都採用extern "C" __stdcall的方式引出函數接口的,在調用DLL中的函數時,如果沒有加__stdcall和__cdecall是缺省調用了__cdecall,而__cdecall是要由調用者清理堆棧的,而在代碼中並沒有清理堆棧的操作,只是調用了函數,所以調


用函數的地址可能會跑飛。不跑飛就OK,而一旦跑飛就出現Access violation的異常。而_stdcall是由被調用的函數清理堆棧,所以調用函數的地址不會跑飛,自然也就OK了。


具體__stdcall/__cdecal/__fastcall的區別可以參見http://blog.csdn.net/limenglandon/article/details/8553201。  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章