summary refs log tree commit diff stats
path: root/plugins/sysinfo/sysinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/sysinfo/sysinfo.cpp')
-rw-r--r--plugins/sysinfo/sysinfo.cpp415
1 files changed, 415 insertions, 0 deletions
diff --git a/plugins/sysinfo/sysinfo.cpp b/plugins/sysinfo/sysinfo.cpp
new file mode 100644
index 00000000..d15118fe
--- /dev/null
+++ b/plugins/sysinfo/sysinfo.cpp
@@ -0,0 +1,415 @@
+/* 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 <comutil.h>
+#include <wbemidl.h>
+
+#include "xchat-plugin.h"
+
+static xchat_plugin *ph;   /* plugin handle */
+static char name[] = "WinSys";
+static char desc[] = "Display info about your hardware and OS";
+static char version[] = "1.1";
+static int firstRun;
+static char *wmiOs;
+static char *wmiCpu;
+static char *wmiVga;
+
+static int
+getCpuArch (void)
+{
+	OSVERSIONINFOEX osvi;
+	SYSTEM_INFO si;
+
+	osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
+	GetVersionEx ((LPOSVERSIONINFOW) &osvi);
+
+	GetSystemInfo (&si);
+
+	if (si.wProcessorArchitecture == 9)
+	{
+		return 64;
+	}
+	else
+	{
+		return 86;
+	}
+}
+
+#if 0
+/* use WMI instead, wProcessorArchitecture displays current binary arch instead of OS arch anyway */
+static char *
+getOsName (void)
+{
+	static char winver[32];
+	double mhz;
+	OSVERSIONINFOEX osvi;
+	SYSTEM_INFO si;
+
+	osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
+	GetVersionEx ((LPOSVERSIONINFOW) &osvi);
+
+	GetSystemInfo (&si);
+
+	strcpy (winver, "Windows ");
+
+	switch (osvi.dwMajorVersion)
+	{
+		case 5:
+			switch (osvi.dwMinorVersion)
+			{
+				case 1:
+					strcat (winver, "XP");
+					break;
+				case 2:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcat (winver, "XP x64 Edition");
+					}
+					else
+					{
+						if (GetSystemMetrics(SM_SERVERR2) == 0)
+						{
+							strcat (winver, "Server 2003");
+						}
+						else
+						{
+							strcat (winver, "Server 2003 R2");
+						}
+					}
+					break;
+			}
+			break;
+		case 6:
+			switch (osvi.dwMinorVersion)
+			{
+				case 0:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcat (winver, "Vista");
+					}
+					else
+					{
+						strcat (winver, "Server 2008");
+					}
+					break;
+				case 1:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcat (winver, "7");
+					}
+					else
+					{
+						strcat (winver, "Server 2008 R2");
+					}
+					break;
+				case 2:
+					if (osvi.wProductType == VER_NT_WORKSTATION)
+					{
+						strcat (winver, "8");
+					}
+					else
+					{
+						strcat (winver, "8 Server");
+					}
+					break;
+			}
+			break;
+	}
+
+	if (si.wProcessorArchitecture == 9)
+	{
+		strcat (winver, " (x64)");
+	}
+	else
+	{
+		strcat (winver, " (x86)");
+	}
+
+	return winver;
+}
+
+/* x86-only, SDK-only, use WMI instead */
+static char *
+getCpuName (void)
+{
+	// Get extended ids.
+	unsigned int nExIds;
+	unsigned int i;
+	int CPUInfo[4] = {-1};
+	static char CPUBrandString[128];
+
+	__cpuid (CPUInfo, 0x80000000);
+	nExIds = CPUInfo[0];
+
+	/* Get the information associated with each extended ID. */
+	for (i=0x80000000; i <= nExIds; ++i)
+	{
+		__cpuid (CPUInfo, i);
+
+		if (i == 0x80000002)
+		{
+			memcpy (CPUBrandString, CPUInfo, sizeof (CPUInfo));
+		}
+		else if (i == 0x80000003)
+		{
+			memcpy( CPUBrandString + 16, CPUInfo, sizeof (CPUInfo));
+		}
+		else if (i == 0x80000004)
+		{
+			memcpy (CPUBrandString + 32, CPUInfo, sizeof (CPUInfo));
+		}
+	}
+
+	return CPUBrandString;
+}
+#endif
+
+static char *
+getCpuMhz (void)
+{
+	HKEY hKey;
+	int result;
+	int data;
+	int dataSize;
+	double cpuspeed;
+	static char buffer[16];
+	const char *cpuspeedstr;
+
+	if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, TEXT("Hardware\\Description\\System\\CentralProcessor\\0"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+	{
+		dataSize = sizeof (data);
+		result = RegQueryValueEx (hKey, TEXT("~MHz"), 0, 0, (LPBYTE)&data, (LPDWORD)&dataSize);
+		RegCloseKey (hKey);
+		if (result == ERROR_SUCCESS)
+		{
+			cpuspeed = ( data > 1000 ) ? data / 1000 : data;
+			cpuspeedstr = ( data > 1000 ) ? "GHz" : "MHz";
+			sprintf (buffer, "%.2f %s", cpuspeed, cpuspeedstr);
+		}
+	}
+
+	return buffer;
+}
+
+static char *
+getMemoryInfo (void)
+{
+	static char buffer[32];
+	MEMORYSTATUSEX meminfo;
+
+	meminfo.dwLength = sizeof (meminfo);
+	GlobalMemoryStatusEx (&meminfo);
+
+	sprintf (buffer, "%I64d MB Total (%I64d MB Free)", meminfo.ullTotalPhys / 1024 / 1024, meminfo.ullAvailPhys / 1024 / 1024);
+
+	return buffer;
+}
+
+static char *
+getWmiInfo (int mode)
+{
+	/* for more details about this wonderful API, see 
+	http://msdn.microsoft.com/en-us/site/aa394138
+	http://msdn.microsoft.com/en-us/site/aa390423
+	http://msdn.microsoft.com/en-us/library/windows/desktop/aa394138%28v=vs.85%29.aspx
+	http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/d6420012-e432-4964-8506-6f6b65e5a451
+	*/
+
+	char *buffer = (char *) malloc (128);
+	HRESULT hres;
+	HRESULT hr;
+	IWbemLocator *pLoc = NULL;
+	IWbemServices *pSvc = NULL;
+	IEnumWbemClassObject *pEnumerator = NULL;
+	IWbemClassObject *pclsObj;
+	ULONG uReturn = 0;
+
+	hres =  CoInitializeEx (0, COINIT_APARTMENTTHREADED | COINIT_SPEED_OVER_MEMORY);
+
+	if (FAILED (hres))
+	{
+		strcpy (buffer, "Error Code 0");
+		return buffer;
+	}
+
+	hres =  CoInitializeSecurity (NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
+
+	/* mysteriously failing after the first execution, but only when used as a plugin, skip it */
+	/*if (FAILED (hres))
+	{
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 1");
+		return buffer;
+	}*/
+
+	hres = CoCreateInstance (CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
+
+	if (FAILED (hres))
+	{
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 2");
+		return buffer;
+	}
+
+	hres = pLoc->ConnectServer (_bstr_t (L"root\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
+
+	if (FAILED (hres))
+	{
+		pLoc->Release ();
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 3");
+		return buffer;
+	}
+
+	hres = CoSetProxyBlanket (pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
+
+	if (FAILED (hres))
+	{
+		pSvc->Release ();
+		pLoc->Release ();
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 4");
+		return buffer;
+	}
+
+	switch (mode)
+	{
+		case 0:
+			hres = pSvc->ExecQuery (_bstr_t ("WQL"), _bstr_t ("SELECT * FROM Win32_OperatingSystem"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+			break;
+		case 1:
+			hres = pSvc->ExecQuery (_bstr_t ("WQL"), _bstr_t ("SELECT * FROM Win32_Processor"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+			break;
+		case 2:
+			hres = pSvc->ExecQuery (_bstr_t ("WQL"), _bstr_t ("SELECT * FROM Win32_VideoController"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+			break;
+
+	}
+
+	if (FAILED (hres))
+	{
+		pSvc->Release ();
+		pLoc->Release ();
+		CoUninitialize ();
+		strcpy (buffer, "Error Code 5");
+		return buffer;
+	}
+
+	while (pEnumerator)
+	{
+		hr = pEnumerator->Next (WBEM_INFINITE, 1, &pclsObj, &uReturn);
+		if (0 == uReturn)
+		{
+			break;
+		}
+		VARIANT vtProp;
+		switch (mode)
+		{
+			case 0:
+				hr = pclsObj->Get (L"Caption", 0, &vtProp, 0, 0);
+				break;
+			case 1:
+				hr = pclsObj->Get (L"Name", 0, &vtProp, 0, 0);
+				break;
+			case 2:
+				hr = pclsObj->Get (L"Name", 0, &vtProp, 0, 0);
+				break;
+		}
+		WideCharToMultiByte (CP_ACP, 0, vtProp.bstrVal, -1, buffer, SysStringLen (vtProp.bstrVal)+1, NULL, NULL);
+		VariantClear (&vtProp);
+    }
+
+	pSvc->Release ();
+	pLoc->Release ();
+	pEnumerator->Release ();
+	pclsObj->Release ();
+	CoUninitialize ();
+	return buffer;
+}
+
+static int
+printInfo (char *word[], char *word_eol[], void *user_data)
+{
+	/* query WMI info only at the first time WinSys is called, then cache it to save time */
+	if (firstRun)
+	{
+		xchat_printf (ph, "%s first execution, querying and caching WMI info...\n", name);
+		wmiOs = getWmiInfo (0);
+		wmiCpu = getWmiInfo (1);
+		wmiVga = getWmiInfo (2);
+		firstRun = 0;
+	}
+	if (xchat_list_int (ph, NULL, "type") >= 2)
+	{
+		/* uptime will work correctly for up to 50 days, should be enough */
+		xchat_commandf (ph, "ME ** WinSys ** Client: HexChat %s (x%d) ** OS: %s ** CPU: %s (%s) ** RAM: %s ** VGA: %s ** Uptime: %.2f Hours **",
+			xchat_get_info (ph, "version"),
+			getCpuArch (),
+			wmiOs,
+			wmiCpu,
+			getCpuMhz (),
+			getMemoryInfo (),
+			wmiVga, (float) GetTickCount() / 1000 / 60 / 60);
+	}
+	else
+	{
+		xchat_printf (ph, " * Client:  HexChat %s (x%d)\n", xchat_get_info (ph, "version"), getCpuArch ());
+		xchat_printf (ph, " * OS:      %s\n", wmiOs);
+		xchat_printf (ph, " * CPU:     %s (%s)\n", wmiCpu, getCpuMhz ());
+		xchat_printf (ph, " * RAM:     %s\n", getMemoryInfo ());
+		xchat_printf (ph, " * VGA:     %s\n", wmiVga);
+		xchat_printf (ph, " * Uptime:  %.2f Hours\n", (float) GetTickCount() / 1000 / 60 / 60);
+	}
+
+	return XCHAT_EAT_XCHAT;
+}
+
+int
+xchat_plugin_init (xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
+{
+	ph = plugin_handle;
+
+	*plugin_name = name;
+	*plugin_desc = desc;
+	*plugin_version = version;
+
+	firstRun = 1;
+
+	xchat_hook_command (ph, "WINSYS", XCHAT_PRI_NORM, printInfo, NULL, NULL);
+	xchat_command (ph, "MENU -ietc\\system.png ADD \"Window/Display System Info\" \"WINSYS\"");
+
+	xchat_printf (ph, "%s plugin loaded\n", name);
+
+	return 1;       /* return 1 for success */
+}
+
+
+int
+xchat_plugin_deinit (void)
+{
+	xchat_command (ph, "MENU DEL \"Window/Display System Info\"");
+	xchat_printf (ph, "%s plugin unloaded\n", name);
+	return 1;
+}