diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/common.vcxproj | 2 | ||||
-rw-r--r-- | src/common/common.vcxproj.filters | 12 | ||||
-rw-r--r-- | src/common/sysinfo/sysinfo.h | 13 | ||||
-rw-r--r-- | src/common/sysinfo/win32/backend.c | 478 | ||||
-rw-r--r-- | src/common/util.c | 154 |
5 files changed, 522 insertions, 137 deletions
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 5c7f2715..1d1fc570 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -36,6 +36,7 @@ <ClInclude Include="server.h" /> <ClInclude Include="servlist.h" /> <ClInclude Include="ssl.h" /> + <ClInclude Include="sysinfo\sysinfo.h" /> <ClInclude Include="text.h" /> <ClInclude Include="$(HexChatLib)textenums.h" /> <ClInclude Include="$(HexChatLib)textevents.h" /> @@ -68,6 +69,7 @@ <ClCompile Include="server.c" /> <ClCompile Include="servlist.c" /> <ClCompile Include="ssl.c" /> + <ClCompile Include="sysinfo\win32\backend.c" /> <ClCompile Include="text.c" /> <ClCompile Include="tree.c" /> <ClCompile Include="url.c" /> diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 79e64cb4..db696eb9 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -9,6 +9,12 @@ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> </Filter> + <Filter Include="Source Files\sysinfo"> + <UniqueIdentifier>{d5a3d281-8400-4663-b60d-036ade5fbff7}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\sysinfo\win32"> + <UniqueIdentifier>{a6d80da7-bc0a-4f1f-a156-c8cdafb7831d}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClInclude Include="cfgfiles.h"> @@ -110,6 +116,9 @@ <ClInclude Include="plugin-identd.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="sysinfo\sysinfo.h"> + <Filter>Source Files\sysinfo</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="cfgfiles.c"> @@ -187,6 +196,9 @@ <ClCompile Include="plugin-identd.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="sysinfo\win32\backend.c"> + <Filter>Source Files\sysinfo\win32</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="..\..\win32\config.h.tt" /> diff --git a/src/common/sysinfo/sysinfo.h b/src/common/sysinfo/sysinfo.h new file mode 100644 index 00000000..d63bf9d8 --- /dev/null +++ b/src/common/sysinfo/sysinfo.h @@ -0,0 +1,13 @@ +#ifndef HEXCHAT_SYSINFO_H +#define HEXCHAT_SYSINFO_H + +#include <glib.h> + +int sysinfo_get_cpu_arch (void); +int sysinfo_get_build_arch (void); +char *sysinfo_get_cpu (void); +char *sysinfo_get_os (void); +void sysinfo_get_hdd_info (guint64 *hdd_capacity_out, guint64 *hdd_free_space_out); +char *sysinfo_get_gpu (void); + +#endif diff --git a/src/common/sysinfo/win32/backend.c b/src/common/sysinfo/win32/backend.c new file mode 100644 index 00000000..c4e686a7 --- /dev/null +++ b/src/common/sysinfo/win32/backend.c @@ -0,0 +1,478 @@ +/* HexChat + * Copyright (c) 2011-2012 Berke Viktor. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <windows.h> +#include <wbemidl.h> + +#include "../sysinfo.h" + +/* Cache */ +static int cpu_arch = 0; +static int build_arch = 0; +static char *os_name = NULL; +static char *cpu_info = NULL; +static char *vga_name = NULL; + +typedef enum +{ + QUERY_WMI_OS, + QUERY_WMI_CPU, + QUERY_WMI_VGA, + QUERY_WMI_HDD, +} QueryWmiType; + +char *query_wmi (QueryWmiType mode); +char *read_os_name (IWbemClassObject *object); +char *read_cpu_info (IWbemClassObject *object); +char *read_vga_name (IWbemClassObject *object); + +guint64 hdd_capacity; +guint64 hdd_free_space; +char *read_hdd_info (IWbemClassObject *object); + +char *bstr_to_utf8 (BSTR bstr); +guint64 variant_to_uint64 (VARIANT *variant); + +char * +sysinfo_get_cpu (void) +{ + if (cpu_info == NULL) + cpu_info = query_wmi (QUERY_WMI_CPU); + + return g_strdup (cpu_info); +} + +char * +sysinfo_get_os (void) +{ + if (os_name == NULL) + os_name = query_wmi (QUERY_WMI_OS); + + return g_strdup_printf ("%s (x%d)", os_name, sysinfo_get_cpu_arch ()); +} + +int +sysinfo_get_cpu_arch (void) +{ + SYSTEM_INFO si; + + if (cpu_arch != 0) + { + return cpu_arch; + } + + GetNativeSystemInfo (&si); + + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + { + return cpu_arch = 64; + } + else + { + return cpu_arch = 86; + } +} + +int +sysinfo_get_build_arch (void) +{ + SYSTEM_INFO si; + + if (build_arch != 0) + { + return build_arch; + } + + GetSystemInfo (&si); + + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) + { + return build_arch = 64; + } + else + { + return build_arch = 86; + } +} + +char * +sysinfo_get_gpu (void) +{ + if (vga_name == NULL) + vga_name = query_wmi (QUERY_WMI_VGA); + + return g_strdup (vga_name); +} + +void +sysinfo_get_hdd_info (guint64 *hdd_capacity_out, guint64 *hdd_free_space_out) +{ + char *hdd_info; + + /* HDD information is always loaded dynamically since it includes the current amount of free space */ + *hdd_capacity_out = hdd_capacity = 0; + *hdd_free_space_out = hdd_free_space = 0; + + hdd_info = query_wmi (QUERY_WMI_HDD); + if (hdd_info == NULL) + { + return; + } + + *hdd_capacity_out = hdd_capacity; + *hdd_free_space_out = hdd_free_space; +} + +/* https://msdn.microsoft.com/en-us/library/aa390423 */ +static char *query_wmi (QueryWmiType type) +{ + GString *result = NULL; + HRESULT hr; + + IWbemLocator *locator = NULL; + BSTR namespaceName = NULL; + BSTR queryLanguageName = NULL; + BSTR query = NULL; + IWbemServices *namespace = NULL; + IUnknown *namespaceUnknown = NULL; + IEnumWbemClassObject *enumerator = NULL; + int i; + gboolean atleast_one_appended = FALSE; + + hr = CoCreateInstance (&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *) &locator); + if (FAILED (hr)) + { + goto exit; + } + + namespaceName = SysAllocString (L"root\\CIMV2"); + + hr = locator->lpVtbl->ConnectServer (locator, namespaceName, NULL, NULL, NULL, 0, NULL, NULL, &namespace); + if (FAILED (hr)) + { + goto release_locator; + } + + hr = namespace->lpVtbl->QueryInterface (namespace, &IID_IUnknown, &namespaceUnknown); + if (FAILED (hr)) + { + goto release_namespace; + } + + hr = CoSetProxyBlanket (namespaceUnknown, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); + if (FAILED (hr)) + { + goto release_namespaceUnknown; + } + + queryLanguageName = SysAllocString (L"WQL"); + + switch (type) + { + case QUERY_WMI_OS: + query = SysAllocString (L"SELECT Caption FROM Win32_OperatingSystem"); + break; + case QUERY_WMI_CPU: + query = SysAllocString (L"SELECT Name, MaxClockSpeed FROM Win32_Processor"); + break; + case QUERY_WMI_VGA: + query = SysAllocString (L"SELECT Name FROM Win32_VideoController"); + break; + case QUERY_WMI_HDD: + query = SysAllocString (L"SELECT Name, Capacity, FreeSpace FROM Win32_Volume"); + break; + default: + goto release_queryLanguageName; + } + + hr = namespace->lpVtbl->ExecQuery (namespace, queryLanguageName, query, WBEM_FLAG_FORWARD_ONLY, NULL, &enumerator); + if (FAILED (hr)) + { + goto release_query; + } + + result = g_string_new (""); + + for (i = 0;; i++) + { + ULONG numReturned = 0; + IWbemClassObject *object; + char *line; + + hr = enumerator->lpVtbl->Next (enumerator, WBEM_INFINITE, 1, &object, &numReturned); + if (FAILED (hr) || numReturned == 0) + { + break; + } + + switch (type) + { + case QUERY_WMI_OS: + line = read_os_name (object); + break; + + case QUERY_WMI_CPU: + line = read_cpu_info (object); + break; + + case QUERY_WMI_VGA: + line = read_vga_name (object); + break; + + case QUERY_WMI_HDD: + line = read_hdd_info (object); + break; + + default: + break; + } + + object->lpVtbl->Release (object); + + if (line != NULL) + { + if (atleast_one_appended) + { + g_string_append (result, ", "); + } + + g_string_append (result, line); + + g_free (line); + + atleast_one_appended = TRUE; + } + } + + enumerator->lpVtbl->Release (enumerator); + +release_query: + SysFreeString (query); + +release_queryLanguageName: + SysFreeString (queryLanguageName); + +release_namespaceUnknown: + namespaceUnknown->lpVtbl->Release (namespaceUnknown); + +release_namespace: + namespace->lpVtbl->Release (namespace); + +release_locator: + locator->lpVtbl->Release (locator); + SysFreeString (namespaceName); + +exit: + if (result == NULL) + { + return NULL; + } + + return g_string_free (result, FALSE); +} + +static char *read_os_name (IWbemClassObject *object) +{ + HRESULT hr; + VARIANT caption_variant; + char *caption_utf8; + + hr = object->lpVtbl->Get (object, L"Caption", 0, &caption_variant, NULL, NULL); + if (FAILED (hr)) + { + return NULL; + } + + caption_utf8 = bstr_to_utf8 (caption_variant.bstrVal); + + VariantClear(&caption_variant); + + if (caption_utf8 == NULL) + { + return NULL; + } + + g_strchomp (caption_utf8); + + return caption_utf8; +} + +static char *read_cpu_info (IWbemClassObject *object) +{ + HRESULT hr; + VARIANT name_variant; + char *name_utf8; + VARIANT max_clock_speed_variant; + guint cpu_freq_mhz; + char *result; + + hr = object->lpVtbl->Get (object, L"Name", 0, &name_variant, NULL, NULL); + if (FAILED (hr)) + { + return NULL; + } + + name_utf8 = bstr_to_utf8 (name_variant.bstrVal); + + VariantClear (&name_variant); + + if (name_utf8 == NULL) + { + return NULL; + } + + hr = object->lpVtbl->Get (object, L"MaxClockSpeed", 0, &max_clock_speed_variant, NULL, NULL); + if (FAILED (hr)) + { + g_free (name_utf8); + + return NULL; + } + + cpu_freq_mhz = max_clock_speed_variant.uintVal; + + VariantClear (&max_clock_speed_variant); + + if (cpu_freq_mhz > 1000) + { + result = g_strdup_printf ("%s (%.2fGHz)", name_utf8, cpu_freq_mhz / 1000.f); + } + else + { + result = g_strdup_printf ("%s (%" G_GUINT32_FORMAT "MHz)", name_utf8, cpu_freq_mhz); + } + + g_free (name_utf8); + + return result; +} + +static char *read_vga_name (IWbemClassObject *object) +{ + HRESULT hr; + VARIANT name_variant; + char *name_utf8; + + hr = object->lpVtbl->Get (object, L"Name", 0, &name_variant, NULL, NULL); + if (FAILED (hr)) + { + return NULL; + } + + name_utf8 = bstr_to_utf8 (name_variant.bstrVal); + + VariantClear (&name_variant); + + if (name_utf8 == NULL) + { + return NULL; + } + + return g_strchomp (name_utf8); +} + +static char *read_hdd_info (IWbemClassObject *object) +{ + HRESULT hr; + VARIANT name_variant; + BSTR name_bstr; + gsize name_len; + VARIANT capacity_variant; + guint64 capacity; + VARIANT free_space_variant; + guint64 free_space; + + hr = object->lpVtbl->Get (object, L"Name", 0, &name_variant, NULL, NULL); + if (FAILED (hr)) + { + return NULL; + } + + name_bstr = name_variant.bstrVal; + name_len = SysStringLen (name_variant.bstrVal); + + if (name_len >= 4 && name_bstr[0] == L'\\' && name_bstr[1] == L'\\' && name_bstr[2] == L'?' && name_bstr[3] == L'\\') + { + // This is not a named volume. Skip it. + VariantClear (&name_variant); + + return NULL; + } + + VariantClear (&name_variant); + + hr = object->lpVtbl->Get (object, L"Capacity", 0, &capacity_variant, NULL, NULL); + if (FAILED (hr)) + { + return NULL; + } + + capacity = variant_to_uint64 (&capacity_variant); + + VariantClear (&capacity_variant); + + if (capacity == 0) + { + return NULL; + } + + hr = object->lpVtbl->Get (object, L"FreeSpace", 0, &free_space_variant, NULL, NULL); + if (FAILED (hr)) + { + return NULL; + } + + free_space = variant_to_uint64 (&free_space_variant); + + VariantClear (&free_space_variant); + + if (free_space == 0) + { + return NULL; + } + + hdd_capacity += capacity; + hdd_free_space += free_space; + + return NULL; +} + +static char *bstr_to_utf8 (BSTR bstr) +{ + return g_utf16_to_utf8 (bstr, SysStringLen (bstr), NULL, NULL, NULL); +} + +static guint64 variant_to_uint64 (VARIANT *variant) +{ + switch (V_VT (variant)) + { + case VT_UI8: + return variant->ullVal; + + case VT_BSTR: + return wcstoull (variant->bstrVal, NULL, 10); + + default: + return 0; + } +} diff --git a/src/common/util.c b/src/common/util.c index 316ac9d4..9ec8ef16 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -32,7 +32,7 @@ #ifdef WIN32 #include <sys/timeb.h> #include <io.h> -#include <VersionHelpers.h> +#include "./sysinfo/sysinfo.h" #else #include <unistd.h> #include <pwd.h> @@ -458,158 +458,38 @@ get_cpu_info (double *mhz, int *cpus) #ifdef WIN32 -static int -get_mhz (void) -{ - HKEY hKey; - int result, data, dataSize; - - if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Hardware\\Description\\System\\" - "CentralProcessor\\0", 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) - { - dataSize = sizeof (data); - result = RegQueryValueEx (hKey, "~MHz", 0, 0, (LPBYTE)&data, &dataSize); - RegCloseKey (hKey); - if (result == ERROR_SUCCESS) - return data; - } - return 0; /* fails on Win9x */ -} - int get_cpu_arch (void) { - SYSTEM_INFO si; - - GetSystemInfo (&si); - - if (si.wProcessorArchitecture == 9) - { - return 64; - } - else - { - return 86; - } + return sysinfo_get_build_arch (); } char * get_sys_str (int with_cpu) { - static char verbuf[64]; - static char winver[20]; - double mhz; + static char *without_cpu_buffer = NULL; + static char *with_cpu_buffer = NULL; - /* Broken since major bumped to 10, should start to work eventually. - * No, IsWindowsVersionOrGreater (10, 0, 0) doesn't work either. - * TODO: replace with IsWindows10OrGreater() once added to the SDK. - */ - if (IsWindowsVersionOrGreater (6, 4, 0)) - { - if (IsWindowsServer ()) - { - strcpy (winver, "Server 10"); - } - else - { - strcpy (winver, "10"); - } - } - else if (IsWindows8Point1OrGreater ()) - { - if (IsWindowsServer ()) - { - strcpy (winver, "Server 2012 R2"); - } - else - { - strcpy (winver, "8.1"); - } - } - else if (IsWindows8OrGreater ()) - { - if (IsWindowsServer ()) - { - strcpy (winver, "Server 2012"); - } - else - { - strcpy (winver, "8"); - } - } - else if (IsWindows7SP1OrGreater ()) + if (with_cpu == 0) { - if (IsWindowsServer ()) + if (without_cpu_buffer == NULL) { - strcpy (winver, "Server 2008 R2 SP1"); + without_cpu_buffer = sysinfo_get_os (); } - else - { - strcpy (winver, "7 SP1"); - } - } - else if (IsWindows7OrGreater ()) - { - if (IsWindowsServer ()) - { - strcpy (winver, "Server 2008 R2"); - } - else - { - strcpy (winver, "7"); - } - } - else if (IsWindowsVistaSP2OrGreater ()) - { - if (IsWindowsServer ()) - { - strcpy (winver, "Server 2008 SP2"); - } - else - { - strcpy (winver, "Vista SP2"); - } - } - else if (IsWindowsVistaSP1OrGreater ()) - { - if (IsWindowsServer ()) - { - strcpy (winver, "Server 2008 SP1"); - } - else - { - strcpy (winver, "Vista SP1"); - } - } - else if (IsWindowsVistaOrGreater ()) - { - if (IsWindowsServer ()) - { - strcpy (winver, "Server 2008"); - } - else - { - strcpy (winver, "Vista"); - } - } - else - { - strcpy (winver, "Unknown"); - } - mhz = get_mhz (); - if (mhz && with_cpu) - { - double cpuspeed = ( mhz > 1000 ) ? mhz / 1000 : mhz; - const char *cpuspeedstr = ( mhz > 1000 ) ? "GHz" : "MHz"; - sprintf (verbuf, "Windows %s [%.2f%s]", winver, cpuspeed, cpuspeedstr); + return without_cpu_buffer; } - else + + if (with_cpu_buffer == NULL) { - sprintf (verbuf, "Windows %s", winver); + char *os = sysinfo_get_os (); + char *cpu = sysinfo_get_cpu (); + with_cpu_buffer = g_strconcat (os, " [", cpu, "]", NULL); + g_free (cpu); + g_free (os); } - - return verbuf; + + return with_cpu_buffer; } #else |