wmiVideoInfo.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  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 GetNumberOfChildContainers( 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. // Special case to deal with PVI_NumAdapters
  311. if(queryType == PVI_NumAdapters)
  312. {
  313. DWORD count = 0;
  314. String value;
  315. if( mDxDiagProvider->GetRootContainer( &rootContainer ) == S_OK
  316. && rootContainer->GetChildContainer( L"DxDiag_DisplayDevices", &displayDevicesContainer ) == S_OK
  317. && displayDevicesContainer->GetNumberOfChildContainers( &count ) == S_OK )
  318. {
  319. value = String::ToString("%d", count);
  320. }
  321. if( rootContainer )
  322. SAFE_RELEASE( rootContainer );
  323. if( displayDevicesContainer )
  324. SAFE_RELEASE( displayDevicesContainer );
  325. *outValue = value;
  326. return true;
  327. }
  328. WCHAR adapterIdString[ 2 ];
  329. adapterIdString[ 0 ] = L'0' + adapterId;
  330. adapterIdString[ 1 ] = L'\0';
  331. String value;
  332. if( mDxDiagProvider->GetRootContainer( &rootContainer ) == S_OK
  333. && rootContainer->GetChildContainer( L"DxDiag_DisplayDevices", &displayDevicesContainer ) == S_OK
  334. && displayDevicesContainer->GetChildContainer( adapterIdString, &deviceContainer ) == S_OK )
  335. {
  336. const WCHAR* propertyName = 0;
  337. switch( queryType )
  338. {
  339. case PVI_Description:
  340. propertyName = L"szDescription";
  341. break;
  342. case PVI_Name:
  343. propertyName = L"szDeviceName";
  344. break;
  345. case PVI_ChipSet:
  346. propertyName = L"szChipType";
  347. break;
  348. case PVI_DriverVersion:
  349. propertyName = L"szDriverVersion";
  350. break;
  351. // Don't get VRAM via DxDiag as that won't tell us about the actual amount of dedicated
  352. // video memory but rather some dedicated+shared RAM value.
  353. }
  354. if( propertyName )
  355. {
  356. VARIANT val;
  357. if( deviceContainer->GetProp( propertyName, &val ) == S_OK )
  358. switch( val.vt )
  359. {
  360. case VT_BSTR:
  361. value = String( val.bstrVal );
  362. break;
  363. default:
  364. AssertWarn( false, avar( "WMIVideoInfo: property type '%i' not implemented", val.vt ) );
  365. }
  366. }
  367. }
  368. if( rootContainer )
  369. SAFE_RELEASE( rootContainer );
  370. if( displayDevicesContainer )
  371. SAFE_RELEASE( displayDevicesContainer );
  372. if( deviceContainer )
  373. SAFE_RELEASE( deviceContainer );
  374. if( value.isNotEmpty() )
  375. {
  376. // Try to get the DxDiag data into some canonical form. Otherwise, we
  377. // won't be giving the card profiler much opportunity for matching up
  378. // its data with profile scripts.
  379. switch( queryType )
  380. {
  381. case PVI_ChipSet:
  382. if( value.compare( "ATI", 3, String::NoCase ) == 0 )
  383. value = "ATI Technologies Inc.";
  384. else if( value.compare( "NVIDIA", 6, String::NoCase ) == 0 )
  385. value = "NVIDIA";
  386. else if( value.compare( "INTEL", 5, String::NoCase ) == 0 )
  387. value = "INTEL";
  388. else if( value.compare( "MATROX", 6, String::NoCase ) == 0 )
  389. value = "MATROX";
  390. break;
  391. case PVI_Description:
  392. if( value.compare( "ATI ", 4, String::NoCase ) == 0 )
  393. {
  394. value = value.substr( 4, value.length() - 4 );
  395. if( value.compare( " Series", 7, String::NoCase | String::Right ) == 0 )
  396. value = value.substr( 0, value.length() - 7 );
  397. }
  398. else if( value.compare( "NVIDIA ", 7, String::NoCase ) == 0 )
  399. value = value.substr( 7, value.length() - 7 );
  400. else if( value.compare( "INTEL ", 6, String::NoCase ) == 0 )
  401. value = value.substr( 6, value.length() - 6 );
  402. else if( value.compare( "MATROX ", 7, String::NoCase ) == 0 )
  403. value = value.substr( 7, value.length() - 7 );
  404. break;
  405. }
  406. *outValue = value;
  407. return true;
  408. }
  409. }
  410. return false;
  411. }
  412. bool WMIVideoInfo::_queryPropertyDXGI( const PVIQueryType queryType, const U32 adapterId, String *outValue )
  413. {
  414. #if 0
  415. if( mDXGIFactory )
  416. {
  417. IDXGIAdapter* adapter;
  418. if( mDXGIFactory->EnumAdapters( adapterId, &adapter ) != S_OK )
  419. return false;
  420. DXGI_ADAPTER_DESC desc;
  421. if( adapter->GetDesc( &desc ) != S_OK )
  422. {
  423. adapter->Release();
  424. return false;
  425. }
  426. String value;
  427. switch( queryType )
  428. {
  429. case PVI_Description:
  430. value = String( desc.Description );
  431. break;
  432. case PVI_Name:
  433. value = String( avar( "%i", desc.DeviceId ) );
  434. break;
  435. case PVI_VRAM:
  436. value = String( avar( "%i", desc.DedicatedVideoMemory / 1048576 ) );
  437. break;
  438. //RDTODO
  439. }
  440. adapter->Release();
  441. *outValue = value;
  442. return true;
  443. }
  444. #endif
  445. return false;
  446. }
  447. bool WMIVideoInfo::_queryPropertyWMI( const PVIQueryType queryType, const U32 adapterId, String *outValue )
  448. {
  449. if( mServices == NULL )
  450. return false;
  451. BSTR bstrWQL = SysAllocString(L"WQL");
  452. BSTR bstrPath = SysAllocString(L"select * from Win32_VideoController");
  453. IEnumWbemClassObject* enumerator;
  454. // Use the IWbemServices pointer to make requests of WMI
  455. HRESULT hr = mServices->ExecQuery(bstrWQL, bstrPath, WBEM_FLAG_FORWARD_ONLY, NULL, &enumerator);
  456. if( FAILED( hr ) )
  457. return false;
  458. IWbemClassObject *adapter = NULL;
  459. ULONG uReturned;
  460. // Get the appropriate adapter.
  461. for ( S32 i = 0; i <= adapterId; i++ )
  462. {
  463. hr = enumerator->Next(WBEM_INFINITE, 1, &adapter, &uReturned );
  464. if ( FAILED( hr ) || uReturned == 0 )
  465. {
  466. enumerator->Release();
  467. return false;
  468. }
  469. }
  470. // Now get the property
  471. VARIANT v;
  472. hr = adapter->Get( smPVIQueryTypeToWMIString[queryType], 0, &v, NULL, NULL );
  473. bool result = SUCCEEDED( hr );
  474. if ( result )
  475. {
  476. switch( v.vt )
  477. {
  478. case VT_I4:
  479. {
  480. LONG longVal = v.lVal;
  481. if( queryType == PVI_VRAM )
  482. {
  483. longVal = longVal >> 20; // Convert to megabytes
  484. // While this value is reported as a signed integer, it is possible
  485. // for video cards to have 2GB or more. In those cases the signed
  486. // bit is set and will give us a negative number. Treating this
  487. // as unsigned will allows us to handle video cards with up to
  488. // 4GB of memory. After that we'll need a new solution from Microsoft.
  489. *outValue = String::ToString( (U32)longVal );
  490. }
  491. else
  492. {
  493. *outValue = String::ToString( (S32)longVal );
  494. }
  495. break;
  496. }
  497. case VT_UI4:
  498. {
  499. *outValue = String::ToString( (U32)v.ulVal );
  500. break;
  501. }
  502. case VT_BSTR:
  503. {
  504. *outValue = String( v.bstrVal );
  505. break;
  506. }
  507. case VT_LPSTR:
  508. case VT_LPWSTR:
  509. break;
  510. }
  511. }
  512. // Cleanup
  513. adapter->Release();
  514. enumerator->Release();
  515. return result;
  516. }