wmiVideoInfo.cpp
Engine/source/platformWin32/videoInfo/wmiVideoInfo.cpp
Classes:
Public Defines
define
Public Variables
CLSID_DxDiagProvider (0xA65B8071, 0x3BFE, 0x4213, 0x9A, 0x5B, 0x49, 0x1D, 0xA4, 0x46, 0x1C, 0xA7)
IID_IDxDiagContainer (0x7D0F462F, 0x4064, 0x4862, 0xBC, 0x7F, 0x93, 0x3E, 0x50, 0x58, 0xC1, 0x0F)
IID_IDxDiagProvider (0x9C6B4CB0, 0x23F8, 0x49CC, 0xA3, 0xED, 0x45, 0xA5, 0x50, 0x00, 0xA6, 0xD2)
Detailed Description
Public Defines
_WIN32_DCOM()
Public Variables
MYGUID CLSID_DxDiagProvider (0xA65B8071, 0x3BFE, 0x4213, 0x9A, 0x5B, 0x49, 0x1D, 0xA4, 0x46, 0x1C, 0xA7)
MYGUID IID_IDxDiagContainer (0x7D0F462F, 0x4064, 0x4862, 0xBC, 0x7F, 0x93, 0x3E, 0x50, 0x58, 0xC1, 0x0F)
MYGUID IID_IDxDiagProvider (0x9C6B4CB0, 0x23F8, 0x49CC, 0xA3, 0xED, 0x45, 0xA5, 0x50, 0x00, 0xA6, 0xD2)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#define _WIN32_DCOM 25 26//#include <comdef.h> 27#include <wbemidl.h> 28//#include <atlconv.h> 29#include <DXGI.h> 30#pragma comment(lib, "comsuppw.lib") 31#pragma comment(lib, "wbemuuid.lib") 32 33#include "platformWin32/videoInfo/wmiVideoInfo.h" 34#include "core/util/safeRelease.h" 35#include "console/console.h" 36 37// http://www.spectranaut.net/sourcecode/WMI.cpp 38 39// Add constructor to GUID. 40struct MYGUID : public GUID 41{ 42 MYGUID( DWORD a, SHORT b, SHORT c, BYTE d, BYTE e, BYTE f, BYTE g, BYTE h, BYTE i, BYTE j, BYTE k ) 43 { 44 Data1 = a; 45 Data2 = b; 46 Data3 = c; 47 Data4[ 0 ] = d; 48 Data4[ 1 ] = e; 49 Data4[ 2 ] = f; 50 Data4[ 3 ] = g; 51 Data4[ 4 ] = h; 52 Data4[ 5 ] = i; 53 Data4[ 6 ] = j; 54 Data4[ 7 ] = k; 55 } 56}; 57 58 59//------------------------------------------------------------------------------ 60// DXDIAG declarations. 61 62struct DXDIAG_INIT_PARAMS 63{ 64 DWORD dwSize; 65 DWORD dwDxDiagHeaderVersion; 66 BOOL bAllowWHQLChecks; 67 LPVOID pReserved; 68}; 69 70struct IDxDiagContainer : public IUnknown 71{ 72 virtual HRESULT STDMETHODCALLTYPE GetNumberOfChildContainers( DWORD* pdwCount ) = 0; 73 virtual HRESULT STDMETHODCALLTYPE EnumChildContainerNames( DWORD dwIndex, LPWSTR pwszContainer, DWORD cchContainer ) = 0; 74 virtual HRESULT STDMETHODCALLTYPE GetChildContainer( LPCWSTR pwszContainer, IDxDiagContainer** ppInstance ) = 0; 75 virtual HRESULT STDMETHODCALLTYPE GetNumberOfProps( DWORD* pdwCount ) = 0; 76 virtual HRESULT STDMETHODCALLTYPE EnumPropNames( DWORD dwIndex, LPWSTR pwszPropName, DWORD cchPropName ) = 0; 77 virtual HRESULT STDMETHODCALLTYPE GetProp( LPCWSTR pwszPropName, VARIANT* pvarProp ) = 0; 78}; 79 80struct IDxDiagProvider : public IUnknown 81{ 82 virtual HRESULT STDMETHODCALLTYPE Initialize( DXDIAG_INIT_PARAMS* pParams ) = 0; 83 virtual HRESULT STDMETHODCALLTYPE GetRootContainer( IDxDiagContainer** ppInstance ) = 0; 84}; 85 86static MYGUID CLSID_DxDiagProvider( 0xA65B8071, 0x3BFE, 0x4213, 0x9A, 0x5B, 0x49, 0x1D, 0xA4, 0x46, 0x1C, 0xA7 ); 87static MYGUID IID_IDxDiagProvider( 0x9C6B4CB0, 0x23F8, 0x49CC, 0xA3, 0xED, 0x45, 0xA5, 0x50, 0x00, 0xA6, 0xD2 ); 88static MYGUID IID_IDxDiagContainer( 0x7D0F462F, 0x4064, 0x4862, 0xBC, 0x7F, 0x93, 0x3E, 0x50, 0x58, 0xC1, 0x0F ); 89 90//------------------------------------------------------------------------------ 91 92WCHAR *WMIVideoInfo::smPVIQueryTypeToWMIString [] = 93{ 94 L"MaxNumberControlled", //PVI_NumDevices 95 L"Description", //PVI_Description 96 L"Name", //PVI_Name 97 L"VideoProcessor", //PVI_ChipSet 98 L"DriverVersion", //PVI_DriverVersion 99 L"AdapterRAM", //PVI_VRAM 100}; 101 102//------------------------------------------------------------------------------ 103 104WMIVideoInfo::WMIVideoInfo() 105 : PlatformVideoInfo(), 106 mLocator( NULL ), 107 mServices( NULL ), 108 mComInitialized( false ), 109 mDXGIModule( NULL ), 110 mDXGIFactory( NULL ), 111 mDxDiagProvider( NULL ) 112{ 113 114} 115 116//------------------------------------------------------------------------------ 117 118WMIVideoInfo::~WMIVideoInfo() 119{ 120 SAFE_RELEASE( mLocator ); 121 SAFE_RELEASE( mServices ); 122 123 if( mDxDiagProvider ) 124 SAFE_RELEASE( mDxDiagProvider ); 125 126 if( mDXGIFactory ) 127 SAFE_RELEASE( mDXGIFactory ); 128 if( mDXGIModule ) 129 FreeLibrary( ( HMODULE ) mDXGIModule ); 130 131 if( mComInitialized ) 132 CoUninitialize(); 133} 134 135//------------------------------------------------------------------------------ 136 137String WMIVideoInfo::_lookUpVendorId(U32 vendorId) 138{ 139 String vendor; 140 switch (vendorId) 141 { 142 case 0x10DE: 143 vendor = "NVIDIA"; 144 break; 145 case 0x1002: 146 vendor = "AMD"; 147 break; 148 case 0x8086: 149 vendor = "INTEL"; 150 break; 151 } 152 return vendor; 153} 154 155//------------------------------------------------------------------------------ 156 157bool WMIVideoInfo::_initialize() 158{ 159 // Init COM 160 HRESULT hr = CoInitialize( NULL ); 161 mComInitialized = SUCCEEDED( hr ); 162 163 if( !mComInitialized ) 164 return false; 165 166 bool success = false; 167 168 success |= _initializeDXGI(); 169 success |= _initializeDxDiag(); 170 success |= _initializeWMI(); 171 172 return success; 173} 174 175bool WMIVideoInfo::_initializeWMI() 176{ 177 //// Set security levels 178 //hr = CoInitializeSecurity( 179 // NULL, 180 // -1, // COM authentication 181 // NULL, // Authentication services 182 // NULL, // Reserved 183 // RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication 184 // RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation 185 // NULL, // Authentication info 186 // EOAC_NONE, // Additional capabilities 187 // NULL // Reserved 188 // ); 189 190 //if( FAILED( hr ) ) 191 //{ 192 // Con::errorf( "WMIVideoInfo: Failed to initialize com security." ); 193 // return false; 194 //} 195 196 // Obtain the locator to WMI 197 HRESULT hr = CoCreateInstance( 198 CLSID_WbemLocator, 199 0, 200 CLSCTX_INPROC_SERVER, 201 IID_IWbemLocator, 202 (void**)&mLocator 203 ); 204 205 if( FAILED( hr ) ) 206 { 207 Con::errorf( "WMIVideoInfo: Failed to create instance of IID_IWbemLocator." ); 208 return false; 209 } 210 211 // Connect to the root\cimv2 namespace with 212 // the current user and obtain pointer pSvc 213 // to make IWbemServices calls. 214 hr = mLocator->ConnectServer( 215 BSTR(L"ROOT\\CIMV2"), // Object path of WMI namespace 216 NULL, // User name. NULL = current user 217 NULL, // User password. NULL = current 218 0, // Locale. NULL indicates current 219 NULL, // Security flags. 220 0, // Authority (e.g. Kerberos) 221 0, // Context object 222 &mServices // pointer to IWbemServices proxy 223 ); 224 225 if( FAILED( hr ) ) 226 { 227 Con::errorf( "WMIVideoInfo: Connect server failed." ); 228 return false; 229 } 230 231 232 // Set security levels on the proxy 233 hr = CoSetProxyBlanket( 234 mServices, // Indicates the proxy to set 235 RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx 236 RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx 237 NULL, // Server principal name 238 RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx 239 RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx 240 NULL, // client identity 241 EOAC_NONE // proxy capabilities 242 ); 243 244 if( FAILED( hr ) ) 245 { 246 Con::errorf( "WMIVideoInfo: CoSetProxyBlanket failed" ); 247 return false; 248 } 249 250 return true; 251} 252 253bool WMIVideoInfo::_initializeDXGI() 254{ 255 // Try using for DXGI 1.1, will only succeed on Windows 7+. 256 mDXGIModule = ( HMODULE ) LoadLibrary( L"dxgi.dll" ); 257 if( mDXGIModule != 0 ) 258 { 259 typedef HRESULT (WINAPI* CreateDXGIFactoryFuncType )( REFIID, void** ); 260 CreateDXGIFactoryFuncType factoryFunction = 261 ( CreateDXGIFactoryFuncType ) GetProcAddress( ( HMODULE ) mDXGIModule, "CreateDXGIFactory1" ); 262 263 if( factoryFunction && factoryFunction( IID_IDXGIFactory1, ( void** ) &mDXGIFactory ) == S_OK ) 264 return true; 265 else 266 { 267 FreeLibrary( ( HMODULE ) mDXGIModule ); 268 mDXGIModule = 0; 269 } 270 } 271 272 return false; 273} 274 275bool WMIVideoInfo::_initializeDxDiag() 276{ 277 if( CoCreateInstance( CLSID_DxDiagProvider, NULL, CLSCTX_INPROC_SERVER, IID_IDxDiagProvider, ( void** ) &mDxDiagProvider ) == S_OK ) 278 { 279 DXDIAG_INIT_PARAMS params; 280 dMemset( ¶ms, 0, sizeof( DXDIAG_INIT_PARAMS ) ); 281 282 params.dwSize = sizeof( DXDIAG_INIT_PARAMS ); 283 params.dwDxDiagHeaderVersion = 111; 284 params.bAllowWHQLChecks = false; 285 286 HRESULT result = mDxDiagProvider->Initialize( ¶ms ); 287 if( result != S_OK ) 288 { 289 Con::errorf( "WMIVideoInfo: DxDiag initialization failed (%i)", result ); 290 SAFE_RELEASE( mDxDiagProvider ); 291 return false; 292 } 293 else 294 { 295 Con::printf( "WMIVideoInfo: DxDiag initialized" ); 296 return true; 297 } 298 } 299 300 return false; 301} 302 303//------------------------------------------------------------------------------ 304// http://msdn2.microsoft.com/en-us/library/aa394512.aspx 305// 306// The Win32_VideoController WMI class represents the capabilities and management capacity of the 307// video controller on a computer system running Windows. 308// 309// Starting with Windows Vista, hardware that is not compatible with Windows Display Driver Model (WDDM) 310// returns inaccurate property values for instances of this class. 311// 312// Windows Server 2003, Windows XP, Windows 2000, and Windows NT 4.0: This class is supported. 313//------------------------------------------------------------------------------ 314 315bool WMIVideoInfo::_queryProperty( const PVIQueryType queryType, const U32 adapterId, String *outValue ) 316{ 317 if( _queryPropertyDXGI( queryType, adapterId, outValue ) ) 318 return true; 319 else if( _queryPropertyDxDiag( queryType, adapterId, outValue ) ) 320 return true; 321 else 322 return _queryPropertyWMI( queryType, adapterId, outValue ); 323} 324 325bool WMIVideoInfo::_queryPropertyDxDiag( const PVIQueryType queryType, const U32 adapterId, String *outValue ) 326{ 327 if( mDxDiagProvider != 0 ) 328 { 329 IDxDiagContainer* rootContainer = 0; 330 IDxDiagContainer* displayDevicesContainer = 0; 331 IDxDiagContainer* deviceContainer = 0; 332 333 // Special case to deal with PVI_NumAdapters 334 if(queryType == PVI_NumAdapters) 335 { 336 DWORD count = 0; 337 String value; 338 339 if( mDxDiagProvider->GetRootContainer( &rootContainer ) == S_OK 340 && rootContainer->GetChildContainer( L"DxDiag_DisplayDevices", &displayDevicesContainer ) == S_OK 341 && displayDevicesContainer->GetNumberOfChildContainers( &count ) == S_OK ) 342 { 343 value = String::ToString("%d", count); 344 } 345 346 if( rootContainer ) 347 SAFE_RELEASE( rootContainer ); 348 if( displayDevicesContainer ) 349 SAFE_RELEASE( displayDevicesContainer ); 350 351 *outValue = value; 352 return true; 353 } 354 355 WCHAR adapterIdString[ 2 ]; 356 adapterIdString[ 0 ] = L'0' + adapterId; 357 adapterIdString[ 1 ] = L'\0'; 358 359 String value; 360 if( mDxDiagProvider->GetRootContainer( &rootContainer ) == S_OK 361 && rootContainer->GetChildContainer( L"DxDiag_DisplayDevices", &displayDevicesContainer ) == S_OK 362 && displayDevicesContainer->GetChildContainer( adapterIdString, &deviceContainer ) == S_OK ) 363 { 364 const WCHAR* propertyName = 0; 365 366 switch( queryType ) 367 { 368 case PVI_Description: 369 propertyName = L"szDescription"; 370 break; 371 372 case PVI_Name: 373 propertyName = L"szDeviceName"; 374 break; 375 376 case PVI_ChipSet: 377 propertyName = L"szChipType"; 378 break; 379 380 case PVI_DriverVersion: 381 propertyName = L"szDriverVersion"; 382 break; 383 384 // Don't get VRAM via DxDiag as that won't tell us about the actual amount of dedicated 385 // video memory but rather some dedicated+shared RAM value. 386 } 387 388 if( propertyName ) 389 { 390 VARIANT val; 391 if( deviceContainer->GetProp( propertyName, &val ) == S_OK ) 392 switch( val.vt ) 393 { 394 case VT_BSTR: 395 value = String( val.bstrVal ); 396 break; 397 398 default: 399 AssertWarn( false, avar( "WMIVideoInfo: property type '%i' not implemented", val.vt ) ); 400 } 401 } 402 } 403 404 if( rootContainer ) 405 SAFE_RELEASE( rootContainer ); 406 if( displayDevicesContainer ) 407 SAFE_RELEASE( displayDevicesContainer ); 408 if( deviceContainer ) 409 SAFE_RELEASE( deviceContainer ); 410 411 if( value.isNotEmpty() ) 412 { 413 // Try to get the DxDiag data into some canonical form. Otherwise, we 414 // won't be giving the card profiler much opportunity for matching up 415 // its data with profile scripts. 416 417 switch( queryType ) 418 { 419 case PVI_ChipSet: 420 if( value.compare( "ATI", 3, String::NoCase ) == 0 ) 421 value = "ATI Technologies Inc."; 422 else if( value.compare( "NVIDIA", 6, String::NoCase ) == 0 ) 423 value = "NVIDIA"; 424 else if( value.compare( "INTEL", 5, String::NoCase ) == 0 ) 425 value = "INTEL"; 426 else if( value.compare( "MATROX", 6, String::NoCase ) == 0 ) 427 value = "MATROX"; 428 break; 429 430 case PVI_Description: 431 if( value.compare( "ATI ", 4, String::NoCase ) == 0 ) 432 { 433 value = value.substr( 4, value.length() - 4 ); 434 if( value.compare( " Series", 7, String::NoCase | String::Right ) == 0 ) 435 value = value.substr( 0, value.length() - 7 ); 436 } 437 else if( value.compare( "NVIDIA ", 7, String::NoCase ) == 0 ) 438 value = value.substr( 7, value.length() - 7 ); 439 else if( value.compare( "INTEL ", 6, String::NoCase ) == 0 ) 440 value = value.substr( 6, value.length() - 6 ); 441 else if( value.compare( "MATROX ", 7, String::NoCase ) == 0 ) 442 value = value.substr( 7, value.length() - 7 ); 443 break; 444 } 445 446 *outValue = value; 447 return true; 448 } 449 } 450 return false; 451} 452 453bool WMIVideoInfo::_queryPropertyDXGI( const PVIQueryType queryType, const U32 adapterId, String *outValue ) 454{ 455 456 if( mDXGIFactory ) 457 { 458 // Special case to deal with PVI_NumAdapters 459 if (queryType == PVI_NumAdapters) 460 { 461 U32 count = 0; 462 IDXGIAdapter1 *adapter; 463 while (mDXGIFactory->EnumAdapters1(count, &adapter) != DXGI_ERROR_NOT_FOUND) 464 { 465 ++count; 466 adapter->Release(); 467 } 468 469 String value = String::ToString("%d", count); 470 *outValue = value; 471 return true; 472 } 473 474 IDXGIAdapter1* adapter; 475 if( mDXGIFactory->EnumAdapters1( adapterId, &adapter ) != S_OK ) 476 return false; 477 478 DXGI_ADAPTER_DESC1 desc; 479 if( adapter->GetDesc1( &desc ) != S_OK ) 480 { 481 adapter->Release(); 482 return false; 483 } 484 485 String value; 486 switch( queryType ) 487 { 488 case PVI_Description: 489 value = String( desc.Description ); 490 break; 491 492 case PVI_Name: 493 value = String( avar( "%i", desc.DeviceId ) ); 494 break; 495 496 case PVI_VRAM: 497 value = String( avar( "%i", desc.DedicatedVideoMemory / 1048576 ) ); 498 break; 499 case PVI_ChipSet: 500 value = _lookUpVendorId(desc.VendorId); 501 break; 502 //TODO PVI_DriverVersion 503 } 504 505 adapter->Release(); 506 *outValue = value; 507 return true; 508 } 509 510 return false; 511} 512 513bool WMIVideoInfo::_queryPropertyWMI( const PVIQueryType queryType, const U32 adapterId, String *outValue ) 514{ 515 if( mServices == NULL ) 516 return false; 517 518 BSTR bstrWQL = SysAllocString(L"WQL"); 519 BSTR bstrPath = SysAllocString(L"select * from Win32_VideoController"); 520 IEnumWbemClassObject* enumerator; 521 522 // Use the IWbemServices pointer to make requests of WMI 523 HRESULT hr = mServices->ExecQuery(bstrWQL, bstrPath, WBEM_FLAG_FORWARD_ONLY, NULL, &enumerator); 524 525 if( FAILED( hr ) ) 526 return false; 527 528 IWbemClassObject *adapter = NULL; 529 ULONG uReturned; 530 531 // Get the appropriate adapter. 532 for ( S32 i = 0; i <= adapterId; i++ ) 533 { 534 hr = enumerator->Next(WBEM_INFINITE, 1, &adapter, &uReturned ); 535 536 if ( FAILED( hr ) || uReturned == 0 ) 537 { 538 enumerator->Release(); 539 return false; 540 } 541 } 542 543 // Now get the property 544 VARIANT v; 545 hr = adapter->Get( smPVIQueryTypeToWMIString[queryType], 0, &v, NULL, NULL ); 546 547 bool result = SUCCEEDED( hr ); 548 549 if ( result ) 550 { 551 switch( v.vt ) 552 { 553 case VT_I4: 554 { 555 LONG longVal = v.lVal; 556 557 if( queryType == PVI_VRAM ) 558 { 559 longVal = longVal >> 20; // Convert to megabytes 560 561 // While this value is reported as a signed integer, it is possible 562 // for video cards to have 2GB or more. In those cases the signed 563 // bit is set and will give us a negative number. Treating this 564 // as unsigned will allows us to handle video cards with up to 565 // 4GB of memory. After that we'll need a new solution from Microsoft. 566 *outValue = String::ToString( (U32)longVal ); 567 } 568 else 569 { 570 *outValue = String::ToString( (S32)longVal ); 571 } 572 break; 573 } 574 575 case VT_UI4: 576 { 577 *outValue = String::ToString( (U32)v.ulVal ); 578 break; 579 } 580 581 case VT_BSTR: 582 { 583 *outValue = String( v.bstrVal ); 584 break; 585 } 586 case VT_LPSTR: 587 case VT_LPWSTR: 588 break; 589 } 590 591 592 } 593 594 // Cleanup 595 adapter->Release(); 596 enumerator->Release(); 597 598 return result; 599} 600