2 * Copyright 2014 Austin English
3 * Copyright 2023 Hans Leidekker for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(systeminfo
);
42 const WCHAR
*property
; /* hardcoded value if class is NULL */
43 void (*callback
)( IWbemServices
*services
, enum format_flags flags
, UINT32
); /* called if class and property are NULL */
44 enum format_flags flags
;
47 static void output_processors( IWbemServices
*services
, enum format_flags flags
, UINT32 width
)
49 IEnumWbemClassObject
*iter
;
50 IWbemClassObject
*obj
;
51 DWORD i
, num_cpus
= 0, count
;
56 str
= SysAllocString( L
"Win32_Processor" );
57 hr
= IWbemServices_CreateInstanceEnum( services
, str
, 0, NULL
, &iter
);
59 if (FAILED( hr
)) return;
61 while (IEnumWbemClassObject_Skip( iter
, WBEM_INFINITE
, 1 ) == S_OK
) num_cpus
++;
63 fwprintf( stdout
, L
"Processor(s):%*s %u Processor(s) Installed.\n", width
- wcslen(L
"Processor(s)"), L
" ", num_cpus
);
64 IEnumWbemClassObject_Reset( iter
);
66 for (i
= 0; i
< num_cpus
; i
++)
68 hr
= IEnumWbemClassObject_Next( iter
, WBEM_INFINITE
, 1, &obj
, &count
);
69 if (FAILED( hr
)) goto done
;
71 hr
= IWbemClassObject_Get( obj
, L
"Caption", 0, &value
, NULL
, NULL
);
74 IWbemClassObject_Release( obj
);
77 fwprintf( stdout
, L
"%*s[%02u]: %s", width
+ 2, L
" ", i
+ 1, V_BSTR(&value
) );
78 VariantClear( &value
);
80 hr
= IWbemClassObject_Get( obj
, L
"Manufacturer", 0, &value
, NULL
, NULL
);
83 IWbemClassObject_Release( obj
);
86 fwprintf( stdout
, L
" %s", V_BSTR(&value
) );
87 VariantClear( &value
);
89 hr
= IWbemClassObject_Get( obj
, L
"MaxClockSpeed", 0, &value
, NULL
, NULL
);
92 IWbemClassObject_Release( obj
);
95 fwprintf( stdout
, L
" ~%u Mhz\n", V_I4(&value
) );
97 IWbemClassObject_Release( obj
);
101 IEnumWbemClassObject_Release( iter
);
104 static void output_hotfixes( IWbemServices
*services
, enum format_flags flags
, UINT32 width
)
106 IEnumWbemClassObject
*iter
;
107 IWbemClassObject
*obj
;
108 DWORD i
, num_hotfixes
= 0, count
;
113 str
= SysAllocString( L
"Win32_QuickFixEngineering" );
114 hr
= IWbemServices_CreateInstanceEnum( services
, str
, 0, NULL
, &iter
);
115 SysFreeString( str
);
116 if (FAILED( hr
)) return;
118 while (IEnumWbemClassObject_Skip( iter
, WBEM_INFINITE
, 1 ) == S_OK
) num_hotfixes
++;
120 fwprintf( stdout
, L
"Hotfix(es):%*s %u Hotfix(es) Installed.\n", width
- wcslen(L
"Hotfix(es)"), L
" ", num_hotfixes
);
121 IEnumWbemClassObject_Reset( iter
);
123 for (i
= 0; i
< num_hotfixes
; i
++)
125 hr
= IEnumWbemClassObject_Next( iter
, WBEM_INFINITE
, 1, &obj
, &count
);
126 if (FAILED( hr
)) goto done
;
128 hr
= IWbemClassObject_Get( obj
, L
"Caption", 0, &value
, NULL
, NULL
);
131 IWbemClassObject_Release( obj
);
134 fwprintf( stdout
, L
"%*s[%02u]: %s\n", width
+ 2, L
" ", i
+ 1, V_BSTR(&value
) );
135 VariantClear( &value
);
137 IWbemClassObject_Release( obj
);
141 IEnumWbemClassObject_Release( iter
);
144 static void output_nics( IWbemServices
*services
, enum format_flags flags
, UINT32 width
)
146 IEnumWbemClassObject
*iter
;
147 IWbemClassObject
*obj
;
148 DWORD i
, num_nics
= 0, count
;
155 str
= SysAllocString( L
"Win32_NetworkAdapterConfiguration" );
156 hr
= IWbemServices_CreateInstanceEnum( services
, str
, 0, NULL
, &iter
);
157 SysFreeString( str
);
158 if (FAILED( hr
)) return;
160 while (IEnumWbemClassObject_Skip( iter
, WBEM_INFINITE
, 1 ) == S_OK
) num_nics
++;
162 fwprintf( stdout
, L
"Network Card(s):%*s %u NICs(s) Installed.\n", width
- wcslen(L
"Network Card(s)"), L
" ", num_nics
);
163 IEnumWbemClassObject_Reset( iter
);
165 for (i
= 0; i
< num_nics
; i
++)
167 hr
= IEnumWbemClassObject_Next( iter
, WBEM_INFINITE
, 1, &obj
, &count
);
168 if (FAILED( hr
)) goto done
;
170 hr
= IWbemClassObject_Get( obj
, L
"Description", 0, &value
, NULL
, NULL
);
173 IWbemClassObject_Release( obj
);
176 fwprintf( stdout
, L
"%*s[%02u]: %s\n", width
+ 2, L
" ", i
+ 1, V_BSTR(&value
) );
177 VariantClear( &value
);
179 /* FIXME: Connection Name, DHCP Server */
181 hr
= IWbemClassObject_Get( obj
, L
"DHCPEnabled", 0, &value
, NULL
, NULL
);
184 IWbemClassObject_Release( obj
);
187 fwprintf( stdout
, L
"%*s DHCP Enabled: %s\n", width
+ 2, L
" ", V_BOOL(&value
) ? L
"Yes" : L
"No" );
189 hr
= IWbemClassObject_Get( obj
, L
"IPAddress", 0, &value
, NULL
, NULL
);
192 IWbemClassObject_Release( obj
);
195 if (V_VT( &value
) == (VT_BSTR
| VT_ARRAY
))
197 sa
= V_ARRAY( &value
);
198 SafeArrayGetUBound( sa
, 1, &bound
);
201 fwprintf( stdout
, L
"%*s IP Addresse(es)\n", width
+ 2, L
" " );
202 for (j
= 0; j
<= bound
; j
++)
204 SafeArrayGetElement( sa
, &j
, &str
);
205 fwprintf( stdout
, L
"%*s [%02u]: %s\n", width
+ 2, L
" ", j
+ 1, str
);
206 SysFreeString( str
);
210 VariantClear( &value
);
211 IWbemClassObject_Release( obj
);
215 IEnumWbemClassObject_Release( iter
);
218 static void output_timezone( IWbemServices
*services
, enum format_flags flags
, UINT32 width
)
220 WCHAR name
[64], timezone
[256] = {};
221 DWORD count
= sizeof(name
);
222 HKEY key_current
= 0, key_timezones
= 0, key_name
= 0;
224 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE
, L
"System\\CurrentControlSet\\Control\\TimeZoneInformation", 0,
225 KEY_READ
, &key_current
)) goto done
;
226 if (RegQueryValueExW( key_current
, L
"TimeZoneKeyName", NULL
, NULL
, (BYTE
*)name
, &count
)) goto done
;
227 if (RegOpenKeyExW( HKEY_LOCAL_MACHINE
, L
"Software\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones", 0,
228 KEY_READ
, &key_timezones
)) goto done
;
229 if (RegOpenKeyExW( key_timezones
, name
, 0, KEY_READ
, &key_name
)) goto done
;
230 count
= sizeof(timezone
);
231 RegQueryValueExW( key_name
, L
"Display", NULL
, NULL
, (BYTE
*)timezone
, &count
);
234 fwprintf( stdout
, L
"Time Zone:%*s %s\n", width
- wcslen(L
"Time Zone"), L
" ", timezone
);
235 RegCloseKey( key_name
);
236 RegCloseKey( key_timezones
);
237 RegCloseKey( key_current
);
240 static const struct sysinfo sysinfo_map
[] =
242 { L
"Host Name", L
"Win32_ComputerSystem", L
"Name" },
243 { L
"OS Name", L
"Win32_OperatingSystem", L
"Caption" },
244 { L
"OS Version", L
"Win32_OperatingSystem", L
"Version" }, /* FIXME build number */
245 { L
"OS Manufacturer", L
"Win32_OperatingSystem", L
"Manufacturer" },
246 { L
"OS Configuration", NULL
, L
"Standalone Workstation" },
247 { L
"OS Build Type", L
"Win32_OperatingSystem", L
"BuildType" },
248 { L
"Registered Owner", L
"Win32_OperatingSystem", L
"RegisteredUser" },
249 { L
"Registered Organization", L
"Win32_OperatingSystem", L
"Organization" },
250 { L
"Product ID", L
"Win32_OperatingSystem", L
"SerialNumber" },
251 { L
"Original Install Date", L
"Win32_OperatingSystem", L
"InstallDate", NULL
, FORMAT_DATE
},
252 { L
"System Boot Time", L
"Win32_OperatingSystem", L
"LastBootUpTime", NULL
, FORMAT_DATE
},
253 { L
"System Manufacturer", L
"Win32_ComputerSystem", L
"Manufacturer" },
254 { L
"System Model", L
"Win32_ComputerSystem", L
"Model" },
255 { L
"System Type", L
"Win32_ComputerSystem", L
"SystemType" },
256 { L
"Processor(s)", NULL
, NULL
, output_processors
},
257 { L
"BIOS Version", L
"Win32_BIOS", L
"SMBIOSBIOSVersion" },
258 { L
"Windows Directory", L
"Win32_OperatingSystem", L
"WindowsDirectory" },
259 { L
"System Directory", L
"Win32_OperatingSystem", L
"SystemDirectory" },
260 { L
"Boot Device", L
"Win32_OperatingSystem", L
"BootDevice" },
261 { L
"System Locale", L
"Win32_OperatingSystem", L
"Locale", NULL
, FORMAT_LOCALE
},
262 { L
"Input Locale", L
"Win32_OperatingSystem", L
"Locale", NULL
, FORMAT_LOCALE
}, /* FIXME */
263 { L
"Time Zone", NULL
, NULL
, output_timezone
},
264 { L
"Total Physical Memory", L
"Win32_OperatingSystem", L
"TotalVisibleMemorySize", NULL
, FORMAT_SIZE
},
265 { L
"Available Physical Memory", L
"Win32_OperatingSystem", L
"FreePhysicalMemory", NULL
, FORMAT_SIZE
},
266 { L
"Virtual Memory: Max Size", L
"Win32_OperatingSystem", L
"TotalVirtualMemorySize", NULL
, FORMAT_SIZE
},
267 { L
"Virtual Memory: Available", L
"Win32_OperatingSystem", L
"FreeVirtualMemory", NULL
, FORMAT_SIZE
},
268 /* FIXME Virtual Memory: In Use */
269 { L
"Page File Location(s)", L
"Win32_PageFileUsage", L
"Name" },
270 { L
"Domain", L
"Win32_ComputerSystem", L
"Domain" },
271 /* FIXME Logon Server */
272 { L
"Hotfix(s)", NULL
, NULL
, output_hotfixes
},
273 { L
"Network Card(s)", NULL
, NULL
, output_nics
},
274 /* FIXME Hyper-V Requirements */
277 static void output_item( IWbemServices
*services
, const struct sysinfo
*info
, UINT32 width
)
280 IWbemClassObject
*obj
= NULL
;
287 fwprintf( stdout
, L
"%s:%*s %s\n", info
->item
, width
- wcslen(info
->item
), L
" ", info
->property
);
289 info
->callback( services
, info
->flags
, width
);
293 if (!(str
= SysAllocString( info
->class ))) return;
294 hr
= IWbemServices_GetObject( services
, str
, 0, NULL
, &obj
, NULL
);
295 SysFreeString( str
);
296 if (FAILED( hr
)) return;
298 hr
= IWbemClassObject_Get( obj
, info
->property
, 0, &value
, NULL
, NULL
);
301 IWbemClassObject_Release( obj
);
310 WCHAR date
[32] = {}, time
[32] = {};
313 memset( &st
, 0, sizeof(st
) );
314 swscanf( V_BSTR(&value
), L
"%04u%02u%02u%02u%02u%02u",
315 &st
.wYear
, &st
.wMonth
, &st
.wDay
, &st
.wHour
, &st
.wMinute
, &st
.wSecond
);
316 GetDateFormatW( LOCALE_SYSTEM_DEFAULT
, 0, &st
, NULL
, date
, ARRAY_SIZE(date
) );
317 GetTimeFormatW( LOCALE_SYSTEM_DEFAULT
, 0, &st
, NULL
, time
, ARRAY_SIZE(time
) );
318 fwprintf( stdout
, L
"%s:%*s %s, %s\n", info
->item
, width
- wcslen(info
->item
), L
" ", date
, time
);
324 WCHAR name
[32] = {}, displayname
[LOCALE_NAME_MAX_LENGTH
] = {};
326 swscanf( V_BSTR(&value
), L
"%x", &lcid
);
327 LCIDToLocaleName( lcid
, name
, ARRAY_SIZE(name
), 0 );
328 GetLocaleInfoW( lcid
, LOCALE_SENGLISHDISPLAYNAME
, displayname
, ARRAY_SIZE(displayname
) );
329 fwprintf( stdout
, L
"%s:%*s %s;%s\n", info
->item
, width
- wcslen(info
->item
), L
" ", name
, displayname
);
335 swscanf( V_BSTR(&value
), L
"%I64u", &size
);
336 fwprintf( stdout
, L
"%s:%*s %I64u MB\n", info
->item
, width
- wcslen(info
->item
), L
" ", size
/ 1024 );
340 fwprintf( stdout
, L
"%s:%*s %s\n", info
->item
, width
- wcslen(info
->item
), L
" ", V_BSTR(&value
) );
343 VariantClear( &value
);
346 static void output_sysinfo( void )
348 IWbemLocator
*locator
;
349 IWbemServices
*services
= NULL
;
350 UINT32 i
, len
, width
= 0;
354 CoInitialize( NULL
);
355 CoInitializeSecurity( NULL
, -1, NULL
, NULL
, RPC_C_AUTHN_LEVEL_DEFAULT
, RPC_C_IMP_LEVEL_IMPERSONATE
, NULL
, 0, NULL
);
357 hr
= CoCreateInstance( &CLSID_WbemLocator
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IWbemLocator
, (void **)&locator
);
358 if (hr
!= S_OK
) return;
360 if (!(path
= SysAllocString( L
"ROOT\\CIMV2" ))) goto done
;
361 hr
= IWbemLocator_ConnectServer( locator
, path
, NULL
, NULL
, NULL
, 0, NULL
, NULL
, &services
);
362 SysFreeString( path
);
363 if (hr
!= S_OK
) goto done
;
365 for (i
= 0; i
< ARRAY_SIZE(sysinfo_map
); i
++) if ((len
= wcslen( sysinfo_map
[i
].item
)) > width
) width
= len
;
368 for (i
= 0; i
< ARRAY_SIZE(sysinfo_map
); i
++) output_item( services
, &sysinfo_map
[i
], width
);
371 if (services
) IWbemServices_Release( services
);
372 IWbemLocator_Release( locator
);
376 int __cdecl
wmain( int argc
, WCHAR
*argv
[] )
382 for (i
= 0; i
< argc
; i
++) FIXME( " %s", wine_dbgstr_w(argv
[i
]) );