星期三, 十一月 18, 2009

如何製作能安裝Windows 7的USB隨身碟

我決定將正式版的Windows 7裝進Asus 1000HE;但因為沒有外接式光碟機,因此要將Windows 7安裝光碟的內容複製到USB隨身碟,並且利用USB隨身碟來開機、安裝。

以下我將會說明3種製作Windows 7安裝隨身碟的方法:一種常見於網路、另兩種更為簡便。開始之前我先大致歸納,基本上,要完成的事情包括:

  • 讓USB隨身碟能夠開機
  • 將Windows 7安裝光碟的內容複製到USB隨身碟
  • 將電腦設定成能以USB裝置開機(本文不會說明這點,請參考自己機器或主機板的手冊,或直接詢問廠商)

因此需要:

  • 能以USB裝置開機的電腦
  • 容量至少4GB的USB隨身碟(Windows 7  x86大約需要2.5  GB、x64需要3  GB左右)
  • Windows 7安裝光碟或ISO檔
  • Windows XP或Windows 7環境(我只在這兩種環境試過,但若能適用Windows 7,應該也適用Vista--不過這只是經驗推測)

在Windows 7環境製作

網路上許多文章--包括TechNet Magazine的Use a USB Key to Install Windows 7—Even on a Netbook,都提及在Windows 7可以利用DiskPart來處理隨身碟(包括格式化,因此請先備份隨身碟裡的重要檔案),然後再將Windows 7安裝光碟的內容複製到USB隨身碟即可。以下是TechNet Magazine《Use a USB Key to Install Windows 7—Even on a Netbook》的作法。再次強調,雖然Windows XP也有DiskPart,但以下只能用在Windows 7。

  1. 將隨身碟接上電腦,並確定已正確接上。
  2. 以系統管理員身份開啟『命令提示字元』。
  3. 執行diskpart
  4. 執行list disk,這會列出電腦所有的實體磁碟。
  5. 觀察列出結果,並記下隨身碟的磁碟編號。隨身碟的磁碟編號通常在後面,甚至是最後一個,此外也可以容量來識別。例如我這個例子是「磁碟3」。
  6. 根據隨身碟的磁碟編號,執行select disk {n},n是隨身碟的磁碟編號。以我為例,即需執行select disk 3。
  7. 執行clean,這會清理隨身碟,因此不會再有任何分割區。
  8. 執行create partition primary,這會在隨身碟建立主分割區。
  9. 執行select partition 1,這會選取隨身碟唯一的分割區。
  10. 執行active,這會將上一步所選取的分割區設為「使用中」,也就等於告知BIOS或EFI,這個分割區是可以用來開機的系統分割區或系統磁碟區。
  11. 執行format fs=fat32 quick,這會以快速模式將隨身碟格式化成FAT32檔案系統。
  12. 執行assign,這會將磁碟代號指定給剛在隨身碟建立、格式化過的分割區。
  13. 執行exit,這會結束diskpart、並關閉它的視窗。

 

接著,請將Windows 7安裝光碟的內容全部複製到USB隨身碟。完成複製之後,這支USB隨身碟就可以開機、安裝Windows 7。接下來要做的,是將這支隨身碟插入電腦,然後設定電腦BIOS,讓電腦能以USB裝置開機。之後螢幕就會顯示Windows 7安裝畫面,依照畫面指示即可安裝Windows 7。

更簡單的作法

不過我發現更簡單的作法。以下的作法適用Windows 7環境,請記得將其中的{drive letter:}換成你自己的隨身碟磁碟代號:

  1. 將隨身碟接上電腦,並確定已正確接上。
  2. 開啟『命令提示字元』,以下步驟3需在命令提示字元輸入指令。
  3. 將USB隨身碟快速格式化成NTFS:format {drive letter:} /q
  4. 將Windows 7安裝光碟的內容全部複製到USB隨身碟(這就不一定要用命令提示字元,利用檔案總管拖放即可)。。

完成!現在可以用這支隨身碟來開機、安裝Windows 7。

在Windows XP環境製作

上述的4步驟大致也能用在Windows XP環境,只是要略作修改;我在差異處加了底線:

  1. 將隨身碟接上電腦,並確定已正確接上。
  2. 開啟『命令提示字元』,以下步驟3~5需在命令提示字元輸入指令。
  3. 將USB隨身碟快速格式化成FAT32format {drive letter:} /fs:fat32 /q
  4. 將隨身碟的檔案系統轉換成NTFSconvert {drive letter:} /fs:ntfs
  5. 執行Windows 7安裝光碟boot資料夾裡的bootsect,才能讓隨身碟開機bootsect /nt60 {drive letter:}
  6. 將Windows 7安裝光碟的內容全部複製到USB隨身碟(同樣的,這就不一定要用命令提示字元,利用檔案總管拖放即可)。

