wmiVideoInfo.cpp 18 KB

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