KiCad PCB EDA Suite
Loading...
Searching...
No Matches
windows/sysinfo.cpp
Go to the documentation of this file.
1/*
2* This program source code file is part of KiCad, a free EDA CAD application.
3*
4* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5*
6* This program is free software; you can redistribute it and/or
7* modify it under the terms of the GNU General Public License
8* as published by the Free Software Foundation; either version 2
9* of the License, or (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20#include <wbemidl.h>
21#include <cstdio>
22#define _WIN32_DCOM
23#include <comdef.h>
24
25
26#include <stdexcept>
27#include <string>
28#include <vector>
29
30#include <kiplatform/sysinfo.h>
31
32#include <algorithm>
33#include <sstream>
34#include <vector>
35
36#include <wx/string.h>
37#include <wx/msw/registry.h>
38
39#include "d3d9.h"
40#include "dxgi.h"
41
42
43namespace KIPLATFORM
44{
45namespace
46{
47 /*
48 * Helper functions from https://stackoverflow.com/questions/6284524/bstr-to-stdstring-stdwstring-and-vice-versa
49 * Licensed CC BY-SA 3.0
50 */
51 std::string ConvertWCSToMBS( const wchar_t* pstr, long wslen )
52 {
53 int len = ::WideCharToMultiByte( CP_ACP, 0, pstr, wslen, NULL, 0, NULL, NULL );
54
55 std::string dblstr( len, '\0' );
56 len = ::WideCharToMultiByte( CP_ACP, 0 /* no flags */, pstr,
57 wslen /* not necessary NULL-terminated */, &dblstr[0], len, NULL,
58 NULL /* no default char */ );
59
60 return dblstr;
61 }
62
63
64 std::string ConvertBSTRToMBS( BSTR bstr )
65 {
66 int wslen = ::SysStringLen( bstr );
67 return ConvertWCSToMBS( (wchar_t*) bstr, wslen );
68 }
69
70
71 BSTR ConvertMBSToBSTR( const std::string& str )
72 {
73 int wsLen = ::MultiByteToWideChar( CP_ACP, 0 /* no flags */, str.data(), str.length(), NULL,
74 0 );
75
76 BSTR wsData = ::SysAllocStringLen( NULL, wsLen );
77 if( ::MultiByteToWideChar( CP_ACP, 0 /* no flags */,
78 str.data(),
79 str.length(),
80 wsData,
81 wsLen ) == 0 )
82 {
83 // conversion failure
84 ::SysFreeString( wsData );
85 wsData = NULL;
86 }
87
88 return wsData;
89 }
90}
91
92
94{
95 openWmi();
96}
97
98
100{
101 freeWmi();
102}
103
104
106{
107 HRESULT hres;
108
109 // We assume wxwidgets is handling calling of CoInitializeEx and CoInitializeSecurity
110 hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator,
111 (LPVOID*) &m_pLoc );
112
113 if( FAILED( hres ) )
114 {
115 throw std::runtime_error( "Failed to create IWbemLocator object." );
116 return hres;
117 }
118
119 // Connect to the root\cimv2 namespace with
120 // the current user and obtain pointer pSvc
121 // to make IWbemServices calls.
122 hres = m_pLoc->ConnectServer( ConvertMBSToBSTR( "ROOT\\CIMV2" ), // Object path of WMI namespace
123 NULL, // User name. NULL = current user
124 NULL, // User password. NULL = current
125 0, // Locale. NULL indicates current
126 0, // Security flags.
127 0, // Authority (for example, Kerberos)
128 0, // Context object
129 &m_pSvc // pointer to IWbemServices proxy
130 );
131
132 if( FAILED( hres ) )
133 {
134 m_pLoc->Release();
135 throw std::runtime_error( "Could not connect to root\\cimv2." );
136 return hres;
137 }
138
139 hres = CoSetProxyBlanket( m_pSvc, // Indicates the proxy to set
140 RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
141 RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
142 NULL, // Server principal name
143 RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
144 RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
145 NULL, // client identity
146 EOAC_NONE // proxy capabilities
147 );
148
149 if( FAILED( hres ) )
150 {
151 m_pSvc->Release();
152 m_pLoc->Release();
153 throw std::runtime_error( "Could not set proxy blanket." );
154 return hres;
155 }
156
157 return hres;
158}
159
160
162{
163 HRESULT hres = 0;
164
165 if( m_pSvc != nullptr )
166 {
167 hres = m_pSvc->Release();
168 }
169
170 if( m_pLoc != nullptr )
171 {
172 hres = m_pLoc->Release();
173 }
174
175 if( m_pEnumerator != nullptr )
176 {
177 hres = m_pEnumerator->Release();
178 }
179
180 return hres;
181}
182
183
184std::string SYSINFO::improveDriverVersion( const std::string& aManufacturer,
185 const std::string& aVersion )
186{
187 if( aManufacturer.find( "NVIDIA" ) != std::string::npos
188 || aManufacturer.find( "Nvidia" ) != std::string::npos )
189 {
190 std::istringstream versionStream( aVersion );
191 std::string s;
192 std::vector<std::string> versionBits;
193 while( getline( versionStream, s, '.' ) )
194 {
195 versionBits.push_back( s );
196 }
197
198 if( versionBits.size() == 4 )
199 {
200 unsigned int numChars2 = versionBits[2].length();
201 unsigned int numChars3 = versionBits[2].length();
202 if( numChars2 >= 1 && numChars3 >= 2 )
203 {
204 if( numChars3 < 4 )
205 {
206 versionBits[3].insert( 0, ( 4 - versionBits[3].size() ), '0' );
207 numChars3 = 4;
208 }
209 }
210
211 std::string major1 = versionBits[2].substr( numChars2 - 1, numChars2 - 1 );
212 std::string major2 = versionBits[3].substr( 0, 1 );
213 std::string major = major1 + major2;
214 std::string minor = versionBits[3].substr( 2, numChars3 - 1 );
215
216
217 return major + "." + minor;
218 }
219 }
220
221 return aVersion;
222}
223
224
225bool SYSINFO::GetMemoryInfo( MEMORY_INFO& aMemoryInfo )
226{
227 MEMORYSTATUSEX statex;
228
229 statex.dwLength = sizeof( statex );
230
231 if( GlobalMemoryStatusEx( &statex ) != 0 )
232 {
233 aMemoryInfo.Usage = statex.dwMemoryLoad;
234 aMemoryInfo.TotalPhysical = statex.ullTotalPhys;
235 aMemoryInfo.FreePhysical = statex.ullAvailPhys;
236 aMemoryInfo.TotalPaging = statex.ullTotalPageFile;
237 aMemoryInfo.FreePaging = statex.ullAvailPageFile;
238 aMemoryInfo.TotalVirtual = statex.ullTotalVirtual;
239 aMemoryInfo.FreeVirtual = statex.ullAvailVirtual;
240
241 return true;
242 }
243
244 return false;
245}
246
247
248bool SYSINFO::GetCPUInfo( std::vector<CPU_INFO>& aCpuInfos )
249{
250 HRESULT hres;
251 DWORD returned = 0;
252
253 IWbemClassObject* processors[2];
254 hres = m_pSvc->ExecQuery(
255 ConvertMBSToBSTR( "WQL" ), ConvertMBSToBSTR( "SELECT * FROM Win32_Processor" ),
256 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 0, &m_pEnumerator );
257
258 if( SUCCEEDED( hres ) )
259 {
260 hres = m_pEnumerator->Next( WBEM_INFINITE, 2, processors, &returned );
261 if( FAILED( hres ) || returned == 0 )
262 {
263 return false;
264 }
265 }
266
267 VARIANT var;
268 VariantInit( &var );
269
270 std::string chRetValue = "";
271 for( UINT ctrlIndex = 0; ctrlIndex < returned; ctrlIndex++ )
272 {
273 IWbemClassObject* processor = processors[ctrlIndex];
274
275 CPU_INFO cpuInfo;
276 hres = processor->Get( ConvertMBSToBSTR( "Name" ), 0, &var, NULL, NULL );
277 if( SUCCEEDED( hres ) )
278 {
279 variantToString( &var, chRetValue );
280 cpuInfo.Name = chRetValue;
281
282 VariantClear( &var );
283 processor->Get( ConvertMBSToBSTR( "Manufacturer" ), 0, &var, NULL, NULL );
284 variantToString( &var, chRetValue );
285 cpuInfo.Manufacturer = chRetValue;
286
287 VariantClear( &var );
288 processor->Get( ConvertMBSToBSTR( "NumberOfCores" ), 0, &var, NULL, NULL );
289 variantToString( &var, chRetValue );
290 long long cores = atoll( chRetValue.c_str() );
291 cpuInfo.NumberCores = cores;
292
293 VariantClear( &var );
294 processor->Get( ConvertMBSToBSTR( "NumberOfLogicalProcessors" ), 0, &var, NULL, NULL );
295 variantToString( &var, chRetValue );
296 long long logical = atoll( chRetValue.c_str() );
297 cpuInfo.NumberLogical = logical;
298
299
300 aCpuInfos.push_back( cpuInfo );
301 }
302
303 VariantClear( &var );
304 }
305
306
307 return true;
308}
309
310
311bool SYSINFO::getVersionFromDXRegistry( int64_t aAdapterLuid, std::string& aDriverVersion )
312{
313 wxString baseKeyName = "SOFTWARE\\Microsoft\\DirectX";
314 wxRegKey key( wxRegKey::HKLM, baseKeyName );
315 HKEY tmpKey;
316
317 if( key.HasSubkeys() )
318 {
319 wxString adapterGuid;
320 long index = 0;
321 for( bool cont = key.GetFirstKey( adapterGuid, index ); cont;
322 cont = key.GetNextKey( adapterGuid, index ) )
323 {
324 wxString subKeyName = baseKeyName + "\\" + adapterGuid;
325
326 LSTATUS status;
327 status = ::RegOpenKeyEx(
328 (HKEY) HKEY_LOCAL_MACHINE, subKeyName.t_str(), 0, KEY_READ, &tmpKey );
329
330 ULONGLONG adapterLuid;
331 DWORD dwType, dwSize = sizeof(ULONGLONG);
332 status = ::RegQueryValueEx((HKEY)tmpKey, L"AdapterLuid",
333 0,
334 &dwType, (LPBYTE)&adapterLuid, &dwSize);
335
336 if (status != ERROR_SUCCESS)
337 {
338 ::RegCloseKey(tmpKey);
339 continue;
340 }
341
342 //access error, target ended up weirdly the wrong type
343 if ( dwType != REG_QWORD_LITTLE_ENDIAN && dwType != REG_QWORD ) {
344 ::RegCloseKey(tmpKey);
345 continue;
346 }
347
348 if (adapterLuid != aAdapterLuid)
349 {
350 ::RegCloseKey(tmpKey);
351 continue;
352 }
353
354 ULONGLONG driverVersion;
355 status = ::RegQueryValueEx((HKEY)tmpKey, L"DriverVersion",
356 0,
357 &dwType, (LPBYTE)&driverVersion, &dwSize);
358
359 if (status != ERROR_SUCCESS)
360 {
361 ::RegCloseKey(tmpKey);
362 continue;
363 }
364
365 //access error, target ended up weirdly the wrong type
366 if ( dwType != REG_QWORD_LITTLE_ENDIAN && dwType != REG_QWORD ) {
367 ::RegCloseKey(tmpKey);
368 continue;
369 }
370
371 std::stringstream fmt;
372 fmt << ( ( driverVersion >> 48 ) & 0xFFFF ) << "."
373 << ( ( driverVersion >> 32 ) & 0xFFFF ) << "."
374 << std::to_string( ( driverVersion >> 16 ) & 0xFFFF ) << "."
375 << std::to_string( driverVersion & 0xFFFF );
376 aDriverVersion = fmt.str();
377
378 ::RegCloseKey(tmpKey);
379 return true;
380 }
381 }
382
383 return false;
384}
385
386
387bool SYSINFO::gpuFromDirectX( std::vector<GPU_INFO>& aGpuInfos )
388{
389 typedef HRESULT( WINAPI * LPCREATEDXGIFACTORY )( REFIID, void** );
390 LPCREATEDXGIFACTORY pCreateDXGIFactory = NULL;
391 HMODULE hDXGI = NULL;
392
393 hDXGI = LoadLibrary( L"dxgi.dll" );
394 //
395 if( NULL == hDXGI )
396 {
397 return false;
398 }
399
400 IID iid_IDXGIFactory;
401
402 //to avoid having to link dxgi.dll, we also hardcode the guid of the interface
403 IIDFromString( L"{7b7166ec-21c7-44ae-b21a-c9ae321ae369}", &iid_IDXGIFactory );
404
405 IDXGIAdapter* pAdapter = NULL;
406 pCreateDXGIFactory = (LPCREATEDXGIFACTORY) GetProcAddress( hDXGI, "CreateDXGIFactory" );
407 if( pCreateDXGIFactory )
408 {
409 IDXGIFactory* pDXGIFactory;
410 HRESULT hr = pCreateDXGIFactory( iid_IDXGIFactory, (void**) &pDXGIFactory );
411 if( SUCCEEDED( hr ) )
412 {
413 UINT adapter = 0;
414 while( pDXGIFactory->EnumAdapters( adapter, &pAdapter ) != DXGI_ERROR_NOT_FOUND )
415 {
416 DXGI_ADAPTER_DESC desc;
417 hr = pAdapter->GetDesc( &desc );
418 if( SUCCEEDED( hr ) )
419 {
420 // Microsoft Basic Render Driver that will always show up
421 if( desc.VendorId == 5140 && desc.DeviceId == 140 )
422 {
423 adapter++;
424 continue;
425 }
426 GPU_INFO gpuInfo;
427
428 char descriptionBuffer[260];
429 char defaultChar = ' ';
430 WideCharToMultiByte( CP_ACP, 0, desc.Description, -1, descriptionBuffer,
431 sizeof( descriptionBuffer ), &defaultChar, NULL );
432
433 gpuInfo.Name = descriptionBuffer;
434 // Names are generally formatted with Manu<space>Model
435 gpuInfo.Manufacturer = gpuInfo.Name.substr( 0, gpuInfo.Name.find( " " ) );
436 ;
437 gpuInfo.MemorySize = desc.DedicatedVideoMemory;
438
439 int64_t luid = ( ( (int64_t) desc.AdapterLuid.HighPart ) << 32 )
440 | desc.AdapterLuid.LowPart;
441
442 if( getVersionFromDXRegistry( luid, gpuInfo.DriverVersion ) )
443 {
445 }
446
447 aGpuInfos.push_back( gpuInfo );
448 }
449
450 adapter++;
451 }
452
453 pDXGIFactory->Release();
454 }
455 }
456
457 FreeLibrary( hDXGI );
458
459 return true;
460}
461
462
463bool SYSINFO::GetGPUInfo( std::vector<GPU_INFO>& aGpuInfos )
464{
465 if (gpuFromDirectX(aGpuInfos))
466 {
467 return true;
468 }
469
470 return false;
471}
472
473
474void SYSINFO::variantToString( const LPVARIANT aVar, std::string& aReturnString ) const
475{
476 HRESULT hr;
477 char returnBuffer[256];
478
479 switch( aVar->vt )
480 {
481 case VT_BSTR:
482 {
483 aReturnString = ConvertBSTRToMBS( aVar->bstrVal );
484 }
485 break;
486 case VT_BOOL:
487 {
488 if( VARIANT_TRUE == aVar->boolVal )
489 aReturnString = "true";
490 else
491 aReturnString = "false";
492 }
493 break;
494 case VT_I4:
495 {
496 sprintf_s( returnBuffer, sizeof( returnBuffer ) - 1, "%u", aVar->uintVal );
497
498 aReturnString = returnBuffer;
499 }
500 break;
501 case VT_UI1:
502 {
503 sprintf_s( returnBuffer, sizeof( returnBuffer ) - 1, "%u", aVar->uintVal );
504 aReturnString = returnBuffer;
505 }
506 break;
507 case VT_UI4:
508 {
509 sprintf_s( returnBuffer, sizeof( returnBuffer ) - 1, "%u", aVar->uintVal );
510 aReturnString = returnBuffer;
511 }
512 break;
513 case VT_BSTR | VT_ARRAY:
514 {
515 VARIANT* raw;
516 hr = SafeArrayAccessData( aVar->parray, (void**) &raw );
517
518 const _bstr_t bstr( raw[0] );
519 hr = SafeArrayUnaccessData( aVar->parray );
520
521 aReturnString = ConvertBSTRToMBS( bstr );
522 }
523 break;
524 case VT_I4 | VT_ARRAY:
525 {
526 BYTE HUGEP* pBuf;
527 LONG low, high;
528 SafeArrayGetLBound( aVar->parray, 1, &low );
529 SafeArrayGetUBound( aVar->parray, 1, &high );
530
531 hr = SafeArrayAccessData( aVar->parray, (void HUGEP**) &pBuf );
532 hr = SafeArrayUnaccessData( aVar->parray );
533 std::string strTmp;
534 high = std::min( high, (long) MAX_PATH * 2 - 1 );
535 for( LONG i = low; i <= high; ++i )
536 {
537 sprintf_s( returnBuffer, sizeof( returnBuffer ) - 1, "%02X", pBuf[i] );
538 aReturnString += returnBuffer;
539 }
540 }
541 break;
542 default: break;
543 }
544}
545
546} // namespace KIPLATFORM
int index
IWbemLocator * m_pLoc
void variantToString(const LPVARIANT aVar, std::string &aReturnString) const
Converts a win32 LPVARIANT to a string.
std::string improveDriverVersion(const std::string &aManufacturer, const std::string &aVersion)
Attempts to convert the Windows driver version string to the vendor version string if possible.
bool gpuFromDirectX(std::vector< GPU_INFO > &aGpuInfos)
Fetches gpu info from directx and registry WMI unforunately has a uint32 max value issue for reportin...
bool GetCPUInfo(std::vector< CPU_INFO > &aCpuInfos) override
Retrieve CPU info for the system.
IWbemServices * m_pSvc
bool GetGPUInfo(std::vector< GPU_INFO > &aGpuInfos) override
Retrieve GPU info for the system.
bool getVersionFromDXRegistry(int64_t aAdapterLuid, std::string &aDriverVersion)
Extracts the driver version for an dapter from the directx section of the registry.
IEnumWbemClassObject * m_pEnumerator
bool GetMemoryInfo(MEMORY_INFO &aRamInfo) override
Retrieve memory info for the system.
Object to store and handle common variant information.
std::string Name
Definition sysinfo.h:32
std::string DriverVersion
Definition sysinfo.h:34
long long MemorySize
Definition sysinfo.h:33
std::string Manufacturer
Definition sysinfo.h:35