1. 程式人生 > >一個win32應用程式檔案的啟動過程

一個win32應用程式檔案的啟動過程

學習windows 程式設計從mfc角度來說可分為兩部分那就是WinMain函式以前的,和WinMain函式以後的。前者涉及很多windows作業系統內部的知識,後者需要看mfc原始碼。雖然大多數程式不需要了解太多關於os載入應用程式這方面的知識,但能較深入瞭解windows os的執行情況對程式設計師是很有幫助的。
     關於os如何載入程式,它包括程序建立,主執行緒 建立,PE檔案載入,程式c執行時啟動函式以及四種main函式的呼叫等。從mfc程式設計角度來說,這些都是不得見的,不過了解這些對程式設計師編制好的windows程式是有好處的。到底在桌面雙擊一個exe程式,os呼叫的第一個函式是什麼?
     要了解一個.exe程式的啟動過程就不得不瞭解一下有關作業系統方面的知識,such as“程序,執行緒,虛擬記憶體"的基本的知識。
     未真正開始之前,先統一一下本文出現的一些名詞的含義:
     App.exe----------假定為應用mfc的AppWizard做出的一個SDI程式,App是它的名字。你
可以把它看為一個標準的"hello mfc!"程式。
      PE------------不要以為它是“體育課”的縮寫呦。它可是微軟的標準win32可執行檔案
.exe和動態連結庫.dll的檔案格式,它的english name是Portable Executable File Forma
t。 
   下面可要正式開始了。
    一個microsoft的.exe程式的啟動方法有很多,這裡我們以雙擊App.exe圖示啟動為例(其他方法,我想也是一樣的)。在補充一下,我所用的os是Windows2000Server,所以這裡也
主要討論win2000下的應用程式,過要涉及較多關於NT核心,畢竟微軟主推win2000/winxp和
Unicode。
    一個microsoft的.exe程式的啟動過程如下:
  (1)當我們雙擊App.exe圖示啟動程式時,系統首先做什麼呢,讓我們先聽一聽侯捷是如何說的吧“執行起來的App程序其實是shell呼叫CreateProcess啟用的”----"深入淺出MFC second edition" page39載。很多書上都是如是說的,shell又名“命令直譯器”,是win32作業系統基於瀏覽器的一個32位使用者介面,它是一個多執行緒的好例子,螢幕上每一個資料夾瀏覽視窗都是它的一個執行緒。它是作業系統引導時載入的系統程序,它具體表現為windows explorer.exe。explorer.exe是所有使用者應用程式的創造者。你完全可以將shell看成是所有應用程式程序的父程序,就像桌面(desktop)可看成所有視窗的父視窗一樣。shell的用途很多,如啟動應用程式,管理檔案系統,將應用程式與相應檔案相關聯等等。我們常見的桌面上的帶有小箭頭的快捷方式(shortcut)就是一個shell連結,shell負責管理一個叫"名字空間"的類似檔案系統似的“超檔案系統”,它允許應用程式在任何地方在不知訪問物件名字和位置的前提下訪問到這個物件,此類物件有:檔案,目錄,驅動器,印表機以及網路資源。而名字空間就是shell把這些物件有層次組織起來的一個結構。名字空間為使用者和應用程式提供了一種可靠和高效的方法來訪問和管理物件。好了不論它是什麼,凡正它呼叫了CreateProcess,一切就從這裡開始了。


  (2)CreateProcess這個函式可作了不少工作。App程序由此誕生。當CreateProcess這個函式被呼叫,系統就會建立一個“程序核心物件”。程序核心物件可以看作一個作業系統用來管理程序的核心物件,它也是系統用來存放關於程序統計資訊的地方(一個小的資料結構),其實它的真正建立者是一個叫NTCreateProcess的windows2000系統服務函式(也叫執行體服務函式),他建立了程序核心物件供使用者擴充套件。程序核心物件的初始使用計數為1。然後系統為該程序建立4GB(=2^32)的虛擬地址空間(所謂虛擬就不是真的建立4GB的實體記憶體空間,這些空間不是真在實體記憶體上).用於載入App.exe可執行檔案和任何必要的dll檔案的資料和程式碼。


  (3)下面概述一下系統的載入器(可稱為loader)是如何載入這些東東的。首先了解一下系統為該程序建立4GB的虛擬地址空間是如何分配的,對於win2000/winxp來說,預設情況下每個使用者程序可以佔有2GB的私有地址空間;作業系統佔有剩餘的2GB空間。在32位x86系統上,