完成!現在這支隨身碟也能用來開機、安裝Windows 7。

x64版本的Windows 7安裝隨身碟

要注意的是上述步驟5的bootsect,如果是在x86環境(不論Windows 7或Windows XP),要製作x64版本的Windows 7安裝隨身碟,不能執行x64 Windows 7安裝光碟boot資料夾裡的bootsect,因為這支bootsect是64位元,不能在32位元環境執行。解決的方法應該是執行x86 Windows 7安裝光碟裡的bootsect(不過我沒有實際試過)。


[全文]

星期三, 十月 28, 2009

User State Migration Tool 4示範影片

最近作了一段User State Migration Tool(USMT)4示範影片。

USMT 4是Windows自動化安裝套件(Windows Automated Installation Kit,WAIK)所提供的命令列工具程式之一,它最主要的兩支程式是 ScanState 和 LoadState,在移轉Windows的過程擔任資料收集和回存的角色,協助您將Windows系統裡的相關設定值移轉到另一部Windows電腦。

這段名為〈邊做邊學 Windows 7:以 USMT 4 將 Windows XP 移轉到 Windows 7〉的影片,收錄在TechNet教學短片

附註一提,微軟在上週透過Microsoft Download Center釋出1.1版的Windows 7 WAIK文件(AIK_Windows7_DocUpdate_10.2009.zip),但此更新文件目前僅有英文版。


[全文]

星期四, 十月 22, 2009

硬體輔助虛擬化偵測工具--Hardware-Assisted Virtualization Detection Tool

諸如Windows Virtual PC(文後簡稱WVPC)必須在支援硬體輔助虛擬化的電腦執行,為了讓使用者更容易識別自己的電腦支不支援這項技術,微軟提供了Hardware-Assisted Virtualization Detection Tool(文後簡稱HAVDT),協助使用者檢測。

對WVPC的執行而言,硬體輔助虛擬化技術有兩項重點:

  • 處理器必須支援硬體輔助虛擬化技術,例如Intel Virtualization Technology(Intel VT)、AMD Virtualization(AMD-V)或VIA VT等,皆是硬體輔助虛擬化技術。
  • 主機板必須啟用處理器所提供的硬體輔助虛擬化技術,有些板子預設關閉了這項功能,因此必須進到BIOS開啟,而且每家廠商在BIOS設定的位置、所用的名稱也各不相同(例如在我Asus P5B-E Plus的AMI BIOS設定,是以Intel VT專案代號Vanderpool Technology稱之)。細節可查閱廠商提供的手冊或直接詢問廠商。

HAVDT不止能檢測處理器是否支援硬體輔助虛擬化技術,還能檢查系統是否開啟了這項功能。HAVDT檔案很小,而且不需安裝就能執行,可到微軟網站下載。HAVDT支援的Windows系統如下:

  • Windows XP SP 3 (Professional)、Windows XP SP 2 (Professional)
  • Windows Vista SP 1, 2 (Home Basic、Home Premium、Business、Enterprise、Ultimate)
  • Windows 7 (Home Basic、Home Premium、Professional、Enterprise、Ultimate)

HAVDT有以下5種執行結果。

  • This tool does not run on this operating system:「HAVDT無法在此作業系統執行」;HAVDT只支援上述版本的Windows,若執行的Windows版本不在上列,就會出現這種結果。

  • This computer does not have hardware-assisted virtualization:「此電腦不含硬體輔助虛擬化功能」;因此無法執行WVPC、Windows XP Mode。

  • Hardware-assisted virtualization is not enabled on this computer:「此電腦的硬體輔助虛擬化功能尚未啟用」;通常要透過BIOS設定來啟用這項功能,而且啟用之後才能執行WVPC、Windows XP Mode。

  • This computer is configured with hardware-assisted virtualization:「此電腦能提供硬體輔助虛擬化技術」;這意味著這部電腦不僅CPU支援硬體輔助虛擬化技術,而且也已啟用這項功能,當然就能執行WVPC、Windows XP Mode。

  • The configuration of this computer is not compatible with Windows Virtual PC:「此電腦的設定與WVPC不相容」;可能是因為這部電腦所具備的Intel Trust Execution Technology(Intel TXT)與WVPC不相容。Intel TXT應該可以從BIOS關閉(詳情可參閱主機板、電腦手冊,或詢問廠商)。

HAVDT也提供傳回值或將結果寫入記錄檔的功能,細節可參閱Microsoft Hardware-Assisted Virtualization Detection Tool User Guide(下載HAVDT的網頁亦可下載User Guide)。

