使用Windows API實現執行時動態獲取程式檔案版本資訊
在應用層面上,程式設計師可以通過儲存在應用程式檔案或動態連結庫檔案中的版本資訊判斷一個檔案是否應該被安裝,並確定當前安裝檔案的衝突。在檔案有了版本資訊這個屬性後,我們編寫的程式就能夠實現以下功能:
1. 避免在新版本的元件上安裝舊版本的相同元件;
2. 在多語言系統環境中,作業系統根據檔案版本資訊裡提供的語言資訊在啟動程式時決定使用的正確語言;
3. 可以防止在不同的路徑下安裝多個檔案的拷貝;
4. 應用程式在執行時,便能判斷檔案的版本是否正確;
5. 在應用程式的關於對話方塊中顯示可執行檔案的版本號;
6. 線上升級程式可以判斷一個檔案是否因為版本過舊,從而進行必要的檔案升級。
因為Windows系統在設計上的先天缺陷,其使用的FSO並不支援檔案的
在Windows系統中任何可以包含Windows資源的檔案都可以包含版本資訊,比如動態連結庫檔案、可執行檔案、字型檔案等。版本資訊被包裝成一個VERSIONINFO結構的資源,通過編譯器打包進這些檔案中。
本文試圖通過分別講解這些API的使用方法,向讀者介紹在
一、幾個重點版本資訊函式的使用方法
在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