WinMain函式
WinMain函式原型
Win32應用程式的入口函式為WinMain,函式原型在WinBase.h檔案中:
int WINAPI WinMain ( _In_ HINSTANCE hInstance, |
WinMain函式原型中的符號
符號 | 描述 | 其它 |
int | 返回值 | |
WINAPI | 函式呼叫約定 |
WINAPI巨集展開: #define WINAPI __stdcall |
WinMain | 函式名 | |
HINSTANCE hInstance | 當前應用程式例項控制程式碼 |
HINSTANCE巨集展開: DECLARE_HANDLE(HINSTANCE); #define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name |
HINSTANCE hPrevInstance | 沒有意義。 它用於 16 位Windows,但現在始終為零 | |
LPSTR lpCmdLine | 命令列引數 | |
int nShowCmd | 視窗顯示控制引數 |
程式入口
C/C++語言中,main稱為主函式,是程式的入口。Win32應用程式入口為什麼是WinMain,而不是main呢?
C/C++語言中,程式入口為什麼是main,而不是其它的呢?
CPU控制權傳遞
CPU是計算機的大腦,CPU讀取指令後執行指令,即:控制CPU讀指令的位置,就控制了CPU。
計算機加電後,CPU從BIOS指定位置讀取並執行開機程式第一條指令,即,CPU被開機程式控制,開機程式獲得了CPU的控制權。
開機程式獲得CPU控制權後,其它程式如何獲得CPU控制權呢?開機程式約定,我會去讀取哪個地址的指令來執行。
其它程式把指令寫入開機程式約定的地方,CPU的控制權就到了其它程式。
CPU控制權一步一步傳遞到作業系統。
CPU控制權到了作業系統後,其它程式想要獲得控制權,就需要遵循作業系統的約定。
作業系統約定包括PE格式等,首先按PE格式生成可執行檔案,如.exe。
雙擊或者呼叫程式建立函式啟動程式,作業系統將可執行程式裝載到記憶體,將下一條讀取地址指向程式的入口地址,這樣CPU的控制權傳遞到了可執行程式。
PE檔案生成
要執行自定義的指令,就要遵循與作業系統的約定。
作業系統要求裝載PE格式的檔案,可以通過編譯工具編譯生成PE格式檔案,如.exe。
程式語言
編譯工具負責生成PE格式檔案。
編譯工具約定了輸入的格式,即程式語言。
程式入口
C/C++語言,可執行程式的入口預設是mainCRTStartup,該入口函式可以通過設定重新指定。
入口函式
程式語言約定了程式的入口函式,如main。有程式入口(mainCRTStartup)呼叫入口函式main
WinMain和main
C/C++語言的入口函式都是main,為什麼Win32是WinMain?
程式入口
程式入口可以通過編譯器指定,根據情況指定入口mainCRTStartup或WinMainCRTStartup或自定義
main呼叫
main呼叫可以通過exe_main.cpp,exe_common.inl檔案檢視
mainCRTStartup()->__scrt_common_main()->__scrt_common_main_seh()->invoke_main()->main()。
WinMain呼叫
WinMain呼叫可以通過exe_winmain.cpp,exe_common.inl檔案檢視
WinMainCRTStartup()->__scrt_common_main()->__scrt_common_main_seh()->invoke_main()->WinMain()。
構建原理
入口函式缺失
在控制檯程式中,不寫main函式,編譯報錯:
1>MSVCRTD.lib(exe_main.obj) : error LNK2019: 無法解析的外部符號 main,函式 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) 中引用了該符號
在Win32程式中,不寫WinMain函式,編譯報錯:
1>MSVCRTD.lib(exe_winmain.obj) : error LNK2019: 無法解析的外部符號 WinMain,函式 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) 中引用了該符號
LIB檔案
上面的MSVCRTD.lib(exe_main.obj) 是什麼意思?
.lib檔案可以是靜態連結庫,也可以是匯入庫。
靜態連結庫包含可執行程式碼,匯入庫包含匯入庫資訊。可以通過lib命令檢視lib檔案的型別。
MSVCRTD.lib是一個靜態連結庫。
exe_main.obj是MSVCRTD.lib中的一部分。
連結
連結時,由於程式入口為mainCRTStartup或WinMainCRTStartup,因此連結時會對程式入口的依賴進行檢查。
main連結時,exe_main.obj包含mainCRTStartup()。
mainCRTStartup()->__scrt_common_main()->__scrt_common_main_seh()->invoke_main()->main()。
如果不寫main函式,連結找不到main函式,連結報錯。
main連結時,exe_winmain.obj包含WinMainCRTStartup()。
WinMainCRTStartup()->__scrt_common_main()->__scrt_common_main_seh()->invoke_main()->WinMain()。
如果不寫WinMain函式,連結找不到WinMain函式,連結報錯。