參考資料

  • Microsoft Hardware-Assisted Virtualization Detection Tool User Guide


[全文]

Windows 7 Upgrade Advisor

就在Windows 7正式推出的前夕,Windows 7 Upgrade Advisor擺脫了測試階段,成為正式版本。

Windows 7 Upgrade Advisor是一支微軟提供的程式,可藉由安裝、執行、掃瞄而給予升級到Windows 7的建議;假如有一部想升級到Windows 7的電腦,便可在這部電腦安裝、執行Windows 7 Upgrade Advisor,這支程式會掃瞄電腦裡的軟硬體,並呈現一份升級的建議。

使用者可到微軟網站下載Windows 7 Upgrade Advisor的自解壓縮安裝程式Windows7UpgradeAdvisorSetup.exe,而因為Windows 7 Upgrade Advisor是以.NET 2.0開發,因此執行環境必須有.NET Framework 2.0;如果沒有,Windows 7 Upgrade Advisor的安裝程式會透過網路下載、安裝.NET Framework 2.0。

Windows7UpgradeAdvisorSetup.exe內含x86和x64兩種版本的程式,安裝程式會根據目的端的情況自動安裝適當的版本,並且會在桌面建立Windows 7 Upgrade Advisor的捷徑。

執行Windows 7 Upgrade Advisor之前,應該連接、開啟所有想在升級後的系統使用的USB硬體,例如印表機、掃描器、外接式儲存設備等。

執行Windows 7 Upgrade Advisor之後,它會掃瞄整個電腦的環境,並且根據情況,給予升級到Windows 7的建議。Windows 7 Upgrade Advisor主程式雖然會列出建議內容,不過最好還是將這份報告存檔(mht格式),以供後續查閱。

如果是執行Win32系統的x64電腦,Windows 7 Upgrade Advisor會提供32位元和64位元各一的報告(需個別存檔),分別列出升級到32位元或64位元Windows 7的建議。

報告的重點包括:

  • 需不需要自訂安裝?也就是先備份舊系統的資料,再重新安裝Windows 7及所有應用程式,最後再還原備份資料。
  • 顯示卡是否支援Aero?
  • CPU、RAM、硬碟空間是否符合升級後所需?
  • 包括顯示卡、網路卡、音效卡等重要的硬體是否相容Windows 7?也就是有沒有適當的驅動程式。
  • 舊系統裡的軟體是否相容Windows 7?結果有4種:有問題、相容、已獲得官方的Windows 7相容認證、未知。
  • 能不能執行Windows XP Mode?包括硬體是否支援,及記憶體、硬碟空間是否足夠。


[全文]

星期四, 十月 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及網域控制器的檢驗。

參考資料


[全文]

星期二, 十月 06, 2009

簡介Windows Automated Installation Kit for Windows 7

Windows Automated Installation Kit(Windows自動化安裝套件,簡稱Windows AIK或WAIK)是微軟提供的Windows自動化部署工具組。不同的WAIK版本,適合不同版本的Windows部署:第1個WAIK是針對Vista所設計,WAIK  1.1適用於Vista SP1和Windows Server 2008,目前最新的WAIK則支援Windows 7、Vista SP1、Windows Server 2008 R2、Windows Server 2008(但可以安裝在Windows XP)。

WAIK是以光碟映像ISO的格式釋出,目前最新版有1796.7  MB,可至微軟網站免費下載。利用虛擬光碟程式掛載ISO檔,或將ISO檔燒成光碟,就能安裝WAIK:可點選光碟自動播放程式左側的『Windows AIK安裝程式』,或者直接執行光碟根目錄的wAIKX86.msi(如果是x64,請執行wAIKAMD64.msi;Itanium請執行wAIKIA64.msi)。

安裝之後會在『開始』功能表建立『Microsoft Windows AIK』資料夾,裡面有相關工具及文件的捷徑(請注意,此資料夾並未包含所有工具程式或文件檔案的捷徑)。這些工具和文件預設是安裝在%ProgramFiles%\Windows AIK資料夾,有些工具程式或文件檔案必須直接到安裝資料夾尋找或執行。

WAIK的工具包括:

  • Windows系統映像管理員(Windows System Image Manager)
  • ImageX(可用以擷取、建立、修改、套用Windows映像的工具)
  • Deployment Image Servicing and Management(DISM)
  • Windows Preinstallation Environment(Windows PE)
  • User State Migration Tool(USMT)
  • 大量啟用管理工具(VAMT)

