Torque3D Documentation / _generateds / wmiVideoInfo.cpp

wmiVideoInfo.cpp

Engine/source/platformWin32/videoInfo/wmiVideoInfo.cpp

More...

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( &params, 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( &params );
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