WINAPI宏、__cdecl、__stdcall、__fastcall

一直搞不懂爲什麼在函數前面加上WINAPI、CALLBACK等是什麼意思 又不是返回值 爲什麼加在前面 今天終於知道了 這是一個呼叫聲明(姑且稱之吧)。

引子:

看看這個函數:

int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
{
MSG msg;

/* Call initialization procedure */
//進行程序的初始化工作
if(!AppInit(hInst,hPrev,sw))
return FALSE;

/*
* Polling messages from event queue
*/
//消息循環處理
for(;;)
{
while(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))//Peek只是查看事件,一般不作任何處理
//Get會做一些例行處理,並且把事件從隊列中刪除掉(WM_PAINT除外)

//通常先peek,看某事件是否存在,再get,進行處理

//未經嚴格測試:如果你get某個在隊列中不存在的事件,程序會陷入等待,但是peek總是立即返回

{
if(msg.message == WM_QUIT)
break; // Leave the PeekMessage while() loop
//TranslateAccelerator將WM_KEYDOWN和WM_SYSYKEYDOWN消息翻譯成爲WM_COMMAND消息,
//然後直接將消息送到相關的窗口過程中去,直到消息被處理後才返回值
if(TranslateAccelerator(ghwndApp, ghAccel, &msg))
continue;

TranslateMessage(&msg);
DispatchMessage(&msg);
}

if(msg.message == WM_QUIT)
break; // Leave the for() loop

WaitMessage();//當本窗口的消息序列中沒有消息的時候,將控制權交給其他的線程直到再次有消息進入自己的消息隊列中時才返回
}

// Reached on WM_QUIT message
CoUninitialize();
return ((int) msg.wParam);
}

別的先別看,現看看這個PASCAL

The __pascal, __fortran, and __syscall calling conventions are no longer supported. You can emulate their functionality by using one of the supported calling conventions and appropriate linker options.

WINDOWS.H now supports the WINAPI macro, which translates to the appropriate calling convention for the target. Use WINAPI where you previously used PASCAL or __far __pascal.

看來現在用WINAPI來代替己經不用的PASCAL了,那麼WINAPI是什麼呢?

WINAPI:

查看WINAPI的定義:(WINDOWS.H)

#define WINAPI FAR PASCAL

WINAPI:Use in place of FAR PASCAL in API declarations. If you are writing a DLL with exported API entry points, you can use this for your own APIs.

原來是個宏定義。用法也說到了,你可以使用WINAPI來爲自己的API寫一個DLL文件(有導出的API入口點的DLL,廢話,沒有API入口,要DLL幹什麼?)。

消息處理函數就是這麼定義的:LONG WINAPI AppWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){}

在VC++ 6.0中,WINDEF.h

#define WINAPI CDECL //=_cdecl

#define CALLBACK PASCAL //=_pascal,VC已經不支持直接使用_pascal了

順便提下CALLBACK:CALLBACK:Use in place of FAR PASCAL in application callback routines such as window procedures and dialog procedures.

在BCB(Boland C++ Builder )中:windef.h

#define WINAPI __stdcall

#define CALLBACK __stdcall

具體來說,他們是關於堆棧的一些說明,首先是函數參數壓棧順序,其次是壓入堆棧的內容由誰來清除,調用者還是函數自己?

簡單說明:

__cdecl是C/C++和MFC程序默認使用的調用約定,也可以在函數聲明時加上__cdecl關鍵字來手工指定。採用__cdecl約定時,函數參數按照從右到左的順序入棧,並且由調用函數者把參數彈出棧以清理堆棧。因此,實現可變參數的函數只能使用該調用約定。由於每一個使用__cdecl約定的函數都要包含清理堆棧的代碼,所以產生的可執行文件大小會比較大。__cdecl可以寫成_cdecl。
__stdcall調用約定用於調用Win32 API函數。採用__stdcal約定時,函數參數按照從右到左的順序入棧,被調用的函數在返回前清理傳送參數的棧,函數參數個數固定。由於函數體本身知道傳進來的參數個數,因此被調用的函數可以在返回前用一條ret n指令直接清理傳遞參數的堆棧。__stdcall可以寫成_stdcall。
__fastcall約定用於對性能要求非常高的場合。__fastcall約定將函數的從左邊開始的兩個大小不大於4個字節(DWORD)的參數分別放在ECX和EDX寄存器,其餘的參數仍舊自右向左壓棧傳送,被調用的函數在返回前清理傳送參數的堆棧。__fastcall可以寫成_fastcall。

特別說明:
1. 在默認情況下,採用__cdecl方式,因此可以省略.
2. WINAPI一般用於修飾動態鏈接庫中導出函數
3. CALLBACK僅用於修飾回調函數

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