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

Windows 7 開發白皮書:版本檢查失敗根因分析與最佳實踐指南

     編輯:關於.NET

前言:版本檢查是相容性殺手

絕大多數應用程式相容性問題源於錯誤的版本檢查邏輯。使用者體驗要么是「靜默失敗」 (啟動後無反應),要么是彈窗宣稱「需要 Windows XP」——明明運行在 Windows 7 上。這類問題通常由兩類原因造成:

  1. 程式碼缺陷:邏輯錯誤 (如 != 代替 >=)、主版本號變更 (5.1→6.0) 導致判斷失效、預期的 Service Pack 未安裝
  2. 故意阻擋:開發者為避免未測試環境風險,主動封鎖未來版本 (強烈不建議)

快速修復:使用者與 IT 專業人員工具

1. 相容模式 (終端使用者)

  1. 右鍵 .exe / 捷徑 → 內容 → 相容性
  2. 勾選「以相容模式執行」→ 選擇目標版本 (如 Windows XP SP3)
  3. 確定 → 執行
相容模式設定
> ⚠️ **限制**:對純受控代碼 (Environment.OSVersion) 無效;混合模式若透過 P/Invoke 呼叫原生版本 API 則有效。

2. 應用程式相容性工具組 ACT (IT/開發者)

建立自訂相容性資料庫 (.sdb),部署到目標電腦:

  1. 啟動 相容性管理員 (ACT 安裝後)
  2. 右鍵建立 新資料庫 → 重新命名
  3. 右鍵資料庫 → Create New → Application Fix
  4. 填寫應用程式資訊 → Next
建立新資料庫
建立 Application Fix
  1. 作業系統模式 選 None
  2. 額外相容模式 選 WinXPSP2VersionLie (版本謊言修正)
  3. 完成嚮導 → 工具列 Save 產生 .sdb
  4. 用 SDBinst 安裝到目標機
選擇版本謊言修正
完成嚮導
儲存 SDB

根治方案:正確的版本檢查邏輯

原生 C++:GetVersionEx 簡易版

#include <windows.h>
#include <stdio.h>

void main()
{
    OSVERSIONINFO osvi;
    BOOL bIsWindowsXPorLater;

    ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&osvi);

    bIsWindowsXPorLater =
        (osvi.dwMajorVersion > 5) ||
        (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion >= 1);

    if (bIsWindowsXPorLater)
        printf("The system meets the requirements.\n");
    else
        printf("The system does not meet the requirements.\n");
}

原生 C++:VerifyVersionInfo 精確版 (檢查 XP SP2+)

#include <windows.h>

BOOL Is_WinXP_SP2_or_Later()
{
    OSVERSIONINFOEX osvi;
    DWORDLONG dwlConditionMask = 0;
    int op = VER_GREATER_EQUAL;

    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    osvi.dwMajorVersion = 5;
    osvi.dwMinorVersion = 1;
    osvi.wServicePackMajor = 2;
    osvi.wServicePackMinor = 0;

    VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op);
    VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, op);
    VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR, op);
    VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMINOR, op);

    return VerifyVersionInfo(&osvi,
        VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
        dwlConditionMask);
}

.NET Framework:Version 物件比較

// 檢查至少 Windows XP
if (Environment.OSVersion.Version < new Version(5, 1))
{
    MessageBox.Show("Windows XP or later required.",
        "Incompatible Operating System", MessageBoxButtons.OK, MessageBoxIcon.Error);
    return;
}
  • 支援 == != <= < > >= 運算子
  • Version 實作 IComparable,邏輯直觀

終極最佳實踐:功能檢測取代版本檢測

作業系統可能透過可轉散發套件新增功能 (如 Direct2D/DirectWrite/Ribbon 回溯至 Vista)。檢測功能而非版本,應用程式才能在功能存在時受益,不存在時優雅降級。

Win32 技巧:LoadLibrary + GetProcAddress

// 定義函數指標型別
typedef BOOL (WINAPI *SetWaitableTimerExProc)(...);

LARGE_INTEGER liDueTime = {0};
LONG period = 1000;
ULONG tolerance = 1000;
HANDLE hTimer = ...;

REASON_CONTEXT reasonContext = {0};
reasonContext.Version = 0;
reasonContext.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
reasonContext.Reason.SimpleReasonString = L"MyTimer";

HMODULE hKernel32Module = GetModuleHandle(_T("kernel32.dll"));
if (hKernel32Module == NULL) return FALSE;

SetWaitableTimerExProc pFnSetWaitableTimerEx = (SetWaitableTimerExProc)::GetProcAddress(hKernel32Module, "SetWaitableTimerEx");

if (pFnSetWaitableTimerEx == NULL) return FALSE; // 功能不存在

if (!pFnSetWaitableTimerEx(hTimer, &liDueTime, period, NULL, NULL, &reasonContext, tolerance))
{ /* handle error */ }
  • 已載入模組用 GetModuleHandle;未載入用 LoadLibrary
  • GetProcAddress 回傳 NULL = 功能不存在
  • 備選:延遲載入 DLL (/DELAYLOAD + __try/__except)

COM API

檢查 CoCreateInstance / QueryInterface 回傳 HRESULT。

.NET P/Invoke

捕捉 EntryPointNotFoundException (函數不存在) 與 DllNotFoundException (DLL 不存在)。

工具與資源彙整

  • Microsoft 應用程式相容性工具組 (ACT)
  • 應用程式相容性手冊:MSDN
  • 版本謊言與受控應用程式:部落格

總結:三層防禦體系

層級對象手段適用場景
L1 緊急修復使用者/IT相容模式 / ACT SDB 部署無法修改程式碼的舊版應用程式
L2 程式碼修正開發者VerifyVersionInfo / Version >= 正確表達最低需求必須檢查版本的舊代碼庫
L3 架構升級開發者功能檢測 (GetProcAddress/QueryInterface/Exception 捕捉)新專案 / 重構 / 跨版本長期維護

**核心信條**:不要阻擋未來版本。正確表達「最低門檻」,優先檢測「功能可用性」,讓應用程式在時間長河中自然演進。

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