從0x00000000到0x7fffffff的空間中存放著 應用程式程式碼,全域性變數,每個執行緒堆疊,dll程式碼。
從0x80000000到0xc0000000的空間中存放著 核心和執行體,HAL(硬體抽象層),引導驅動程式。
從0xc0000000到0xc0800000的空間中存放著 程序頁表和超空間。
從0xc0800000到0xffffffff的空間中存放著 系統快取記憶體,分頁緩衝池,非分頁緩衝池。


首先,CreateProcess開啟應用程式檔案(.exe),它先掃描該檔案的檔案頭,該檔案頭裡含有檔案能執行在那個環境之下,如果是win32環境,系統就直接載入檔案的程式碼和資料並輸入(import)該檔案執行所需的dll函式。如果不是win32環境比如時os/2的.exe則先載入相應的環境子系統,載由該環境載入該檔案的程式碼和資料以及該檔案執行所需的dll函式。至於系統是如何知道檔案的程式碼和資料以及該檔案執行所需的dll函式所在的位置就需要你瞭解一下PE檔案格式了,其實也很簡單,PE檔案擁有很多sections,資料和程式碼都放在不同的section裡面,檔案執行所需的dll也放在單獨的section(.idata)裡,這裡就不詳述了。而且在載入過程中涉及到有關虛擬記憶體,記憶體對映檔案等很多較深的知識,我會在以後的系列文章中詳細專題論述的。

  (4)程序載入程式碼和資料完畢後,就開始建立執行緒來執行程序空間內的程式碼。程序是靜態的,它只是執行緒的容器。一個程序至少因該有一個執行緒(main thread),其它執行緒都是主執行緒通過呼叫CreateThread函式建立的。執行緒也是核心物件,他的實際建立者是一個叫NtCreateThread的windows2000系統服務函式。一個執行緒其實只是一個執行緒核心物件和兩個堆疊(一個核心堆疊,用於執行緒執行在核心態;一個使用者堆疊,用於執行緒執行在使用者態),執行緒與程序類似,也擁有執行緒核心物件計數和執行緒控制代碼,這裡不詳述。執行緒用於描述程序中的執行路徑。每當程序被初始化時,系統就要建立一個主執行緒。該執行緒與c/c++執行時庫的啟動程式碼一道開始執行,啟動程式碼則呼叫進入點函式(就是我們的main函式,它也是主執行緒的進入點函式),並且繼續執行直到進入點函式返回並且c/c++執行時庫的啟動程式碼呼叫ExitProcess為止。每個執行緒都有自己的入口點函式,主執行緒入口點函式名字必須是main,wmain,WinMain或wWinMain.而其他的執行緒入口點函式名字可使用任何名字。每個執行緒函式必須有一個返回值,它將作為執行緒的退出程式碼。對於主執行緒來說,這個返回值將傳給c/c++執行時庫的啟動函式。


  (5)c/c++執行時庫的啟動函式它其實是一個程式的真正呼叫的第一個函式,它是在程式連結時由連結程式選擇相應的啟動函式並加到程式的開始處。c/c++執行時庫有四個版本的啟動函式,他們分別對應不同型別的應用程式。比如,需要ANSI字元和字串的GUI應用程式的啟動函式是WinMainCRTStartup,其對應的進入點函式是WinMain,需要Unicode字元和字串的GUI應用程式的啟動函式是wWinMainCRTStartup,其對應
的進入點函式是wWinMain,而需要ANSI字元和字串的CUI應用程式(如控制檯console程式)的應用程式的啟動函式是mainCRTStartup,對應的入口點函式為main;需要Unicode字元和字串的CUI應用程式(如控制檯console程式)的應用程式的啟動函式為wmainCRTStartup,對應的入口點函式為wmain;c/c++執行時庫的啟動函式的功能如下:

