一、版本信息獲取函數簡介和作用
獲取文件版本信息的作用:
1. 避免在新版本的組件上安裝舊版本的相同組件;
2. 在多語言系統環境中,操作系統根據文件版本信息里提供的語言信息在啟動程序時決定使用的正確語言;
3. 防止在不同的路徑下安裝多個文件的拷貝;
4. 應用程序在運行時,便能判斷文件的版本是否正確;
5. 在應用程序的關於對話框中顯示可執行文件的版本號;
6. 在線升級程序可以判斷一個文件是否因為版本過舊,從而進行必要的文件升級。
Windows系統通過API(可編程接口)的方式為軟件開發人員提供了管理版本信息的方法。API函數有GetFileVersionInfo、GetFileVersionInfo、VerFindFile、VerInstallFile和VerQueryValue,它們被存放在Windows系統目錄下一個被命名為VERSION.DLL的動態鏈接庫文件中。
在Windows系統中任何可以包含Windows資源的文件都可以包含版本信息,比如動態鏈接庫文件、可執行文件、字體文件等。版本信息被包裝成一個VERSIONINFO結構的資源,通過編譯器打包進這些文件中。
GetFileVersionInfo 函數被用來獲取包含在指定文件中的版本信息。其函數聲明如下:
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函數。
GetFileVersionInfoSize函數被用來判斷操作系統是否能夠從指定文件中獲取版本信息。如果存在版本信息,便返回以字節為單位的這些信息所占用空間的大小。其Delphi函數聲明如下:
function GetFileVersionInfoSize(
lptstrFilename: PChar; // 文件名
var lpdwHandle: DWORD // set to zero
): DWORD; stdcall;
參數說明:
lptstrFilename,一個以NULL結束字符串,它指明期望從哪個文件中獲取版本信息的文件名。
lpdwHandle,一個指向將被函數設置為0的變量的指針。
函數調用成功,它將返回文件版本信息的字節大小;否則返回0,可通過GetLastError函數得到擴展的錯誤信息。
在調用GetFileVersionInfo函數前應先調用GetFileVersionInfoSize函數。GetFileVersionInfoSize函數的返回值確定了GetFileVersionInfo函數所使用的版本信息緩沖區的大小。
VerLanguagename函數被用來獲取與指定的二進制微軟語言標示相關聯的語言描述字符串。其Delphi函數聲明如下:
function VerLanguageName(
wLang: DWORD; // 微軟語言標識符
szLang: PChar; // 語言描述緩沖區
nSize: DWORD // 緩沖區大小
): DWORD; stdcall;
參數說明:
wLang,語言標識符,是一個二進制數字。指定二進制語言標識符。如果向得到完整的語言標識符列表,請參見語言標識符部分的內容。舉個例子,與語言標識符0x040A相關聯的描述字符串就是“卡斯蒂利亞西班牙語”。如果是一個未知的標識符,那么szLang參數就會指向一個缺省字符串--“Language Neutral”。
szLang,這個參數指向一個緩沖區。這個緩沖區用於存儲由wLang參數所確定的、用來描述語言的、以NULL結尾的字符串。
nSize 指定緩沖區的大小,單位是字符數量。
函數將返回存儲在緩沖區中字符串的以字符為單位的大小。返回值不包含結束NULL字符。如果描述字符串小於或等於緩沖區的大小,那么整個描述字符串將保存在這個緩沖區中;否則,緩沖區中將之保留描述字符串的前面大小等於緩沖區大小的部分。
如果發生錯誤,返回值將等於0。未知的語言標識符不會產生錯誤。
通常,安裝程序通過這個函數來翻譯從VarQuery函數返回的語言標識符。當出現語言沖突的時候,這個得到的文本字符串便可以用在一個向用戶詢問怎樣處理的對話框中,提示用戶進行處理。
VerQueryValue函數被用來從指定的版本信息資源中獲取指定版本信息。最常用的獲取版本信息的邏輯流程是:先調用GetFileVersionInfoSize函數,緊接着再調用GetFileVersionInfo函數,最后再調用VerQueryValue函數。其Delphi函數聲明如下:
function VerQueryValue(
pBlock: Pointer; // 存放版本資源的緩沖區
lpSubBlock: PChar; // 期望獲取的值
var lplpBuffer: Pointer; // 指向存放版本值緩沖區的指針
var puLen: UINT // 版本信息長度
): BOOL; stdcall;
參數說明:
pBlock,一個指向用於存儲版本信息資源的緩沖區的指針,這個版本信息資源是從GetFileVersionInfo函數返回的。
lpSubBlock,指向一個零結尾的字符串,指定到底獲得哪個版本信息值。這個字符串必須由被反斜線符號(\)分開的名字組成如下格式之一:
→“\”,指定根區域。函數將返回一個指向VS_FIXEDFIELDFILEINFO結構的版本信息資源。
→“\VarFileInfo\Translation”,指定一個保存在可變類型變量信息的結構中的轉換陣列。函數返回一個指向語言和代碼頁標識符數組的指針。應用程序可以使用這些標識符來訪問存儲在版本信息資源中的特定語言字符串表結構。
→“\StringFileInfo\lang-codepage\string-name”,指定存儲在特定語言字符串表中結構的值。其中,lang-codepage的書寫格式是:用雙字(DWORD)表示的、保存在資源中的轉換陣列的語言與代碼頁標識符對,並且需要書寫成十六進制形式的字符串;string-name必須是在后面注釋中預定義的字符串之一。函數根據指定的語言與代碼頁,返回一個與之相關的字符串。
lplpBuffer,一個指向用於保存指向被請求的版本信息緩沖區的變量的指針。簡單的說,就是一個指向指針的指針。
puLen,指向一個保存版本信息長度的緩沖區。
如果指定的版本信息結構存在並且有效,函數將返回一個非0值。如果長度緩沖區的地址等於0,指定的版本信息名稱將無效。
並且,在指定的名稱不存在或指定的資源無效時,函數的返回值將等於0。
以下列表是預定義的版本信息統一字符編碼標准字符串:
Comments、InternalName、ProductName、CompanyName、LegalCopyright、ProductVersion、FileDescription、LegalTrademarks、PrivateBuild、FileVersion、OriginalFilename、SpecialBuild
二、函數使用實例
在Delphi的集成編輯器中按下Shift+Ctrl+F11鍵,在彈出的對話框中按照下表的內容,在相應鍵值的未知輸入內容:
例如:“產品名稱”、“產品版本號”、“文件說明”、“產品合法商標”、“運行文件版本號”、“公司名稱”、“合法商標”、“產品內部名稱”、“原文件名”等
代碼示例:
const
InfoNum = 9;
InfoStr: array[1..InfoNum] of string = (
'ProductName',
'ProductVersion',
'FileDescription',
'LegalCopyright',
'FileVersion',
'CompanyName',
'LegalTradeMarks',
'InternalName',
'OriginalFileName'
);
var
S: string;
BufSize, Len: DWORD;
Buf: PChar;
Value: PChar;
begin
S := Application.ExeName;
BufSize := GetFileVersionInfoSize(PChar(S), BufSize);
if BufSize > 0 then begin
Buf := AllocMem(BufSize); //獲取內存控件,用於保存從文件中獲得的版本信息資源。
GetFileVersionInfo(PChar(S), 0, BufSize, Buf); //獲得在內存中存儲版本信息資源所需要的最小內存空間大小
if VerQueryValue(Buf, PChar('StringFileInfo\080403A8\' + InfoStr[1]), Pointer(Value), Len) then ProductName.Caption := Value;
if VerQueryValue(Buf, PChar('StringFileInfo\080403A8\' + InfoStr[2]), Pointer(Value), Len) then ProductVersion.Caption := '產品版本: ' + Value;
if VerQueryValue(Buf, PChar('StringFileInfo\080403A8\' + InfoStr[3]), Pointer(Value), Len) then FileDescription.Caption := '文件說明: ' + Value;
if VerQueryValue(Buf, PChar('StringFileInfo\080403A8\' + InfoStr[4]), Pointer(Value), Len) then LegalCopyright.Caption := '合法版權: ' + Value;
if VerQueryValue(Buf, PChar('StringFileInfo\080403A8\' + InfoStr[5]), Pointer(Value), Len) then FileVersion.Caption := '文件版本: ' + Value;
if VerQueryValue(Buf, PChar('StringFileInfo\080403A8\' + InfoStr[6]), Pointer(Value), Len) then CompanyName.Caption := '公司名稱: ' + Value;
if VerQueryValue(Buf, PChar('StringFileInfo\080403A8\' + InfoStr[7]), Pointer(Value), Len) then LegalTrademarks.Caption := '合法商標: ' + Value;
if VerQueryValue(Buf, PChar('StringFileInfo\080403A8\' + InfoStr[8]), Pointer(Value), Len) then InternalName.Caption := '內部名稱: ' + Value;
if VerQueryValue(Buf, PChar('StringFileInfo\080403A8\' + InfoStr[9]), Pointer(Value), Len) then OriginalFilename.Caption := '原文件名: ' + Value;
FreeMem(Buf, BufSize); //釋放內存
end else begin
Application.MessageBox('獲取產品信息時遇到錯誤,請嘗試重新啟動'','錯誤',MB_OK + MB_ICONSTOP);
Application.Terminate;
end;
修改於:2019.12.06
