在DOS下,生成一個可執(zhí)行文件的步驟比較簡單,用編譯器將源程序編譯為obj文件,再用鏈接器將obj文件鏈接成exe文件,不同語言的開發(fā)過程都差不多。
DOS可執(zhí)行文件中的內(nèi)容基本上是由源程序中所寫的代碼和數(shù)據(jù)定義轉(zhuǎn)換而來的。惟一的例外是帶覆蓋部分的exe文件,它在基本的exe文件后附加了一些自定義的數(shù)據(jù),可執(zhí)行部分的長度由文件頭偏移0002h和0004h中的長度給出,后面就是附加上去的數(shù)據(jù)。這樣,即使一個帶覆蓋的exe文件大小遠遠超過640 KB,在DOS下也能運行。因為操作系統(tǒng)只裝入真正的可執(zhí)行部分,然后由程序自己去讀取覆蓋部分的數(shù)據(jù)。一些打包軟件生成的奇大無比的自解壓包就采用這種結(jié)構(gòu),可執(zhí)行部分是解包代碼,覆蓋部分是被壓縮的數(shù)據(jù)。DOS對可執(zhí)行文件覆蓋部分的數(shù)據(jù)格式并沒有規(guī)定,它是程序員按自己的方式組織的。如果程序員愿意,也可以把這些數(shù)據(jù)單獨放在另外一個文件中。
Win32可執(zhí)行文件叫做PE文件。PE文件的基本結(jié)構(gòu)和DOS可執(zhí)行文件有很大的不同。它把程序中的不同部分分成各種節(jié)區(qū)(),其中可以有一個節(jié)區(qū)是放置各種資源的數(shù)據(jù)結(jié)構(gòu)頭文件和源文件,如菜單、對話框、位圖、光標、圖標和聲音等。雖然可以把資源部分理解成類似DOS可執(zhí)行文件中的“覆蓋”部分,但資源是Win32可執(zhí)行文件的標準組成部分,而且是非常重要的組成部分。所以和DOS軟件的開發(fā)過程相比,Win32軟件的開發(fā)中多了一個創(chuàng)建資源文件的步驟。
以使用軟件包為例,通過如圖2.1所示的Win32匯編開發(fā)軟件的流程,程序員要做的工作分創(chuàng)建代碼和創(chuàng)建資源兩部分。
代碼部分的開發(fā)工作和DOS下寫代碼的步驟是一樣的。程序員用文本編輯器書寫匯編源代碼(*.asm文件),這和C源程序類似。asm文件中也可以用語句包含數(shù)據(jù)定義和函數(shù)聲明的頭文件。Win32匯編的頭文件一般用inc作擴展名,如軟件包附帶的.inc文件定義了Win32 API中很多參數(shù)和數(shù)據(jù)結(jié)構(gòu),其他的inc文件則是不同DLL中的Win32 API函數(shù)聲明。最后,asm文件經(jīng)匯編編譯器編譯成以obj為擴展名的目標文件。
資源文件中可以包括對話框、快捷鍵、菜單、字符串、版本信息和一些圖形資源等內(nèi)容。資源文件的源文件是一種類似“腳本”的文本文件。其中用不同的語法定義了不同類型的資源。資源腳本文件的擴展名一般為rc,經(jīng)過資源編譯器編譯成資源文件*.res。資源腳本文件同樣用到很多預定義值,所以軟件包中一般也有資源頭文件可供源文件來導入。軟件包中的資源頭文件是.h。
在資源文件中,對話框資源只記錄定義值,如對話框的大小、位置等,并非真正存儲對話框最后顯示在屏幕上的像素。這些大小、位置等信息最后由解釋后才在屏幕上被繪畫成像素;菜單、字符串、快捷鍵等由文本構(gòu)成;圖形資源則真正由像素組成,它們在資源腳本中被定義為一個文件名,由資源編譯器從磁盤文件導入。在資源文件中支持的圖形文件有bmp位圖文件、cur光標文件和ico圖標文件。這些圖形文件可以用其他圖形處理軟件生成。wav聲音文件也是得到支持的。
編譯好目標文件*.obj和資源文件*.res后,最后一步是用鏈接器將它們鏈接成可執(zhí)行文件。鏈接的時候要用到函數(shù)庫。在DOS環(huán)境下編程的時候數(shù)據(jù)結(jié)構(gòu)頭文件和源文件,使用的函數(shù)庫是靜態(tài)庫。靜態(tài)庫是一些已經(jīng)編譯好的代碼模塊。當用戶在源程序中用到某個函數(shù)的時候,鏈接器從庫文件中將這個函數(shù)的二進制代碼取出,和obj文件合在一起生成最終的exe文件。但在Win32環(huán)境下,大部分的公用函數(shù)封裝在DLL文件中,以動態(tài)鏈接的方式供用戶程序調(diào)用。這時候庫文件中只需要包含函數(shù)在DLL中的位置信息,不再需要有二進制代碼部分。所以鏈接的時候也只是把庫文件中的位置信息取出放入最后的可執(zhí)行文件中。Win32中這種只包含位置信息的庫文件稱為導入庫。
Win32匯編編程中使用不同匯編編譯器的時候,匯編源程序的格式和資源腳本文件的格式可能稍微有所不同。各種頭文件、庫文件的文件名也有所不同。所以在開始編程之前,必須先選定一種合適的編譯器。