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

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