1 .典型 C/C++ 程序
2. Windows 編程的第一種方式是傳統的 SDK 方式, Windows 操作系統是由 C 語言編寫的,故可采用 C 語言直接調用 windows 的 API 函數進行編程。
以下為 Win SDK 應用程序窗口程序框架示例及框架解析。
(1) 建立 Win32 應用程序項目 Win32SDK :
Visual Studio 2005 à 文件 à 新建 à 項目 à Visual C++ à win32 à win32 項目 à win32 應用程序 à 空項目(默認使用 Unicode 字符集)。 如果運行時提示找不到 mfc80d.dll 或 msvcr80d.dll 文件,在“項目屬性 à 配置屬性 à 清單工具 à 常規”中的“使用 FAT32 解決辦法”處選擇“是”,再重新生成解決方案。
(2) 添加源文件 Win32SDK.cpp
3. Windows 下的 C/C++ 應用程序運行機制
( 1 ) subsystem 選項
VC6 :
Project Settings à C/C++ à Preprocessor à Preprocessor Definitions : _CONSOLE ( _WINDOWS )
Project Settings à C/C++ à Project Options : /D "_CONSOLE" ( /D "_WINDOWS " )
Project Settings à Link à Project Options : /subsystem:console ( /subsystem:windows )
VC2005 :
項目屬性 à C/C++ à 預處理器 à 預處理器定義: _CONSOLE ( _WINDOWS )
項目屬性 à C/C++ à 命令行: /D "_CONSOLE" ( /D "_WINDOWS " )
項目屬性 à 鏈接器 à 命令行: /SUBSYSTEM:CONSOLE ( /SUBSYSTEM:WINDOWS )
項目屬性 à 鏈接器 à 系統 à 子系統:控制臺 (/SUBSYSTEM:CONSOLE) ( Windows (/SUBSYSTEM:WINDOWS) )
( 2 )可執行文件的 Entry Point
可執行文件都有一個 Entry Point (起始地址), LINK 時可以用 /entry 指定。
缺省情況下,如果 subsystem 是 “console” , Entry Point 是 mainCRTStartup(ANSI) 或 wmainCRTStartuup(UNICODE) ,即:
/subsystem:"console" /entry:"mainCRTStartup" (ANSI)
/subsystem:"console" /entry:"wmainCRTStartuup" (UNICODE)
mainCRTStartup 或 wmainCRTStartuup 會調用用戶編寫的 main 或 wmain 。 在進入可執行文件的代碼前,系統將會創建一個控制臺窗口。
值得一提的是,在進入應用程序的 Entry Point 前, Windows 的裝載器已經做過 C 變量的初始化,有初值的全局變量擁有了它們的初值,沒有初值的變量被設為 0 。
如果 subsystem 是 “windows” , Entry Point 是 WinMain(ANSI) 或 wWinMain(UINCODE) ,即:
/subsystem:"windows" /entry:"WinMainCRTStartup" (ANSI)
/sbusystem:"windows" /entry:"wWinMainCRTStartup" (UINCODE)
WinMainCRTStartup 或 wWinMainCRTStartup 會調用 用戶編寫的 WinMain 或 wWinMain 。 窗口由用戶調用 CreateWindow(Ex) 創建 。
在 VC2005 中, 項目屬性 à 鏈接器 à 高級處有入口點選項,在編寫 Windows Mobile ANSI 控制臺程序時需指定入口點為 mainWCRTStartup ( WindowsCE (/SUBSYSTEM:WINDOWSCE) )。
在 VC2005 中,建一個簡單的 Console 程序( main 為入口函數),編譯后 F10 將進入 crtexe.c ,查看調用堆棧如下:
à int main ( int argc , char * argv [])
à int __tmainCRTStartup ( void )
à int mainCRTStartup ( void )
<1>mainCRTStartup 函數只是簡單的調用 __tmainCRTStartup 函數,其代碼如下:
#ifdef _WINMAIN_
int WinMainCRTStartup ( void ) // UNICODE 版本: int wWinMainCRTStartup(void)
#else
int mainCRTStartup ( void ) // UNICODE 版本: int wmainCRTStartup(void)
{
__security_init_cookie ();
return __tmainCRTStartup ();
}
<2>__tmainCRTStartup 函數調用 main/WinMain 函數,其代碼如下:
int __tmainCRTStartup ( void )
{
// ……
#ifdef _WINMAIN_
GetStartupInfo ( & StartupInfo );
……
mainret = WinMain (…) // UNICODE 版本: int wWinMain(…)
#else /* _WINMAIN_ */
mainret = main ( … ); // UNICODE 版本: int wmain(…)
// ……
/*
* do C++ constructors (initializers) specific to this EXE
*/
if ( __native_startup_state == __initializing )
{
_initterm ( __xc_a , __xc_z );
__native_startup_state = __initialized ;
}
// ……
if ( ! managedapp )
exit ( mainret );
// ……
return mainret ;
}
可以推測上述 _WINMAIN_ 宏是與 subsystem 相關的一個 VC 編譯器內部宏。
(3)應用程序的啟動
程序是一連串 靜態 的指令,而進程是一個容器,它包含了一系列運行在這個程序實例上下文中的線程使用的資源。
當我們用鼠標點擊磁盤上的可執行文件 App.exe 后, App.exe 被裝載至內存后就形成了進程,因此進程是一個正在運行的程序的實例。一般我們可以同時啟動多個 App.exe 的實例,即創建同名的多個不同 ID 的進程。
進程內核對象不是進程本身,僅僅是一個系統用來管理這個進程的一個小的數據結構( PCB , Process Control Block )。進程是不活潑的,程序代碼的執行是線程的工作,線程是進程內執行代碼的獨立實體。一個進程要完成任何的事情,它必須有一個運行在其地址空間的線程。 Windows 操作系統調用 CreateProcess 函數創建一個新的進程和該進程的主線程,返回 LPPROCESS_INFORMATION 信息。 主線程通過執行 C/C++ 運行期啟動代碼初始化 C/C++ 運行期庫, C/C++ 運行期啟動代碼又會調用 main 函數。主線程在運行期間,可以調用 CreateThread 創建輔助線程,即所謂的多線程。
當 App.exe 進程的主線程入口函數 main/WinMain 返回后,啟動函數 mainCRTStartup ( __tmainCRTStartup )調用 C/C++ 運行期退出函數 exit( 參數為 main/WinMain 返回值 ) 。
全局變量(包括內置類型和類類型)存儲在全局區。 exit 函數會銷毀所有全局的或靜態的 C++ 對象, 全局 C++ 對象的構造函數在進入應用程序的 Entry Point 之后,調用用戶編寫的 main/WinMain 之前調用。編譯器調用 atexit 記錄全局對象的析構函數( dynamic atexit destructor for 'x' , 多個函數形成多播鏈),在 exit 退出時( main/WinMain 返回之后)調用。
在 exit 處 F11 進入 crt0dat.c 中的 doexit ,其中析構函數的調用代碼片段如下:
/*
* do _onexit/atexit() terminators(if there are any)
* These terminators MUST be executed in reverse order (LIFO)!
*/
_PVFV * onexitbegin = ( _PVFV *) _decode_pointer ( __onexitbegin );
_PVFV * onexitend = ( _PVFV *) _decode_pointer ( __onexitend );
// 依次調用 atexit 注冊的函數( oneixtbegin à onexitend )
HelloCPP2.cpp 程序在 VC6 中,沒輸出 "X deconstructor" ,在 VC2005 中輸出 "X deconstructor" 。
最后( /* return to OS or to caller */ )調用 ExitProcess ( doexit à __crtExitProcess )促使操作系統終止應用程序。
參考:
《 如何屏蔽控制臺應用程序的窗口? 》
《深入淺出 MFC 》第一章 à Win32 程序基本概念 à 進程與線程 à 一個進程的誕生與死亡
《 Windows 核心編程 第五版》 4.1 編寫第一個 Windows 應用程序。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