隸屬WAIK但不在上述WAIK安裝資料夾裡的工具有:

  • Windows安裝程式(用來安裝Windows的程式,位於Windows產品光碟)
  • Sysprep(位於%WINDIR%\system32\sysprep資料夾)

WAIK相關工具對不同Windows版本及硬體架構,各有不同的支援,細節可參閱TechNet Library的《Deployment Tools Supported Platforms》。


[全文]

Windows 7小時鐘也能顯示3個時區的時間

預設只會顯示系統時區的時間,但透過『日期和時鐘/其他時鐘』的設定,Windows 7的小時鐘最多能顯示3個時區的時間。

修改之後,將滑鼠移到工作列右側顯示時間的位置,就會顯示所有已指定的時間。

如果以滑鼠點擊工作列右側顯示時間的位置,則會顯示所有已指定的時間。


[全文]

Windows SDK練習曲--取得系統資訊

之前做過的osInfo為基礎,再呼叫若干取得系統資訊的API,拼湊並改版成sysInfo。

sysInfo是主控台程式,不具實用性,完全無法與Windows內建的systemInfo.exe相比;製作sysInfo的目的只是呼叫相關API的練習。

除了之前osInfo用到的技巧,sysInfo又呼叫了GetComputerGetUserNameGetSystemDirectoryGetWindowsDirectoryExpandEnvironmentStrings,以及GetNativeSystemInfo / GetSystemInfo

由於程式不算短,與其完整列在網頁,不如讓有興趣的人下載(sysInfo.zip,4 KB)後研究。我在程式碼裡加了若干註解,而相關API的細節,則請參閱MSDN Library。

參考資料:MSDN Getting System Information


[全文]

星期一, 十月 05, 2009

Windows 7內建光碟映像檔燒錄程式

其名為『Windows光碟映像燒錄程式』,能支援ISO和IMG格式,而且預設也與這兩種檔案類型設定關聯,只要以滑鼠雙按這兩種類型的檔案,就會出現『Windows光碟映像燒錄程式』。

如果Windows 7安裝了其他會處理光碟映像檔案的軟體,可能會覆蓋『Windows光碟映像燒錄程式』與ISO、IMG的檔案關聯,而須執行滑鼠右鈕快顯功能表的『開啟檔案』裡面的『Windows光碟映像燒錄程式』。


[全文]

Windows 7的可靠性監視器

源自Vista的『可靠性及效能監視器』,Windows 7的『可靠性監視器』列出電腦的『嚴重事件』和『資訊事件』。

欲執行『可靠性監視器』,可先從『控制台』執行『行動作業中心』,再從『行動作業中心』的『維護』底下,點選『檢視可靠性歷程記錄』。或者,在『開始/搜尋程式或檔案』輸入『Reliability』,也會找到『檢視可靠性歷程記錄』。

『可靠性監視器』能以天或週作為檢視方式,可供使用者查看嚴重事件(例如有哪些程式當掉)及資訊事件(例如安裝了哪些系統更新程式)。『可靠性監視器』還會以1到10的分數來評估系統整體的穩定性。


[全文]

Windows 7的問題步驟收錄程式--PSR

多數願意助人解決電腦問題的熱心人士,可能經常遇到不懂發問者在講什麼的情況。現在,Windows 7提供的『問題步驟收錄程式』(Problem Steps Recorder,PSR),可以讓發問者錄下操作步驟;藉此,或許對發問與回答之間的溝通有所助益。

欲執行『問題步驟收錄程式』,可以在『開始』功能表裡的『搜尋程式及檔案』輸入psr,就會看到『psr.exe』和『記錄步驟以重現問題』,任點其中一個皆可啟動PSR。

psr

按下PSR的『開始錄製』之後,PSR會擷取使用者每個操作動作的全螢幕畫面,並且自動附上每個步驟的文字說明。使用者亦可在錄製的過程『新增註解』。

按下PSR的『停止錄製』之後,PSR會將所錄製的圖檔畫面、文字說明編譯成單一的MHTML檔,並且再壓縮成ZIP檔,而後讓使用者決定ZIP檔的存放位置。

接著發問者可透過將ZIP檔交給回答者,並輔以適當的問題說明,應該可讓回答者更能瞭解問題所在。

此外,使用者也可以選擇不擷取螢幕畫面(在『說明/設定』所出現的交談窗,點選『啟用螢幕擷取』的『否』),這只會產生每個步驟的文字說明。

想要更瞭解PSR嗎?執行它、隨意錄製幾個步驟、存檔,然後開啟並檢視壓縮檔裡的MHTML,必能對PSR的功能有所體悟。


[全文]

星期二, 九月 29, 2009

Jump List很棒,但有時候還是需要快顯功能表