以wWinMainCRTStartup(大多數執行在windows2000下的應用程式的啟動函式都是它)為例。它負責:
  *檢索指向新程序的完整命令列指標;
  *檢索指向新程序的環境變數的指標;
  *對c/c++執行時的全域性變數進行初始化;
  *對c執行期的記憶體單元分配函式(比如malloc,calloc)和其他低層I/O例程使用的記憶體棧進行初始化。
  *為C++的全域性和靜態類呼叫建構函式。
當這些初始化工作完成後,該啟動函式就呼叫wWinMain函式進入應用程式的執行。
當wWinMain函式執行完畢返回時,wWinMainCRTStartup啟動函式就呼叫c執行期的exit()函式,將返回值(nMainRetVal)傳遞給它。之後exit()便開始收尾工作:
  *呼叫由_onexit()函式呼叫和註冊的任何函式。
  *為C++的全域性和靜態類呼叫解構函式;
  *呼叫作業系統的ExitProcess函式,將nMainRetVal傳遞給它,這使得作業系統能夠撤銷進
程並設定它的exit  程式碼。


(6)至此啟動函式的任務完成,至於中間wWinMain函式的執行過程看看mfc原始碼即可。不過我還要提一下,wWinMain函式其實只是呼叫了mfc的AfxWinMain()函式,而一切的真正程式碼的運
行也是從AfxWinMain()開始的。
   以上只是粗略將一下一個microsoft的.exe程式的啟動過程,其中有很多深奧的知識我只是提了一下,有些知識在以後的文章中還會陸續提到的。

相關推薦

一個win32應用程式檔案啟動過程

學習windows 程式設計從mfc角度來說可分為兩部分那就是WinMain函式以前的,和WinMain函式以後的。前者涉及很多windows作業系統內部的知識,後者需要看mfc原始碼。雖然大多數程式不需要了解太多關於os載入應用程式這方面的知識,但能較深入瞭解windows os的執行情況對程式設計師是很有

Windows 中一個應用程式啟動過程

轉載自:https://blog.csdn.net/cpp_mybest/article/details/80194158 1. Explorer.exe      Windows 能夠流行起來,很大一個原因是它有友好的使用者圖形介面,操作方便簡單,容易上手。在

筆記-iOS應用程式啟動過程

程式的啟動 使用Xcode開啟一個專案,很容易會發現一個檔案main.m檔案,此處就是應用的入口。 程式啟動時,先執行main函式,main函式是iOS程式的入口點 內部會呼叫UIApplicationMain函式 UIApplicationMain裡會建立一個UIApplication物

使用Windows API建立一個Win32應用程式視窗

新建一一個專案名為MakeWin的Win32應用程式空專案,然後為其新增一個名為MakeWin的C++原始檔 #include<windows.h> char Name[]="MakeWin"; LRESULT CALLBACK WndProc(HWND,UINT,WPAR

應用程式程序啟動過程

--摘自《Android進階解密》 1.AMS在啟動應用程式時會檢查者應用程式需要的應用程序是否存在,不存在就會請求Zygote程序啟動需要的應用程式程序 2.Zygote的Java框架層中會建立一個Server端的Socket,這個Socket用來等待AMS請求Zygote來建立新的應用程式程序 3.

Android應用程式程序啟動過程(前篇)

前言 在此前我講過Android系統的啟動流程,系統啟動後,我們就比較關心應用程式是如何啟動的,這一篇我們來一起學習Android7.0 應用程式程序啟動過程,需要注意的是“應用程式程序啟動過程”,而不是應用程式啟動過程。關於應用程式啟動過程,我會在後

Android應用程式啟動過程

前言 在Android系統中,Activity和Service是應用程式的核心元件,它們以鬆藕合的方式組合在一起構成了一個完整的應用程式,這得益於應用程式框架層提供了一套完整的機制來協助應用程式啟動這些Activity和Service,以及提供Binder機制幫

Android應用程式程序啟動過程(後篇)

前言 在前篇中我們講到了Android應用程式程序啟動過程,這一篇我們來講遺留的知識點:在應用程式程序建立過程中會啟動Binder執行緒池以及在應用程式程序啟動後會建立訊息迴圈。 1.Binder執行緒池啟動過程 我們首先來看RuntimeInit

xp系統安裝win10:不是有效的win32應用程式和安裝過程的反覆重啟問題

