/*
Miranda Crash Dumper Plugin
Copyright (C) 2008 - 2012 Boris Krasnovskiy All Rights Reserved
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "stdafx.h"
static HINSTANCE hKernel = GetModuleHandleA("kernel32.dll");
int GetTZOffset(void)
{
TIME_ZONE_INFORMATION tzInfo = {};
uint32_t type = GetTimeZoneInformation(&tzInfo);
int offset = 0;
switch (type) {
case TIME_ZONE_ID_DAYLIGHT:
offset = -(tzInfo.Bias + tzInfo.DaylightBias);
break;
case TIME_ZONE_ID_STANDARD:
offset = -(tzInfo.Bias + tzInfo.StandardBias);
break;
case TIME_ZONE_ID_UNKNOWN:
offset = -tzInfo.Bias;
break;
}
return offset;
}
CMStringW GetISO8061Time(SYSTEMTIME *stLocal)
{
SYSTEMTIME loctime;
if (stLocal == nullptr) {
stLocal = &loctime;
GetLocalTime(stLocal);
}
CMStringW ret;
if (g_plugin.bClassicDates) {
wchar_t buf[100];
GetDateFormatW(LOCALE_CUSTOM_DEFAULT, DATE_LONGDATE, stLocal, 0, buf, _countof(buf));
ret.AppendFormat(L"%s ", buf);
GetTimeFormatW(LOCALE_CUSTOM_DEFAULT, 0, stLocal, 0, buf, _countof(buf));
ret.Append(buf);
}
else {
int offset = GetTZOffset();
// Build a string showing the date and time.
ret.Format(L"%d-%02d-%02d %02d:%02d:%02d%+03d%02d",
stLocal->wYear, stLocal->wMonth, stLocal->wDay,
stLocal->wHour, stLocal->wMinute, stLocal->wSecond,
offset / 60, offset % 60);
}
return ret;
}
CMStringW GetLastWriteTime(FILETIME *ftime)
{
FILETIME ftLocal;
SYSTEMTIME stLocal;
// Convert the last-write time to local time.
FileTimeToLocalFileTime(ftime, &ftLocal);
FileTimeToSystemTime(&ftLocal, &stLocal);
return GetISO8061Time(&stLocal);
}
CMStringW GetLastWriteTime(LPCTSTR fileName)
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind = FindFirstFile(fileName, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE)
return L"";
FindClose(hFind);
return GetLastWriteTime(&FindFileData.ftLastWriteTime);
}
const PLUGININFOEX* GetMirInfo(HMODULE hModule)
{
CMPluginBase &pPlugin = GetPluginByInstance(hModule);
return (pPlugin.getInst() == hModule) ? &pPlugin.getInfo() : nullptr;
}
void GetInternetExplorerVersion(CMStringW &buffer)
{
HKEY hKey;
DWORD size;
wchar_t ieVersion[1024] = {};
wchar_t ieBuild[512] = {};
wchar_t iVer[64] = {};
if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Internet Explorer", 0, KEY_QUERY_VALUE, &hKey)) {
size = _countof(ieBuild);
if (RegQueryValueEx(hKey, L"Build", nullptr, nullptr, (LPBYTE)ieBuild, &size) != ERROR_SUCCESS)
ieBuild[0] = 0;
size = _countof(ieVersion);
if (RegQueryValueEx(hKey, L"Version", nullptr, nullptr, (LPBYTE)ieVersion, &size) != ERROR_SUCCESS)
ieVersion[0] = 0;
size = _countof(iVer);
if (RegQueryValueEx(hKey, L"IVer", nullptr, nullptr, (LPBYTE)iVer, &size) != ERROR_SUCCESS)
iVer[0] = 0;
RegCloseKey(hKey);
}
buffer.Append(L"Internet Explorer: ");
if (ieVersion[0] == 0) {
if (iVer[0] == 0)
buffer.Append(L"");
else if (mir_wstrcmp(iVer, L"100") == 0)
buffer.Append(L"1.0");
else if (mir_wstrcmp(iVer, L"101") == 0)
buffer.Append(L"NT");
else if (mir_wstrcmp(iVer, L"102") == 0)
buffer.Append(L"2.0");
else if (mir_wstrcmp(iVer, L"103") == 0)
buffer.Append(L"3.0");
}
else buffer.Append(ieVersion);
if (ieBuild[0] != 0)
buffer.AppendFormat(L" (build %s)", ieBuild);
}
void TrimMultiSpaces(wchar_t *str)
{
wchar_t *src = str, *dest = str;
bool trimst = false;
for (;;) {
if (*src == ' ') {
if (!trimst) {
trimst = true;
*dest++ = *src;
}
}
else {
trimst = false;
*dest++ = *src;
}
if (*src++ == 0) break;
}
}
void GetProcessorString(CMStringW &buffer)
{
wchar_t cpuIdent[512] = {};
wchar_t cpuName[512] = {};
HKEY hKey;
if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Hardware\\Description\\System\\CentralProcessor\\0", 0, KEY_QUERY_VALUE, &hKey)) {
DWORD size = _countof(cpuName);
if (RegQueryValueEx(hKey, L"ProcessorNameString", nullptr, nullptr, (LPBYTE)cpuName, &size) != ERROR_SUCCESS)
mir_wstrcpy(cpuName, L"Unknown");
size = _countof(cpuIdent);
if (RegQueryValueEx(hKey, L"Identifier", nullptr, nullptr, (LPBYTE)cpuIdent, &size) != ERROR_SUCCESS)
if (RegQueryValueEx(hKey, L"VendorIdentifier", nullptr, nullptr, (LPBYTE)cpuIdent, &size) != ERROR_SUCCESS)
mir_wstrcpy(cpuIdent, L"Unknown");
RegCloseKey(hKey);
}
TrimMultiSpaces(cpuName);
buffer.AppendFormat(L"CPU: %s [%s]", cpuName, cpuIdent);
if (IsProcessorFeaturePresent(PF_NX_ENABLED))
buffer.Append(L" [DEP Enabled]");
SYSTEM_INFO si = {};
GetSystemInfo(&si);
if (si.dwNumberOfProcessors > 1)
buffer.AppendFormat(L" [%u CPUs]", si.dwNumberOfProcessors);
}
void GetFreeMemoryString(CMStringW &buffer)
{
unsigned ram;
MEMORYSTATUSEX ms = {};
ms.dwLength = sizeof(ms);
GlobalMemoryStatusEx(&ms);
ram = (unsigned int)((ms.ullTotalPhys / (1024 * 1024)) + 1);
buffer.AppendFormat(L"Installed RAM: %u MBytes", ram);
}
void GetFreeDiskString(LPCTSTR dirname, CMStringW &buffer)
{
ULARGE_INTEGER tnb, tfb, fs = {};
GetDiskFreeSpaceEx(dirname, &fs, &tnb, &tfb);
fs.QuadPart /= (1024 * 1024);
buffer.AppendFormat(L"Free disk space on Miranda partition: %u MBytes", fs.LowPart);
}
void ReadableExceptionInfo(PEXCEPTION_RECORD excrec, CMStringW& buffer)
{
buffer.Append(L"Exception: ");
switch (excrec->ExceptionCode) {
case EXCEPTION_BREAKPOINT:
buffer.Append(L"User Defined Breakpoint");
break;
case EXCEPTION_ACCESS_VIOLATION:
buffer.Append(L"Access Violation");
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
buffer.Append(L"Array Bounds Exceeded");
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
buffer.Append(L"Datatype Misalignment");
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
buffer.Append(L"Floating Point denormlized operand");
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
buffer.Append(L"Floating Point divide by 0");
break;
case EXCEPTION_FLT_INEXACT_RESULT:
buffer.Append(L"Floating Point inexact result");
break;
case EXCEPTION_FLT_INVALID_OPERATION:
buffer.Append(L"Floating Point invalid operation");
break;
case EXCEPTION_FLT_OVERFLOW:
buffer.Append(L"Floating Point overflow");
break;
case EXCEPTION_FLT_STACK_CHECK:
buffer.Append(L"Floating Point stack overflow/underflow");
break;
case EXCEPTION_FLT_UNDERFLOW:
buffer.Append(L"Floating Point underflow");
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
buffer.Append(L"Invalid instruction executed");
break;
case EXCEPTION_IN_PAGE_ERROR:
buffer.Append(L"Access to the not present page");
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
buffer.Append(L"Integer divide by zero");
break;
case EXCEPTION_INT_OVERFLOW:
buffer.Append(L"Integer overflow");
break;
case EXCEPTION_PRIV_INSTRUCTION:
buffer.Append(L"Priveleged instruction executed");
break;
case EXCEPTION_STACK_OVERFLOW:
buffer.Append(L"Stack overflow");
break;
case 0xe06d7363:
buffer.Append(L"Unhandled C++ software exception");
break;
default:
buffer.AppendFormat(L"%x", excrec->ExceptionCode);
break;
}
buffer.AppendFormat(L" at address %p.", excrec->ExceptionAddress);
if (excrec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || excrec->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
switch (excrec->ExceptionInformation[0]) {
case 0:
buffer.AppendFormat(L" Reading from address %p.", (LPVOID)excrec->ExceptionInformation[1]);
break;
case 1:
buffer.AppendFormat(L" Writing to address %p.", (LPVOID)excrec->ExceptionInformation[1]);
break;
case 8:
buffer.AppendFormat(L" DEP at address %p.", (LPVOID)excrec->ExceptionInformation[1]);
break;
}
}
}
void GetAdminString(CMStringW &buffer)
{
BOOL b;
__try {
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
b = AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdministratorsGroup);
if (b) {
if (!CheckTokenMembership(nullptr, AdministratorsGroup, &b))
b = FALSE;
FreeSid(AdministratorsGroup);
}
else b = GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
b = TRUE;
}
buffer.AppendFormat(L"Administrator privileges: %s", b ? L"Yes" : L"No");
}
void GetLanguageString(CMStringW &buffer)
{
wchar_t name1[256], name2[256], name3[256], name4[256];
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, name1, 256);
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, name2, 256);
GetLocaleInfo(MAKELCID(GetUserDefaultUILanguage(), SORT_DEFAULT), LOCALE_SENGLANGUAGE, name3, 256);
GetLocaleInfo(MAKELCID(GetSystemDefaultUILanguage(), SORT_DEFAULT), LOCALE_SENGLANGUAGE, name4, 256);
buffer.AppendFormat(L"OS Languages: (UI | Locale (User/System)) : %s/%s | %s/%s", name3, name4, name1, name2);
}
void GetLanguagePackString(CMStringW &buffer)
{
buffer.Append(L"Language pack: ");
if (packlcid != LOCALE_USER_DEFAULT) {
wchar_t lang[MAX_PATH], ctry[MAX_PATH];
if (GetLocaleInfo(packlcid, LOCALE_SENGLANGUAGE, lang, MAX_PATH)) {
if (GetLocaleInfo(packlcid, LOCALE_SISO3166CTRYNAME, ctry, MAX_PATH))
buffer.AppendFormat(L"%s (%s) [%04x]", lang, ctry, packlcid);
else
buffer.Append(lang);
}
else buffer.Append(L"Locale id invalid");
}
else buffer.Append(L"No language pack installed");
}
void GetWow64String(CMStringW &buffer)
{
BOOL wow64 = 0;
if (!IsWow64Process(GetCurrentProcess(), &wow64))
wow64 = 0;
if (wow64)
buffer.Append(L" [running inside WOW64]");
}
void GetVersionInfo(HMODULE hLib, CMStringW& buffer)
{
HRSRC hVersion = FindResource(hLib, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
if (hVersion != nullptr) {
HGLOBAL hGlobal = LoadResource(hLib, hVersion);
if (hGlobal != nullptr) {
LPVOID versionInfo = LockResource(hGlobal);
if (versionInfo != nullptr) {
int vl = *(unsigned short*)versionInfo;
unsigned *res = (unsigned*)versionInfo;
while (*res != 0xfeef04bd && ((char*)res - (char*)versionInfo) < vl) ++res;
if (((char*)res - (char*)versionInfo) < vl) {
VS_FIXEDFILEINFO *vsInfo = (VS_FIXEDFILEINFO*)res;
buffer.AppendFormat(L" v.%u.%u.%u.%u",
HIWORD(vsInfo->dwFileVersionMS), LOWORD(vsInfo->dwFileVersionMS),
HIWORD(vsInfo->dwFileVersionLS), LOWORD(vsInfo->dwFileVersionLS));
}
}
FreeResource(hGlobal);
}
}
}