Windows 7可以讓使用者在工作列建立程式的捷徑,但這種情況若對程式捷徑按下滑鼠右鈕,所顯現的是『Jump List』。但,捷徑原本的快顯功能表呢?

我會將常用的程式訂選到工作列,但之前讓我困擾的是,若對這類工作列的程式捷徑按下滑鼠右鈕,所顯現的是『Jump List』,而非原本的快顯功能表。

難道這類捷徑無法顯現快顯功能表嗎?

不是,只是必須拐個彎:要先按住Shift按鍵,再對程式捷徑按下滑鼠右鈕,才會顯現快顯功能表。


[全文]

星期一, 九月 28, 2009

Windows 7內建Open Command Windows Here

我很喜歡Microsoft PowerToys for Windows XP裡的Open Command Windows Here,原本打算找找怎麼讓Windows 7也具備這項功能,但其實Windows 7已經內建這項功能了。

只是微軟讓使用者必須拐個彎才能看到這項功能:先按住Shift按鍵,再以滑鼠右鈕按下檔案總管裡的磁碟或資料夾項目。這時所顯現的快顯功能表,會多出一些項目,其中的『在此處開啟命令視窗』,就如同Microsoft PowerToys for Windows XP的Open Command Windows Here。

Windows_Explorer_Right_Click_Shift

按住Shift按鍵的快顯功能表多出的項目還有『在新處理程序開啟』和『複製路徑』。


[全文]

星期四, 九月 24, 2009

Windows SDK練習曲--Windows版本相關資訊 [Native Code] (2)

取得Windows版本相關資訊--Native Code(1)》曾提及取自Windows SDK 7的Getting the System Version主控台程式,這個程式用了許多Windows API取得Windows版本資訊,以下則將簡述這些API。

GetVersionEx

從Windows 2000就存在的GetVersionEx,是取得Windows版本資訊的基本函式。如果呼叫失敗,GetVersionEx會傳回0;呼叫成功則傳回非0。

GetVersionEx必須使用OSVERSIONINFO或OSVERSIONINFOEX結構作為參數,GetVersionEx會將取得的資訊置入作為參數的結構,包括Windows的主序號、次序號等。以下列出幾個Windows的主序號及次序號。

Windows 主序號.次序號
Windows 2000 5.0(用戶端及伺服端皆然)
Windows XP 5.1
Windows Server 2003 5.2
Windows Server 2003 R2 5.2
Windows Vista 6.0
Windows Server 2008 6.0
Windows 7 6.1
Windows Server 2008 R2 6.1


這支程式會用到OSVERSIONINFOEX的以下成員:

  • dwPlatformId:平台代號,其值若為VER_PLATFORM_WIN32_NT,表示NT平台。
  • dwMajorVersion:主版本序號
  • dwMinorVersion:次版本序號
  • wProductType:Windows作業系統的產品類型,有VER_NT_WORKSTATION、VER_NT_SERVER、VER_NT_DOMAIN_CONTROLLER等3種常數值。用來判斷Windows是用戶端還是伺服器版本。
  • wSuiteMask:Windows作業系統的組合方式,可以利用位元運算(遮罩)查得作業系統的詳細資訊。可以用來檢查伺服器版是不是Home Server、Datacenter或Enterprise等版本、用戶端版是不是家用版、或是不是Embedded版本。

關於GetVersionEx及OSVERSIONINFOEX,還可參考舊作《如何檢測各種Windows平台的版本資訊》的《利用GetVersionEx檢查Windows系統版本》、《GetVersionEx使用範例》、《OSVERSIONINFOEX結構剖析》、《GetVersionEx與OSVERSIONINFOEX搭配應用》等節。

GetNativeSystemInfo / GetSystemInfo

這兩個函式在這支程式的目的是偵測Windows版本是不是x86、x64或IA64。32位元程式要呼叫GetNativeSystemInfo,64位元程式要呼叫GetSystemInfo。GetNativeSystemInfo或GetSystemInfo需使用SYSTEM_INFO結構,而這支程式會用到結構中的wProcessorArchitecture成員,這個成員可以是以下常數值:

常數值 說明
PROCESSOR_ARCHITECTURE_AMD64 x64
PROCESSOR_ARCHITECTURE_IA64 IA64(Intel Itanium)
PROCESSOR_ARCHITECTURE_INTEL x86
PROCESSOR_ARCHITECTURE_UNKNOWN 未知

GetSystemMetrics

這個API會根據參數而傳回系統特定的公制單位或系統設定值。這支程式以下列方式檢查是不是Windows Server 2003 R2:

if( GetSystemMetrics(SM_SERVERR2) )

GetProductInfo

這是Vista及Windows Server 2008開始支援的API,可以根據傳入的主、次版本序號及主、次Service Pack版本序號,取得SKU(例如旗艦版還是企業版)。此函式實際上可取得的 SKU 不止這支程式所列,完整資訊可參考SDK文件。

參考資料:MSDN Getting the System Version


[全文]

星期三, 九月 23, 2009

Windows SDK練習曲--Windows版本相關資訊 [Native Code] (1)

程式可能需要取得Windows版本相關資訊,以下取自Windows SDK 7 Getting the System Version的主控台程式,或許可作為您的參考。

[2009/09/24更新]更新程式碼,會顯示版本的主序號和次序號。

這支程式一共用了GetVersionExGetSystemMetricsGetProductInfoGetNativeSystemInfo / GetSystemInfo等API(延伸閱讀:《取得Windows版本相關資訊--Native Code(2)》),能取得相當完整的版本資訊,包括序號、SKU、用戶端或伺服端、Service Pack'、Build Number等。

我是以Visual Studio 2008建立這支主控台程式(系統需先安裝Windows SDK)。以下分別是這支主控台程式在我的Windows 7及Windows XP的執行結果。

osInfo on Windows 7

osInfo-xp

這支程式取自Windows SDK 7的Getting the System Version,但以下的中文註解是我所加入。

   1:  // osInfo.cpp : 定義主控台應用程式的進入點。
   2:  //
   3:  
   4:  #include "stdafx.h"
   5:  #include <windows.h>
   6:  #include <tchar.h>
   7:  #include <stdio.h>
   8:  #include <strsafe.h>
   9:  
  10:  #pragma comment(lib, "User32.lib")
  11:  
  12:  #define BUFSIZE 256
  13:  
  14:  typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
  15:  typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
  16:  
  17:  BOOL GetOSDisplayString( LPTSTR pszOS)
  18:  {
  19:      // 宣告變數
  20:      OSVERSIONINFOEX osvi; // 呼叫GetVersionEx需要此結構,內存Windows版本相關資訊
  21:      SYSTEM_INFO si; // 呼叫GetNativeSystemInfo需要此結構,內存系統資訊
  22:      PGNSI pGNSI;
  23:      PGPI pGPI;
  24:      BOOL bOsVersionInfoEx;
  25:      DWORD dwType;
  26:      
  27:      ZeroMemory(&si, sizeof(SYSTEM_INFO));
  28:      ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  29:      
  30:      osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  31:  
  32:      // GetVersionEx 呼叫成功會傳回非0值
  33:      //
  34:      if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
  35:          // GetVersionEx 呼叫失敗,結束函式
  36:          return 1;
  37:  
  38:      // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise
  39:      // 呼叫 GetNativeSystemInfo 或 GetSystemInfo
  40:      pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo");
  41:      if(NULL != pGNSI)
  42:          pGNSI(&si);
  43:      else GetSystemInfo(&si); // 呼叫 GetNativeSystemInfo 失敗,改呼叫 GetSystemInfo
  44:  
  45:      // NT 平台且主版本序號大於 4 者,會符合以下條件式
  46:      // 這支程式僅支援 NT 平台且主版本序號大於 4 的 Windows
  47:      if ( VER_PLATFORM_WIN32_NT==osvi.dwPlatformId && osvi.dwMajorVersion > 4 )
  48:      {
  49:          // 隨著以下的檢查,會一一將查到的資訊複製到 pszOS 字串
  50:          StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft "));
  51:  
  52:          // Test for the specific product.
  53:          // 先從主版本序號為 6 的產品開始檢
  54:          // 也就是 Vista / Windows Server 2008、Windows 7 / Windows Server 2008 R2
  55:          if ( osvi.dwMajorVersion == 6 )
  56:          {
  57:              // 如果次版本序號是 0,就是 Vista / Windows Server 2008
  58:              if( osvi.dwMinorVersion == 0 )
  59:              {
  60:                  // VER_NT_WORKSTATION 表示用戶端版
  61:                  if( osvi.wProductType == VER_NT_WORKSTATION )
  62:                      StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista (Ver 6.0) "));
  63:                  // 不然就是伺服器版
  64:                  else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 (Ver 6.0) " ));
  65:              }
  66:  
  67:              // 如果次版本序號是 1,就是 Windows 7 / Windows Server 2008 R2
  68:              if ( osvi.dwMinorVersion == 1 )
  69:              {
  70:                  if( osvi.wProductType == VER_NT_WORKSTATION )
  71:                      StringCchCat(pszOS, BUFSIZE, TEXT("Windows 7 (Ver 6.1) "));
  72:                  else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 (Ver 6.1) " ));
  73:              }
  74:              
  75:              // 呼叫 GetProductInfo,取得產品類型
  76:              pGPI = (PGPI) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo");
  77:              
  78:              pGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
  79:              
  80:              // 根據 dwType 取得 SKU
  81:              // 實際上可取得的 SKU 不止以下所列,
  82:              // 完整資訊可參考 SDK 文件 GetProductInfo 的說明
  83:              switch( dwType )
  84:              {
  85:              case PRODUCT_ULTIMATE:
  86:                  StringCchCat(pszOS, BUFSIZE, TEXT("Ultimate Edition" ));
  87:                  break;
  88:              case PRODUCT_HOME_PREMIUM:
  89:                  StringCchCat(pszOS, BUFSIZE, TEXT("Home Premium Edition" ));
  90:                  break;
  91:              case PRODUCT_HOME_BASIC:
  92:                  StringCchCat(pszOS, BUFSIZE, TEXT("Home Basic Edition" ));
  93:                  break;
  94:              case PRODUCT_ENTERPRISE:
  95:                  StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
  96:                  break;
  97:              case PRODUCT_BUSINESS:
  98:                  StringCchCat(pszOS, BUFSIZE, TEXT("Business Edition" ));
  99:                  break;
 100:              case PRODUCT_STARTER:
 101:                  StringCchCat(pszOS, BUFSIZE, TEXT("Starter Edition" ));
 102:                  break;
 103:              case PRODUCT_CLUSTER_SERVER:
 104:                  StringCchCat(pszOS, BUFSIZE, TEXT("Cluster Server Edition" ));
 105:                  break;
 106:              case PRODUCT_DATACENTER_SERVER:
 107:                  StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition" ));
 108:                  break;
 109:              case PRODUCT_DATACENTER_SERVER_CORE:
 110:                  StringCchCat(pszOS, BUFSIZE, TEXT("Datacenter Edition (core installation)" ));
 111:                  break;
 112:              case PRODUCT_ENTERPRISE_SERVER:
 113:                  StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition" ));
 114:                  break;
 115:              case PRODUCT_ENTERPRISE_SERVER_CORE:
 116:                  StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition (core installation)" ));
 117:                  break;
 118:              case PRODUCT_ENTERPRISE_SERVER_IA64:
 119:                  StringCchCat(pszOS, BUFSIZE, TEXT("Enterprise Edition for Itanium-based Systems" ));
 120:                  break;
 121:              case PRODUCT_SMALLBUSINESS_SERVER:
 122:                  StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server" ));
 123:                  break;
 124:              case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
 125:                  StringCchCat(pszOS, BUFSIZE, TEXT("Small Business Server Premium Edition" ));
 126:                  break;
 127:              case PRODUCT_STANDARD_SERVER:
 128:                  StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition" ));
 129:                  break;
 130:              case PRODUCT_STANDARD_SERVER_CORE:
 131:                  StringCchCat(pszOS, BUFSIZE, TEXT("Standard Edition (core installation)" ));
 132:                  break;
 133:              case PRODUCT_WEB_SERVER:
 134:                  StringCchCat(pszOS, BUFSIZE, TEXT("Web Server Edition" ));
 135:                  break;
 136:              }
 137:          }
 138:          
 139:          // 以下檢查主版本序號為 5 且次版本序號為 2 的產品
 140:          // 也就是 Windows Server 2003 或 Windows Server 2003 R2
 141:          if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
 142:          {
 143:              if( GetSystemMetrics(SM_SERVERR2) )
 144:                  StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Server 2003 R2 (Ver 5.2), "));
 145:              else if ( osvi.wSuiteMask==VER_SUITE_STORAGE_SERVER )
 146:                  StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Storage Server 2003 (Ver 5.2) "));
 147:              else if ( osvi.wSuiteMask==VER_SUITE_WH_SERVER )
 148:                  StringCchCat(pszOS, BUFSIZE, TEXT( "Windows Home Server (Ver 5.2) "));
 149:              else if( osvi.wProductType == VER_NT_WORKSTATION &&
 150:                  si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
 151:              {
 152:                  // Windows XP Professional x64 與 Windows Server 2003 是相同 codebase
 153:                  // 但 wProductType 是 VER_NT_WORKSTATION,
 154:                  // 且 wProcessorArchitecture 是 PROCESSOR_ARCHITECTURE_AMD64
 155:                  StringCchCat(pszOS, BUFSIZE, TEXT( "Windows XP Professional x64 Edition (Ver 5.2) "));
 156:              }
 157:              // 以上皆非則為 Windows Server 2003
 158:              else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2003, "));
 159:                       
 160:              // Test for the server type.
 161:              // 檢查其他的伺服器版
 162:              if ( osvi.wProductType != VER_NT_WORKSTATION )
 163:              {
 164:                  if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 )
 165:                  {
 166:                      if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
 167:                          StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition for Itanium-based Systems" ));
 168:                      else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
 169:                          StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition for Itanium-based Systems" ));
 170:                  }
 171:  
 172:                  else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
 173:                  {
 174:                      if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
 175:                          StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter x64 Edition" ));
 176:                      else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
 177:                          StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise x64 Edition" ));
 178:                      else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard x64 Edition" ));
 179:                  }
 180:                  else
 181:                  {
 182:                      if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
 183:                          StringCchCat(pszOS, BUFSIZE, TEXT( "Compute Cluster Edition" ));
 184:                      else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
 185:                          StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Edition" ));
 186:                      else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
 187:                          StringCchCat(pszOS, BUFSIZE, TEXT( "Enterprise Edition" ));
 188:                      else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
 189:                          StringCchCat(pszOS, BUFSIZE, TEXT( "Web Edition" ));
 190:                      else StringCchCat(pszOS, BUFSIZE, TEXT( "Standard Edition" ));
 191:                  }
 192:              }
 193:          }
 194:          
 195:          // 以下檢查主版本序號為 5 且次版本序號為 1 的產品
 196:          // 也就是 Windows XP
 197:          if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
 198:          {
 199:              StringCchCat(pszOS, BUFSIZE, TEXT("Windows XP (Ver 5.1) "));
 200:              if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
 201:                  StringCchCat(pszOS, BUFSIZE, TEXT( "Home Edition" ));
 202:              else StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
 203:          }
 204:          
 205:          // 以下檢查主版本序號為 5 且次版本序號為 0 的產品
 206:          // 也就是 Windows 2000
 207:          if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
 208:          {
 209:              StringCchCat(pszOS, BUFSIZE, TEXT("Windows 2000 (Ver 5.0) "));
 210:              
 211:              if ( osvi.wProductType == VER_NT_WORKSTATION )
 212:              {
 213:                  // 用戶端版本
 214:                  StringCchCat(pszOS, BUFSIZE, TEXT( "Professional" ));
 215:              }
 216:              else 
 217:              {
 218:                  // 伺服器版本
 219:                  if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
 220:                      StringCchCat(pszOS, BUFSIZE, TEXT( "Datacenter Server" ));
 221:                  else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
 222:                      StringCchCat(pszOS, BUFSIZE, TEXT( "Advanced Server" ));
 223:                  else StringCchCat(pszOS, BUFSIZE, TEXT( "Server" ));
 224:              }
 225:          }
 226:          
 227:          // Include service pack (if any) and build number.
 228:          // 取得 Service Pack 版本及組建編號
 229:          if( _tcslen(osvi.szCSDVersion) > 0 )
 230:          {
 231:              StringCchCat(pszOS, BUFSIZE, TEXT(" ") );
 232:              StringCchCat(pszOS, BUFSIZE, osvi.szCSDVersion);
 233:          }
 234:          
 235:          TCHAR buf[80];
 236:          
 237:          StringCchPrintf( buf, 80, TEXT(" (build %d)"), osvi.dwBuildNumber);
 238:          StringCchCat(pszOS, BUFSIZE, buf);
 239:          
 240:          // 主版本序號 6 及 6 以上,再檢查是 x64 還是 x86
 241:          if ( osvi.dwMajorVersion >= 6 )
 242:          {
 243:              if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
 244:                  StringCchCat(pszOS, BUFSIZE, TEXT( ", 64-bit" ));
 245:              else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
 246:                  StringCchCat(pszOS, BUFSIZE, TEXT(", 32-bit"));
 247:          }
 248:          
 249:          // 完成檢查,傳回 True
 250:          return TRUE; 
 251:     }
 252:     
 253:     else
 254:     {  
 255:         // 這支程式僅支援 NT 平台且主版本序號大於 4 的 Windows
 256:         printf( "This sample does not support this version of Windows.\n");
 257:         return FALSE;
 258:     }
 259:  }
 260:   
 261:  // 主控台程式的進入點
 262:  int __cdecl _tmain()
 263:  {
 264:      TCHAR szOS[BUFSIZE];
 265:      
 266:      // 呼叫 GetOSDisplayString
 267:      if( GetOSDisplayString( szOS ) )
 268:          // 呼叫成功即列出相關版本資訊
 269:          _tprintf( TEXT("\n%s\n"), szOS );
 270:  }

參考資料:MSDN Getting the System Version


[全文]