對於一個初學者來說,對於如下函數定義,一定會有點迷惑。
STDAPI DllGetClassObject(){}
也許你會問該函數定義中的STDAPI是什麼東東。如果你對此迷惑,那我告訴你在WINNT.h檔案中STDAPI宏定義如下:
#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE
在MSDN中STDAPICALLTYPE宏有如下定義:
#ifdef _WIN32 // Win32 doesn't support __export
#define STDAPICALLTYPE __stdcall
#else
#define STDAPICALLTYPE __export __stdcall
#endif
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C extern
#endif
由此可知,其實STDAPI只是一個宏定義。而該宏定義由兩個宏定義(EXTERN_C和STDAPICALLTYPE)和HRESULT組成。經過先行編譯,有如下結果:
extern "c" HRESULT __stdcall
這裡,我假設是在Win32情況下進行先行編譯處理的,所以就沒有__export了。同時,定義了__cplusplus,即用C++文法。
extern "C"就不用我來說明了吧。隨便一本將c/c++的文法書都會提到的。HRESULT是函數的傳回值類型。而__stdcall是一種調用類型(call type)。這才是我想說的東西。
在編程時,也許你會看到函式宣告或定義中會出現CALLBACK和WINAPI兩個宏。其實,它們也是__stdcall的代名詞。看windef.h中的內容:
#define CALLBACK __stdcall
#define WINAPI __stdcall
那麼,除了__stdcall,還有別的調用類型嗎?究竟什麼是調用類型呢?我的理解是:調用類型就是如何使用函數參數的一種規則。有三種調用類型:__fastcall、__cdecl、__stdcall。
1、__cdecl調用類型:
這是C的調用規則。對於所有非C++成員函數或未標有__stdcall或__fastcall的函數來說,這是預設調用規則。
2、__fastcall調用類型:
從字面意思可知,這是一種快速調用。因為CPU的寄存器會被使用來存放函數參數列表中的頭幾個參數。而剩下參數將被從右至左地推倒堆棧上。被調用函數將從寄存器和堆棧獲得函數參數。在x86中,ECX和EDX一般被用來存放開始的參數。在.NET中,為了效能上的快速,就是使用ecx和edx來實現 __fastcall的。
3、 __stdcall調用類型:
該調用只是通過堆棧來push和pop參數。push參數時,順序是從右至左。
現在,你應該明白了吧。最後,我帶一句。三種調用類型在VC編譯器中對應/Gd、/Gr、/Gz三個編譯選項。