星期四, 十月 15, 2009

Windows SDK練習曲--檢驗Windows版本資訊

Windows版本資訊除了能「取得」之後自行檢查,也能直接將相關資訊送交特定API來檢驗;例如若想知道是不是Windows 7,就送驗主序號6和次序號1。


負責檢驗版本資訊的API是VerifyVersionInfo,但在呼叫之前,必須先以OSVERSIONINFOEX結構和VER_SET_CONDITION巨集來處理欲檢驗的相關資訊。以下以檢驗Windows 7為例說明(Windows 7的版本序號是6.1)。

設定OSVERSIONINFOEX結構

之前的例子就曾用過OSVERSIONINFOEX,這個結構可儲存好幾種Windows版本相關資訊,本例欲檢驗Windows 7,因此其中與本例相關的是:

  • dwMajorVersion:主序號,設為6。
  • dwMinorVersion:次序號,設為1。
  • wServicePackMajor:Service Pack主序號,設為0。
  • wServicePackMinor:Service Pack次序號,設為0。
  • wProductType:產品類型,設為VER_NT_WORKSTATION。

雖然目前Windows 7並無Service Pack,也就是並無檢驗Service Pack序號的必要,但仍建議加入,並設為0。整個初始OSVERSIONINFOEX的程式碼如下:

OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
osvi.dwMajorVersion = 6;
osvi.dwMinorVersion = 1;
osvi.wServicePackMajor = 0;
osvi.wServicePackMinor = 0;
osvi.wProductType = VER_NT_WORKSTATION;

呼叫VER_SET_CONDITION巨集

VER_SET_CONDITION巨集的目的是設定比較的條件遮罩,以設定Windows 7的主序號為例:

VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
  • dwlConditionMask:儲存比較資訊(初始值需為0),後續會是呼叫VerifyVersionInfo的第3個參數。
  • VER_MAJORVERSION:設定比較的類型,VER_MAJORVERSION即為版本主序號。所有類型的常數包括:
    • VER_BUILDNUMBER(dwBuildNumber)
    • VER_MAJORVERSION(dwMajorVersion)
    • VER_MINORVERSION(dwMinorVersion)
    • VER_PLATFORMID(dwPlatformId)
    • VER_PRODUCT_TYPE(wProductType)
    • VER_SERVICEPACKMAJOR(wServicePackMajor)
    • VER_SERVICEPACKMINOR(wServicePackMinor)
    • VER_SUITENAME(wSuiteMask)
  • VER_GREATER_EQUAL:比較運算子,VER_GREATER_EQUAL表示必須大於或等於,也就是本例必須大於或等於6才會得到True值。其他的運算子常數包括:
    • VER_EQUAL:等於
    • VER_GREATER:大於
    • VER_GREATER_EQUAL:大於或等於
    • VER_LESS:小於
    • VER_LESS_EQUAL:小於或等於

本例需比較5項資訊,程式碼如下:

VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL);
VER_SET_CONDITION(dwlConditionMask, VER_NT_WORKSTATION, VER_EQUAL );

呼叫VerifyVersionInfo函式

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

VerifyVersionInfo函式有3個參數:

  1. 指向OSVERSIONINFOEX的指標。
  2. 檢驗的類型,同VER_SET_CONDITION的第2個參數,能以OR位元運算子(|)合併所有欲檢驗的類型常數。
  3. 比較資訊,就是VER_SET_CONDITION巨集的第1個參數。

VerifyVersionInfo函式的傳回值有3種情況:

  • 目前作業系統符合檢驗資訊,傳回非零值(也就是True)。
  • 目前作業系統「不」符合檢驗資訊,或,傳回零(也就是Flase),且GetLastError函式會傳回ERROR_OLD_WIN_VERSION。
  • VerifyVersionInfo函式呼叫失敗,傳回零(也就是Flase),且GetLastError函式會傳回不同於ERROR_OLD_WIN_VERSION的錯誤碼(端視錯誤原因而定)。

檢驗Windows版本資訊

我們可以將檢驗Windows 7的程式碼包裝成函式(例如Is_Win7_or_Later),再根據傳回值來判斷目前的作業系統版本是不是Windows 7:

if(Is_Win7_or_Later())
    printf("這是 Windows 7 或其後續版本\n");
else printf("這不是 Windows 7 或其後續版本\n");

完整的程式碼請下載verifyWinVer.zip(1 KB),其中還另外包含了Windows Server 2008 SP2及網域控制器的檢驗。

參考資料

4 意見:

~影子~ 提到...

嗚~我程式知識不深都看不懂
> <

賴榮樞 提到...

影子您好:

如果您想看懂的話,可以花點時間加強 C 語言、Windows SDK 開發的能力。

NONO 提到...

賴大哥您好,小弟想請問一下,如何判斷作業系統WIN-PE與非WIN-PE?因為使用您的方式擷取出來的資訊並不能判斷出是否為PE版本,系統提供的API得到的版本數在WIN-PE與非WIN-PE下得到的版本數皆相同,小弟也曾參考MSND範例http://msdn.microsoft.com/en-us/library/ms724429(v=VS.85).aspx,但還是得不到答案,所以想請教賴大哥有什麼方式可以判斷目前作業系統版本是否為WIN-PE,謝謝。

賴榮樞 提到...

NONO你好:

目前並沒有直接得知Windows PE版本資訊的Windows API,只能旁敲側擊。

網路上有一篇討論(http://groups.google.com/group/microsoft.public.win32.programmer.kernel/browse_thread/thread/8da9b4e7a911b410?pli=1),其中Jeffrey Tan提供的方式值得一試,供你參考。