檔案版本資訊的存在使得應用程式正確的安裝檔案變得簡單,並且使安裝程式能夠分析檔案的當前安裝狀態。通常,版本資訊應該包括檔案的版本號碼、檔案功能描述以及檔案作者等多項重要內容。
在應用程式層面上,程式員可以通過儲存在應用程式檔案或動態連結程式庫檔案中的版本資訊判斷一個檔案是否應該被安裝,並確定當前安裝檔案的衝突。在檔案有了版本資訊這個屬性後,我們編寫的程式就能夠實現以下功能:
1. 避免在新版本的組件上安裝舊版本的相同組件;
2. 在多語言系統內容中,作業系統根據檔案版本資訊裡提供的語言資訊在啟動程式時決定使用的正確語言;
3. 可以防止在不同的路徑下安裝多個檔案的拷貝;
4. 應用程式在運行時,便能判斷檔案的版本是否正確;
5. 在應用程式的關於對話方塊中顯示可執行檔的版本號碼;
6. 線上升級程式可以判斷一個檔案是否因為版本過舊,從而進行必要的檔案升級。
因為Windows系統在設計上的先天缺陷,其使用的FSO並不支援檔案的版本資訊功能。為了能對檔案的版本資訊進行管理,微軟在Platform SDK(平台軟體開發套件)中通過API(可程式化介面)的方式為軟體開發人員提供了管理版本資訊的方法。這些API是GetFileVersionInfo、GetFileVersionInfo、VerFindFile、VerInstallFile和VerQueryValue,它們被存放在Windows系統目錄下一個被命名為VERSION.DLL的動態連結程式庫檔案中。
在Windows系統中任何可以包含Windows資源的檔案都可以包含版本資訊,比如動態連結程式庫檔案、可執行檔、字型檔等。版本資訊被封裝成一個VERSIONINFO結構的資源,通過編譯器打包進這些檔案中。
本文試圖通過分別講解這些API的使用方法,向讀者介紹在delphi中通過編程的方法,怎樣實現在運行時動態擷取程式檔案版本資訊的功能。
一、幾個重點版本資訊函數的使用方法
在Windows作業系統中採用語言識別項來區別不同的自然語言,語言識別項是一個32位的不帶正負號的整數,一個數值唯一對應一種自然語言。因此,除了前面列出的五個函數外,在我們編寫程式的時候還會經常使用到VerLanguageName函數,通過調用這個函數,我們的程式便能夠自由的在用整數表示的語言識別項和用字串表示的語言名稱之間進行轉換。
以下便是用於處理版本資訊函數的完整列表。須要注意的是:1. 在Windows NT 3.51或更早版本的作業系統中,版本資訊函數不能操作16位的Windows檔案像(File Image);2.
在Windows 95/98/Me/NT4/2000作業系統中,這些函數同時可以操作16位和32位兩種檔案像;3. 在Windows XP作業系統中,這些函數同時可以操作16位、32位和64位共三種檔案像。
[插入表格1]
在這篇文章中,我們將著重介紹GetFileVersionInfo、GetFileVersionInfoSize、VerLanguageName和VerQueryValue這四個函數的使用方法。在實際應用時,其餘的兩個函數很少使用,因此不作為重點內容進行介紹。
1.1. GetFileVersionInfo函數
GetFileVersionInfo函數被用來擷取包含在指定檔案中的版本資訊。其delphi函式宣告如下:
function GetFileVersionInfo( lptstrFilename: PChar; // 檔案名稱 dwHandle: DWORD; // 忽略 dwLen: DWORD; // 緩衝區大小 lpData: Pointer // 版本資訊緩衝區 ): BOOL; stdcall; |
參數說明:
lptstrFilename,一個以NULL結束字串,它指定了期望從中擷取版本詳細的檔案名稱。如果檔案名稱不包含完整路徑,函數將使用LoadLibrary函數的預設搜尋次序進行搜尋。在Windows 95/98/Me作業系統中路徑名不能超過126個字元。
dwHandle,這個參數沒有使用,將被忽略。
dwLen,請先調用GetFileVersionInfoSize函數確定檔案版本資訊的位元組數大小。dwLen必須等於或大於這個值。如果lpDate指向的緩衝區空間不夠,函數將根據實際大小裁減出檔案的版本資訊。
lpData,指向一個用於儲存函數調用後返回的檔案版本資訊的緩衝區。
如果函數調用成功,它將返回True;否則返回False。可通過GetLastError函數得到擴充的錯誤資訊。
在調用GetFileVersionInfo函數前必須先調用GetFileVersionFileSize。為了從檔案版本資訊中擷取有用資訊,必須使用VerQueryValue函數。
1.2. GetFileVersionInfoSize函數
GetFileVersionInfoSize函數被用來判斷作業系統是否能夠從指定檔案中擷取版本資訊。如果存在版本資訊,便返回以位元組為單位的這些資訊所佔用空間的大小。其delphi函式宣告如下:
function GetFileVersionInfoSize( lptstrFilename: PChar; // 檔案名稱 var lpdwHandle: DWORD // set to zero ): DWORD; stdcall; |
參數說明:
lptstrFilename,一個以NULL結束字串,它指明期望從哪個檔案中擷取版本資訊的檔案名稱。
lpdwHandle,一個指向將被函數設定為0的變數的指標。
如果函數調用成功,它將返迴文件版本資訊的位元組大小;否則返回0,可通過GetLastError函數得到擴充的錯誤資訊。
在調用GetFileVersionInfo函數前應先調用GetFileVersionInfoSize函數。GetFileVersionInfoSize函數的傳回值確定了GetFileVersionInfo函數所使用的版本資訊緩衝區的大小。
1.3. VerLanguageName函數
VerLanguagename函數被用來擷取與指定的二進位微軟語言標示相關聯的語言描述字串。其delphi函式宣告如下:
function VerLanguageName( wLang: DWORD; // 微軟語言識別項 szLang: PChar; // 語言描述緩衝區 nSize: DWORD // 緩衝區大小 ): DWORD; stdcall; |
參數說明:
wLang,語言識別項,是一個位元字。指定二進位語言識別項。如果向得到完整的語言識別項列表,請參見語言識別項部分的內容。舉個例子,與語言識別項0x040A相關聯的描述字串就是“卡斯蒂利亞西班牙語”。如果是一個未知的標識符,那麼szLang參數就會指向一個預設字串--“Language Neutral”。
szLang,這個參數指向一個緩衝區。這個緩衝區用於儲存由wLang參數所確定的、用來描述語言的、以NULL結尾的字串。
nSize 指定緩衝區的大小,單位是字元數量。
函數將返回儲存在緩衝區中字串的以字元為單位的大小。傳回值不包含結束NULL字元。如果描述字串小於或等於緩衝區的大小,那麼整個描述字串將儲存在這個緩衝區中;否則,緩衝區中將之保留描述字串的前面大小等於緩衝區大小的部分。
如果發生錯誤,傳回值將等於0。未知的語言識別項不會產生錯誤。
通常,安裝程式通過這個函數來翻譯從VarQuery函數返回的語言識別項。當出現語言衝突的時候,這個得到的文本字串便可以用在一個向使用者詢問怎樣處理的對話方塊中,提示使用者進行處理。
1.4. VerQueryValue函數
VerQueryValue函數被用來從指定的版本資訊資源中擷取指定版本資訊。最常用的擷取版本資訊的邏輯流程是:先調用GetFileVersionInfoSize函數,緊接著再調用GetFileVersionInfo函數,最後再調用VerQueryValue函數。其delphi函式宣告如下:
function VerQueryValue( pBlock: Pointer; // 存放版本資源的緩衝區 lpSubBlock: PChar; // 期望擷取的值 var lplpBuffer: Pointer; // 指向存放版本值緩衝區的指標 var puLen: UINT // 版本資訊長度 ): BOOL; stdcall; |
參數說明:
pBlock,一個指向用於儲存版本資訊資源的緩衝區的指標,這個版本資訊資源是從GetFileVersionInfo函數返回的。
lpSubBlock,指向一個零結尾的字串,指定到底獲得哪個版本資訊值。這個字串必須由被反斜線符號()分開的名字組成如下格式之一:
→“”,指定根地區。函數將返回一個指向VS_FIXEDFIELDFILEINFO結構的版本資訊資源。
→“VarFileInfoTranslation”,指定一個儲存在可變類型變數資訊的結構中的轉換陣列。函數返回一個指向語言和字碼頁標識符數組的指標。應用程式可以使用這些標識符來訪問儲存在版本資訊資源中的特定語言字串表結構。
→“StringFileInfolang-codepagestring-name”,指定儲存在特定語言字串表中結構的值。其中,lang-codepage的書寫格式是:用雙字(DWORD)表示的、儲存在資源中的轉換陣列的語言與字碼頁標識符對,並且需要書寫成十六進位形式的字串;string-name必須是在後面注釋中預定義的字串之一。函數根據指定的語言與字碼頁,返回一個與之相關的字串。
lplpBuffer,一個指向用於儲存指向被請求的版本資訊緩衝區的變數的指標。簡單的說,就是一個指向指標的指標。
puLen,指向一個儲存版本資訊長度的緩衝區。
如果指定的版本資訊結構存在並且有效,函數將返回一個非0值。如果長度緩衝區的地址等於0,指定的版本資訊名稱將無效。
並且,在指定的名稱不存在或指定的資源無效時,函數的傳回值將等於0。
以下列表是預定義的版本資訊統一字元編碼標準字串:
Comments、InternalName、ProductName、CompanyName、LegalCopyright、ProductVersion、FileDescription、LegalTrademarks、PrivateBuild、FileVersion、OriginalFilename、SpecialBuild