首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

獲取 DLL 版本資訊的兩種方法:從 DllGetVersion 到 FileVersion API 完整解析

     編輯:關於VC++

在 Windows 程式開發中,確認系統上特定動態連結庫(DLL)的版本號是常見需求。例如判斷 comctl32.dll 版本以決定是否支援某些 Common Controls 功能。許多開發者嘗試透過 GetProcAddress 取得特定函數位址來間接推斷版本,但這種方式既繁瑣又不夠可靠。本文將系統性介紹兩種標準獲取 DLL 版本的方法,並提供一個封裝良好的 CModuleVersion 類別,大幅簡化開發流程。

方法一:簡易途徑 — DllGetVersion

現代 Windows DLL(特別是系統元件如 comctl32.dll、shell32.dll 等)通常匯出 DllGetVersion 函數,專門用於回報版本資訊。其原型定義於 shlwapi.h(舊版 SDK 在 showapi.h)中:

typedef struct _DLLVERSIONINFO {
    DWORD cbSize;
    DWORD dwMajorVersion;
    DWORD dwMinorVersion;
    DWORD dwBuildNumber;
    DWORD dwPlatformID; // DLLVER_PLATFORM_WINDOWS (1) 或 DLLVER_PLATFORM_NT (2)
} DLLVERSIONINFO;

HRESULT DllGetVersion(DLLVERSIONINFO *pdvi);

由於並非所有 DLL 都實作此函數,呼叫時必須採用標準動態連結流程:

  1. LoadLibrary 載入目標 DLL
  2. GetProcAddress 取得 DllGetVersion 位址
  3. 若非 NULL,呼叫該函數填充 DLLVERSIONINFO 結構
  4. FreeLibrary 釋放模組

CModuleVersion 類別已將上述流程封裝為靜態方法,使用極為直觀:

DLLVERSIONINFO dvi;
if (CModuleVersion::DllGetVersion(_T("comctl32.dll"), dvi)) {
    // dvi.dwMajorVersion, dvi.dwMinorVersion 等即為版本號
}

方法二:通用途徑 — FileVersion API

當 DLL 未提供 DllGetVersion(如舊版 shell32.dll)時,必須使用版本資源 API。這組 API 包含 GetFileVersionInfoSize、GetFileVersionInfo、VerQueryValue 等,定義於 winver.h,需連結 version.lib。

大多數 EXE/DLL 內建 VS_VERSION_INFO 資源,包含固定資訊(VS_FIXEDFILEINFO:檔案版本、產品版本等)與可變字串資訊(公司名稱、版權、內部名稱等),這些正是エクスプローラ「屬性 → 版本」頁籤顯示的內容。

CModuleVersion 繼承自 VS_FIXEDFILEINFO,可直接存取固定欄位:

CModuleVersion ver;
if (ver.GetFileVersionInfo(_T("comctl32.dll"))) {
    WORD major = HIWORD(ver.dwFileVersionMS);
    WORD minor = LOWORD(ver.dwFileVersionMS);
    // ...
}

可變字串則透過 GetValue 取得:

CString sCompany = ver.GetValue(_T("CompanyName"));
CString sCopyright = ver.GetValue(_T("LegalCopyright"));

CModuleVersion 內部機制詳解

固定資訊擷取

GetFileVersionInfo 先呼叫 GetFileVersionInfoSize 取得緩衝區大小,配置記憶體後再呼叫 GetFileVersionInfo 填充資料。原始緩衝區包含固定與可變兩區塊。固定資訊對應根節點 "\\":

LPVOID lpvi; UINT len;
VerQueryValue(buf, _T("\\"), &lpvi, &len); // lpvi 指向 VS_FIXEDFILEINFO

可變字串資訊擷取

可變資訊依語言與代碼頁組織,需先查詢 "\\VarFileInfo\\Translation" 取得 langID 與 charset(如繁體中文 0x0404、ANSI 代碼頁 0x04E4),再構造鍵值路徑:

\\StringFileInfo\\040404E4\\CompanyName

CModuleVersion::GetValue 內部自動處理語言查詢、字串格式化與 VerQueryValue 呼叫,開發者完全無需關心細節。

實務應用範例:VersionDlg 示範程式

隨文附贈的 VersionDlg 為 MFC 對話框程式,包含編輯框輸入模組名稱,即時以兩種方法顯示版本資訊。核心邏輯於 ON_EN_CHANGE 處理函式 OnChangedModule 中:

void CVersionDialog::OnChangedModule() {
    CString moduleName;
    GetDlgItemText(IDC_MODULE, moduleName);
    
    // 方法一:DllGetVersion
    DLLVERSIONINFO dvi;
    if (CModuleVersion::DllGetVersion(moduleName, dvi)) {
        FormatAndDisplay(dvi, m_staticDllVer);
    }
    
    // 方法二:FileVersion API
    CModuleVersion ver;
    if (ver.GetFileVersionInfo(moduleName)) {
        FormatAndDisplay(ver, m_staticFileVer);
    }
}

關鍵技術細節:自動連結 version.lib

版本 API 屬於 version.lib,若專案設定未加入此庫會產生連結錯誤。ModuleVer.h 採用 #pragma comment 指令自動導入:

// 告訴連結器自動連結 version.lib
#pragma comment(linker, "/defaultlib:version.lib")

此技巧極為實用,免去手動設定專案屬性頁的麻煩。

版本資訊的實際應用場景

  • 關於對話框 / 啟動畫面:直接讀取自身模組版本資源,修改資源檔即自動更新顯示,免除硬編碼版本號。
  • 相容性判斷:根據 DLL 版本動態調整呼叫方式,避免 if (ver <= 470) ... else if (ver == 471) ... 這類脆弱的硬編碼邏輯。
  • 語言/地區偵測:透過版本資源中的語言 ID 確認模組支援的語系,配合多語系部署。

歷史背景補充:comctl32.dll 版本演進

早期 comctl32.dll 版本混亂(4.70、4.71、4.72…6.00 隨 IE 發布),導致應用程式相容性極差。微軟後續允許應用程式隨安裝包重新分發 comctl32.dll(詳見 MSDN 文件 40comupd.htm),並引入 Side-by-Side 組件機制徹底解決 DLL Hell 問題。現代開發建議使用 Manifest 指定相依版本,而非直接檢查檔案版本。

總結

獲取 DLL 版本資訊,優先嘗試 DllGetVersion(快速、結構化);若不支援則回退至 FileVersion API(通用、資訊豐富)。CModuleVersion 類別以乾淨的介面封裝雙重機制,並自動處理記憶體管理、語言查詢、資源釋放等繁瑣細節,是 Windows 系統程式開發者的利器。完整原始碼請參考本文附件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved