星期三, 九月 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

2 意見:

Jim 提到...

請問這支程式跟 systeminfo | @find "OS" 取得的資訊差異?

賴榮樞 提到...

Hello Jim,

這支程式所取得的資訊量無法與 SystemInfo 指令相比;這支程式只能取得版本序號、產品類型等資訊而已。