Posted on 2008-03-07 16:38
微塵 閱讀(674)
評論(0) 編輯 收藏 引用 所屬分類:
Windows編程
轉(zhuǎn)自
chenxixia 的 Blog
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=455591
設(shè)有一個Win32下的可執(zhí)行文件MyApp.exe,這是一個Win32應用程序,符合標準的PE格式。MyApp.exe的主要執(zhí)行代碼都集中在其源文件MyApp.cpp中,該文件第一個被執(zhí)行的函數(shù)是WinMain。初學者會認為程序就是首先從這個WinMain函數(shù)開始執(zhí)行,其實不然。
在WinMain函數(shù)被執(zhí)行之前,有一系列復雜的加載動作,還要執(zhí)行一大段啟動代碼。運行程序MyApp.exe時,操作系統(tǒng)的加載程序首先為進程分配一個4GB的虛擬地址空間,然后把程序MyApp.exe所占用的磁盤空間作為虛擬內(nèi)存映射到這個4GB的虛擬地址空間中。一般情況下,會映射到虛擬地址空間中0X00400000的位置。加載一個應用程序的時間比一般人所設(shè)想的要少,因為加載一個PE文件并不是把這個文件整個一次性的從磁盤讀到內(nèi)存中,而是簡單的做一個內(nèi)存映射,映射一個大文件和映射一個小文件所花費的時間相差無幾。當然,真正執(zhí)行文件中的代碼時,操作系統(tǒng)還是要把存在于磁盤上的虛擬內(nèi)存中的代碼交換到物理內(nèi)存(RAM)中。但是,這種交換也不是把整個文件所占用的虛擬地址空間一次性的全部從磁盤交換到物理內(nèi)存中,操作系統(tǒng)會根據(jù)需要和內(nèi)存占用情況交換一頁或多頁。當然,這種交換是雙向的,即存在于物理內(nèi)存中的一部分當前沒有被使用的頁也可能被交換到磁盤中。
接著,系統(tǒng)在內(nèi)核中創(chuàng)建進程對象和主線程對象以及其它內(nèi)容。
然后操作系統(tǒng)的加載程序搜索PE文件中的引入表,加載所有應用程序所使用的動態(tài)鏈接庫。對動態(tài)鏈接庫的加載與對應用程序的加載完全類似。
再接著,操作系統(tǒng)執(zhí)行PE文件首部所指定地址處的代碼,開始應用程序主線程的執(zhí)行。首先被執(zhí)行的代碼并不是MyApp中的WinMain函數(shù),而是被稱為C Runtime startup code的WinMainCRTStartup函數(shù),該函數(shù)是連接時由連接程序附加到文件MyApp.exe中的。該函數(shù)得到新進程的全部命令行指針和環(huán)境變量的指針,完成一些C運行時全局變量以及C運行時內(nèi)存分配函數(shù)的初始化工作。如果使用C++編程,還要執(zhí)行全局類對象的構(gòu)造函數(shù)。最后,WinMainCRTStartup函數(shù)調(diào)用WinMain函數(shù)。
WinMainCRTStartup函數(shù)傳給WinMain函數(shù)的4個參數(shù)分別為:hInstance、hPrevInstance、lpCmdline、nCmdShow。
hInstance:該進程所對應的應用程序當前實例的句柄。WinMainCRTStartup函數(shù)通過調(diào)用GetStartupInfo函數(shù)獲得該參數(shù)的值。該參數(shù)實際上是應用程序被加載到進程虛擬地址空間的地址,通常情況下,對于大多數(shù)進程,該參數(shù)總是0X00400000。
hPrevInstance:應用程序前一實例的句柄。由于Win32應用程序的每一個實例總是運行在自己的獨立的進程地址空間中,因此,對于Win32應用程序,WinMainCRTStartup函數(shù)傳給該參數(shù)的值總是NULL。如果應用程序希望知道是否有另一個實例在運行,可以通過線程同步技術(shù),創(chuàng)建一個具有唯一名稱的互斥量,通過檢測這個互斥量是否存在可以知道是否有另一個實例在運行。
lpCmdline:命令行參數(shù)的指針。該指針指向一個以0結(jié)尾的字符串,該字符串不包括應用程序名。
nCmdShow:指定如何顯示應用程序窗口。如果該程序通過在資源管理器中雙擊圖標運行,WinMainCRTStartup函數(shù)傳給該參數(shù)的值為SW_SHOWNORMAL。如果通過在另一個應用程序中調(diào)用CreatProcess函數(shù)運行,該參數(shù)由CreatProcess函數(shù)的參數(shù)lpStartupInfo(STARTUPINFO.wShowWindow)指定。