在點選啟動程式安裝win10時,卻提示不是有效的win32程式,無法執行,下圖: 這時利用bios引導就可以實現安裝win10系統了。 額額額。。。還有 我在安裝win10的過程中總是重複這

[筆記]Android應用程式程序啟動過程的理解

疑問: 1.Process.fork是啥意思?類似new嗎? 2.接著1問,新APP程序和ActivityThread類是怎麼關聯起來的?是zygote程序呼叫執行的ActivityThread類的main方法,怎麼就執行在了新APP程序中? 3.UI主執行緒是啥時候建

Spring Application (Spring 應用程式啟動過程

Spring應用程式啟動過程:1. Spring將"bean配置檔案"中的資訊載入到容器的“Bean定義登錄檔(BeanDefinitionRegistry)”中,此時bean還未初始化。2.呼叫工廠後處理器。 從BeanDefinitionRegistry中找出型別是Bea

一個應用程式無法啟動錯誤的解決過程

作者:朱金燦            早上同事向我請教一個問題,說是啟動exe時遇到一個應用程式無法啟動的錯誤,具體如下圖:            我讓他開啟“控制面板\所有控制面板項\管理工具\事件檢視器”,找到對應的出錯日誌,如下圖:日誌資訊如下:“C:\Users\Adm

Android應用程式內部啟動Activity過程 startActivity 的原始碼分析

                        上文介紹了Android應用程式的啟動過程,即應用程式預設Activity的啟動過程,一般來說,這種預設Activity是在新的程序和任務中啟動的;本文將繼續分析在應用程式內部啟動非預設Activity的過程的原始碼,這種非預設Activity一般是在原來的程序

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

 轉自 chenxixia 的 Blog Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=455591 設有一個Win32下的可執行檔案MyApp.exe,這是一個Win32應用程式,符合標準的PE格式。

boost靜態連結庫和c++/clr不相容問題:未能載入檔案程式集,不是有效的Win32應用程式

專案上遇到的問題:c++編寫的類使用託管c++包裝成dll提供給c#專案使用。c++需要使用boost,clr,專案目標平臺都是win32/x86。開發環境win10 x64系統,vs2013,.Net Framework 4.0,boost 1.55。 【問

dll檔案載入執行載入的14001錯誤,由於應用程式配置不正確,應用程式未能啟動

最近在處理專案問題的的時候發現了這麼一個問題,就是我們的程式在呼叫第三方提供的dll檔案的時候在一臺機器上面會報14001的錯誤,但是在另一臺機器上面不會。兩臺機器上面的作業系統是相同的。針對這個問題和這個錯誤碼,查找了很多的相關資料。 vc錯誤查詢的給予的對於14001的

VC++6.0 Win32應用程式 如何新增窗體 ------阿冬專欄

1、建立一個win32 application。選一個簡單的win32程式。名為win32dialog 2、【插入】-【資源】-選【dialog】-點【新建】 3、點儲存,命名為win32dialog.rc。 4、關掉子視窗(編輯框),左邊 fileview中 【新增檔案到工作區】選上win32di

5.1 Win32應用程式:EXE

  Nico Bendlin的MiniDExe很好地演示了不使用任何Delphi例程來實現一個Win32應用程式的方法。對於一個可執行程式.EXE來說,只須滿足如下條件,就可以在被Windows系統中執行:  是一個以.EXE方式生成的格式正確的PE(Portable Executable)檔案有一個正確的入

exe應用程式無法啟動,因為應用程式的並行配置不正確

問題:exe應用程式無法啟動,因為應用程式的並行配置不正確。有關詳細資訊,請參閱應用程式事件日誌,或使用命令列 sxstrace.exe 工具。 原因查詢: 1)開始→所有程式→附件→右鍵命令提示符→以管理員身份執行 2)輸入sxstrace.exe Trace -logfile:C

大資料篇:Spark入門第一個Spark應用程式詳解:WordCount

任務要求 編寫一個Spark應用程式,對某個檔案中的單詞進行詞頻統計。 備註:本文spark的根目錄名:spark-1.6.3-bin-hadoop2.6 #準備工作 cd /usr/local/spark-1.6.3-bin-hadoop2.6 mkdir mycode