絕大多數應用程式相容性問題源於錯誤的版本檢查邏輯。使用者體驗要么是「靜默失敗」 (啟動後無反應),要么是彈窗宣稱「需要 Windows XP」——明明運行在 Windows 7 上。這類問題通常由兩類原因造成:
!= 代替 >=)、主版本號變更 (5.1→6.0) 導致判斷失效、預期的 Service Pack 未安裝
Environment.OSVersion) 無效;混合模式若透過 P/Invoke 呼叫原生版本 API 則有效。
建立自訂相容性資料庫 (.sdb),部署到目標電腦:
Create New → Application FixNext

NoneWinXPSP2VersionLie (版本謊言修正)Save 產生 .sdbSDBinst 安裝到目標機


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");
}
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);
}
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)。檢測功能而非版本,應用程式才能在功能存在時受益,不存在時優雅降級。
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;未載入用 LoadLibraryGetProcAddress 回傳 NULL = 功能不存在/DELAYLOAD + __try/__except)檢查 CoCreateInstance / QueryInterface 回傳 HRESULT。
捕捉 EntryPointNotFoundException (函數不存在) 與 DllNotFoundException (DLL 不存在)。
| 層級 | 對象 | 手段 | 適用場景 |
|---|---|---|---|
| L1 緊急修復 | 使用者/IT | 相容模式 / ACT SDB 部署 | 無法修改程式碼的舊版應用程式 |
| L2 程式碼修正 | 開發者 | VerifyVersionInfo / Version >= 正確表達最低需求 | 必須檢查版本的舊代碼庫 |
| L3 架構升級 | 開發者 | 功能檢測 (GetProcAddress/QueryInterface/Exception 捕捉) | 新專案 / 重構 / 跨版本長期維護 |
**核心信條**:不要阻擋未來版本。正確表達「最低門檻」,優先檢測「功能可用性」,讓應用程式在時間長河中自然演進。