1. 程式人生 > >(轉)Win32應用程式的載入與啟動分析

(轉)Win32應用程式的載入與啟動分析

 轉自 chenxixia 的 Blog

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=455591



設有一個Win32下的可執行檔案MyApp.exe,這是一個Win32應用程式,符合標準的PE格式。MyApp.exe的主要執行程式碼都集中在其原始檔MyApp.cpp中,該檔案第一個被執行的函式是WinMain。初學者會認為程式就是首先從這個WinMain函式開始執行,其實不然。

    在WinMain函式被執行之前,有一系列複雜的載入動作,還要執行一大段啟動程式碼。執行程式MyApp.exe時,作業系統的載入程式首先為程序分配一個4GB的虛擬地址空間,然後把程式MyApp.exe所佔用的磁碟空間作為虛擬記憶體對映到這個4GB的虛擬地址空間中。一般情況下,會對映到虛擬地址空間中0X00400000的位置。載入一個應用程式的時間比一般人所設想的要少,因為載入一個PE檔案並不是把這個檔案整個一次性的從磁碟讀到記憶體中,而是簡單的做一個記憶體對映,對映一個大檔案和對映一個小檔案所花費的時間相差無幾。當然,真正執行檔案中的程式碼時,作業系統還是要把存在於磁碟上的虛擬記憶體中的程式碼交換到實體記憶體(RAM)中。但是,這種交換也不是把整個檔案所佔用的虛擬地址空間一次性的全部從磁碟交換到實體記憶體中,作業系統會根據需要和記憶體佔用情況交換一頁或多頁。當然,這種交換是雙向的,即存在於實體記憶體中的一部分當前沒有被使用的頁也可能被交換到磁碟中。

    接著,系統在核心中建立程序物件和主執行緒物件以及其它內容。

    然後作業系統的載入程式搜尋PE檔案中的引入表,載入所有應用程式所使用的動態連結庫。對動態連結庫的載入與對應用程式的載入完全類似。

    再接著,作業系統執行PE檔案首部所指定地址處的程式碼,開始應用程式主執行緒的執行。首先被執行的程式碼並不是MyApp中的WinMain函式,而是被稱為C Runtime startup code的WinMainCRTStartup函式,該函式是連線時由連線程式附加到檔案MyApp.exe中的。該函式得到新程序的全部命令列指標和環境變數的指標,完成一些C執行時全域性變數以及C執行時記憶體分配函式的初始化工作。如果使用C++程式設計,還要執行全域性類物件的建構函式。最後,WinMainCRTStartup函式呼叫WinMain函式。

   WinMainCRTStartup函式傳給WinMain函式的4個引數分別為:hInstance、hPrevInstance、lpCmdline、nCmdShow。

    hInstance:該程序所對應的應用程式當前例項的控制代碼。WinMainCRTStartup函式通過呼叫GetStartupInfo函式獲得該引數的值。該引數實際上是應用程式被載入到程序虛擬地址空間的地址,通常情況下,對於大多數程序,該引數總是0X00400000。

    hPrevInstance:應用程式前一例項的控制代碼。由於Win32應用程式的每一個例項總是執行在自己的獨立的程序地址空間中,因此,對於Win32應用程式,WinMainCRTStartup函式傳給該引數的值總是NULL。如果應用程式希望知道是否有另一個例項在執行,可以通過執行緒同步技術,建立一個具有唯一名稱的互斥量,通過檢測這個互斥量是否存在可以知道是否有另一個例項在執行。

    lpCmdline:命令列引數的指標。該指標指向一個以0結尾的字串,該字串不包括應用程式名。

    nCmdShow:指定如何顯示應用程式視窗。如果該程式通過在資源管理器中雙擊圖示執行,WinMainCRTStartup函式傳給該引數的值為SW_SHOWNORMAL。如果通過在另一個應用程式中呼叫CreatProcess函式執行,該引數由CreatProcess函式的引數lpStartupInfo(STARTUPINFO.wShowWindow)指定。