天天看點

[Windows程式設計] 使用API函數GetProcAddress的注意事項

Windows API 函數 GetProcAddress 被廣泛用于取得函數指針位址。 例如:

typedef BOOL (WINAPI *pfnGetProductInfo)(DWORD, DWORD, DWORD, DWORD, PDWORD);

pGPI = (pfnGetProductInfo) GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "GetProductInfo");

注意函數定義typedef 中的WINAPI, 它指定了函數的調用協定, 這部分是非常必要而且關鍵的,寫代碼的時候需要注意。

比如你要想取得标準C++運作庫(msvcrt.dll) 中的strcpy函數,函數定義就應該是:

typedef char * (__cdecl *pfnStrRChr)(const char *string, int c);

pSRS = (pfnStrRChR)GetProcAddress(hMSVCRT, "strrchr");

函數調用協定指定了函數參數的傳遞方式以及棧管理方式。如果你這裡不指定調用協定,編譯器會用預設的調用協定。 結果可能和DLL 函數原先指定協定的不同,函數被調用時會直接導緻程式崩潰。

比較主流的函數調用方式有 _cdecl , _stdcall, _fastcall, _thiscall 。

_cdecl 是C語言預設的函數調用協定:所有參數從右到左依次入棧,棧中的參數由調用者清除。

_stdcall 是Pascal 語言的預設的函數調用協定,所有參數從右到左依次入棧,棧中的參數由被調用的函數在傳回後清除。 Windows API 全部采用 _stdcall 方式, 上面例子中的WINAPI 其實就是 ___stdcall

#define WINAPI __stdcall

__fastcall 是前兩個(x86機器)或者4個(x64機器)參數由寄存器傳遞,其餘參數還是通過堆棧傳遞。 棧中的參數由被調用的函數在傳回後清除。Borland Delphi, C++ Builder 預設使用這種調用方式。

_thiscall 和_stdcall 類似, 隻是_thiscall 把類的this指針放在某個特定的寄存器中,比如Visual C++放在ECX中, Borland C++放在EAX中。

經比較,幾種調用協定存在挺大差異,是以GetProcAddress 得到的函數需要指定正确的調用協定。

 本文轉自 陳本峰 51CTO部落格,原文連結:http://blog.51cto.com/wingeek/274021,如需轉載請自行聯系原作者

繼續閱讀