diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 1a172f6cd0..3957d9dd6c 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -1446,6 +1446,7 @@ nielslaute NIF NLD NLog +NLSTEXT NMLVEMPTYMARKUP NOACTIVATE noactive diff --git a/tools/BugReportTool/BugReportTool/BugReportTool.vcxproj b/tools/BugReportTool/BugReportTool/BugReportTool.vcxproj index 4347deb6df..7446321e05 100644 --- a/tools/BugReportTool/BugReportTool/BugReportTool.vcxproj +++ b/tools/BugReportTool/BugReportTool/BugReportTool.vcxproj @@ -38,6 +38,7 @@ + @@ -53,6 +54,7 @@ + diff --git a/tools/BugReportTool/BugReportTool/BugReportTool.vcxproj.filters b/tools/BugReportTool/BugReportTool/BugReportTool.vcxproj.filters index 97629d25ed..1873491280 100644 --- a/tools/BugReportTool/BugReportTool/BugReportTool.vcxproj.filters +++ b/tools/BugReportTool/BugReportTool/BugReportTool.vcxproj.filters @@ -10,6 +10,7 @@ + @@ -24,5 +25,6 @@ + \ No newline at end of file diff --git a/tools/BugReportTool/BugReportTool/Main.cpp b/tools/BugReportTool/BugReportTool/Main.cpp index 9f8370e5d1..b22be935d3 100644 --- a/tools/BugReportTool/BugReportTool/Main.cpp +++ b/tools/BugReportTool/BugReportTool/Main.cpp @@ -13,6 +13,7 @@ #include #include "ReportMonitorInfo.h" +#include "ReportRegistry.h" using namespace std; using namespace std::filesystem; using namespace winrt::Windows::Data::Json; @@ -148,27 +149,6 @@ void hideUserPrivateInfo(const filesystem::path& dir) } } -void reportMonitorInfo(const filesystem::path& tmpDir) -{ - auto monitorReportPath = tmpDir; - monitorReportPath.append("monitor-report-info.txt"); - - try - { - wofstream monitorReport(monitorReportPath); - monitorReport << "GetSystemMetrics = " << GetSystemMetrics(SM_CMONITORS) << '\n'; - report(monitorReport); - } - catch (std::exception& ex) - { - printf("Failed to report monitor info. %s\n", ex.what()); - } - catch (...) - { - printf("Failed to report monitor info\n"); - } -} - void reportWindowsVersion(const filesystem::path& tmpDir) { auto versionReportPath = tmpDir; @@ -285,6 +265,9 @@ int wmain(int argc, wchar_t* argv[], wchar_t*) // Write dotnet installation info to the temporary folder reportDotNetInstallationInfo(tmpDir); + // Write registry to the temporary folder + reportRegistry(tmpDir); + // Zip folder auto zipPath = path::path(saveZipPath); std::string reportFilename{"PowerToysReport_"}; @@ -304,4 +287,4 @@ int wmain(int argc, wchar_t* argv[], wchar_t*) deleteFolder(tmpDir); return 0; -} \ No newline at end of file +} diff --git a/tools/BugReportTool/BugReportTool/ReportMonitorInfo.cpp b/tools/BugReportTool/BugReportTool/ReportMonitorInfo.cpp index 5caccb9113..5028257578 100644 --- a/tools/BugReportTool/BugReportTool/ReportMonitorInfo.cpp +++ b/tools/BugReportTool/BugReportTool/ReportMonitorInfo.cpp @@ -1,56 +1,82 @@ #pragma once #include "ReportMonitorInfo.h" #include +#include #include "../../../src/common/utils/winapi_error.h" +using namespace std; -int report(std::wostream& os) +namespace { - struct capture + int buildMonitorInfoReport(std::wostream& os) { - std::wostream* os = nullptr; - }; - - auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM prm) -> BOOL { - std::wostream& os = *((capture*)prm)->os; - MONITORINFOEX mi; - mi.cbSize = sizeof(mi); - - if (GetMonitorInfoW(monitor, &mi)) + struct capture { - os << "GetMonitorInfo OK\n"; - DISPLAY_DEVICE displayDevice = { sizeof(displayDevice) }; + std::wostream* os = nullptr; + }; - DWORD i = 0; - while (EnumDisplayDevicesW(mi.szDevice, i++, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME)) + auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM prm) -> BOOL { + std::wostream& os = *((capture*)prm)->os; + MONITORINFOEX mi; + mi.cbSize = sizeof(mi); + + if (GetMonitorInfoW(monitor, &mi)) { - const bool active = displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE; - const bool mirroring = displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER; - os << "EnumDisplayDevices OK:\n" - << "\tMirroring = " << mirroring << '\n' - << "\tActive = " << active << '\n' - << "\tDeviceID = " << displayDevice.DeviceID << '\n' - << "\tDeviceKey = " << displayDevice.DeviceKey << '\n' - << "\tDeviceName = " << displayDevice.DeviceName << '\n' - << "\tDeviceString = " << displayDevice.DeviceString << '\n'; + os << "GetMonitorInfo OK\n"; + DISPLAY_DEVICE displayDevice = { sizeof(displayDevice) }; + + DWORD i = 0; + while (EnumDisplayDevicesW(mi.szDevice, i++, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME)) + { + const bool active = displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE; + const bool mirroring = displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER; + os << "EnumDisplayDevices OK:\n" + << "\tMirroring = " << mirroring << '\n' + << "\tActive = " << active << '\n' + << "\tDeviceID = " << displayDevice.DeviceID << '\n' + << "\tDeviceKey = " << displayDevice.DeviceKey << '\n' + << "\tDeviceName = " << displayDevice.DeviceName << '\n' + << "\tDeviceString = " << displayDevice.DeviceString << '\n'; + } } + else + { + auto message = get_last_error_message(GetLastError()); + os << "GetMonitorInfo FAILED: " << (message.has_value() ? message.value() : L"") << '\n'; + } + return TRUE; + }; + capture c; + c.os = &os; + if (EnumDisplayMonitors(nullptr, nullptr, callback, (LPARAM)&c)) + { + os << "EnumDisplayMonitors OK\n"; } else { auto message = get_last_error_message(GetLastError()); - os << "GetMonitorInfo FAILED: " << (message.has_value() ? message.value() : L"") << '\n'; + os << "EnumDisplayMonitors FAILED: " << (message.has_value() ? message.value() : L"") << '\n'; } - return TRUE; - }; - capture c; - c.os = &os; - if (EnumDisplayMonitors(nullptr, nullptr, callback, (LPARAM)&c)) - { - os << "EnumDisplayMonitors OK\n"; + return 0; } - else +} + +void reportMonitorInfo(const filesystem::path& tmpDir) +{ + auto monitorReportPath = tmpDir; + monitorReportPath.append("monitor-report-info.txt"); + + try { - auto message = get_last_error_message(GetLastError()); - os << "EnumDisplayMonitors FAILED: " << (message.has_value() ? message.value() : L"") << '\n'; + wofstream monitorReport(monitorReportPath); + monitorReport << "GetSystemMetrics = " << GetSystemMetrics(SM_CMONITORS) << '\n'; + buildMonitorInfoReport(monitorReport); } - return 0; -} \ No newline at end of file + catch (std::exception& ex) + { + printf("Failed to report monitor info. %s\n", ex.what()); + } + catch (...) + { + printf("Failed to report monitor info\n"); + } +} diff --git a/tools/BugReportTool/BugReportTool/ReportMonitorInfo.h b/tools/BugReportTool/BugReportTool/ReportMonitorInfo.h index f02e95e599..d1dcd26ab7 100644 --- a/tools/BugReportTool/BugReportTool/ReportMonitorInfo.h +++ b/tools/BugReportTool/BugReportTool/ReportMonitorInfo.h @@ -1,4 +1,4 @@ #pragma once #include -int report(std::wostream& os); \ No newline at end of file +void reportMonitorInfo(const std::filesystem::path& tmpDir); diff --git a/tools/BugReportTool/BugReportTool/ReportRegistry.cpp b/tools/BugReportTool/BugReportTool/ReportRegistry.cpp new file mode 100644 index 0000000000..5d19cc5128 --- /dev/null +++ b/tools/BugReportTool/BugReportTool/ReportRegistry.cpp @@ -0,0 +1,207 @@ +#include "ReportRegistry.h" + +using namespace std; + +namespace +{ + vector> registryKeys = { + { HKEY_CLASSES_ROOT, L"Software\\Classes\\CLSID\\{DD5CACDA-7C2E-4997-A62A-04A597B58F76}" }, + { HKEY_CLASSES_ROOT, L"powertoys" }, + { HKEY_CLASSES_ROOT, L"CLSID\\{ddee2b8a-6807-48a6-bb20-2338174ff779}" }, + { HKEY_CLASSES_ROOT, L"CLSID\\{36B27788-A8BB-4698-A756-DF9F11F64F84}" }, + { HKEY_CLASSES_ROOT, L"CLSID\\{45769bcc-e8fd-42d0-947e-02beef77a1f5}" }, + { HKEY_CLASSES_ROOT, L"AppID\\{CF142243-F059-45AF-8842-DBBE9783DB14}" }, + { HKEY_CLASSES_ROOT, L"CLSID\\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\\InprocServer32" }, + { HKEY_CLASSES_ROOT, L"CLSID\\{0440049F-D1DC-4E46-B27B-98393D79486B}" }, + { HKEY_CLASSES_ROOT, L"AllFileSystemObjects\\ShellEx\\ContextMenuHandlers\\PowerRenameExt" }, + { HKEY_CURRENT_USER, L"SOFTWARE\\Classes\\AppUserModelId\\PowerToysRun" }, + { HKEY_CLASSES_ROOT, L".svg\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" }, + { HKEY_CLASSES_ROOT, L".svg\\shellex\\{E357FCCD-A995-4576-B01F-234630154E96}" }, + { HKEY_CLASSES_ROOT, L".md\\shellex\\{8895b1c6-b41f-4c1c-a562-0d564250836f}" } + }; + + vector> registryValues = { + { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{ddee2b8a-6807-48a6-bb20-2338174ff779}" }, + { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers", L"{45769bcc-e8fd-42d0-947e-02beef77a1f5}" }, + { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", L"prevhost.exe" }, + { HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION", L"dllhost.exe" } + }; + + // Is there a Windows API for this? + std::unordered_map hKeyToString = { + { HKEY_CLASSES_ROOT, L"HKEY_CLASSES_ROOT" }, + { HKEY_CURRENT_USER, L"HKEY_CURRENT_USER" }, + { HKEY_LOCAL_MACHINE, L"HKEY_LOCAL_MACHINE" }, + { HKEY_PERFORMANCE_DATA, L"HKEY_PERFORMANCE_DATA" }, + { HKEY_PERFORMANCE_NLSTEXT, L"HKEY_PERFORMANCE_NLSTEXT"}, + { HKEY_PERFORMANCE_TEXT, L"HKEY_PERFORMANCE_TEXT"}, + { HKEY_USERS, L"HKEY_USERS"}, + }; + + void queryKey(HKEY key, wofstream& stream, int indent = 1) + { + TCHAR achKey[255]; + DWORD cbName; + TCHAR achClass[MAX_PATH] = TEXT(""); + DWORD cchClassName = MAX_PATH; + DWORD cSubKeys = 0; + DWORD cbMaxSubKey; + DWORD cchMaxClass; + DWORD cValues; + DWORD cchMaxValue; + DWORD cbMaxValueData; + + DWORD i, retCode; + + TCHAR achValue[255]; + DWORD cchValue = 255; + LPBYTE value; + + // Get the class name and the value count. + retCode = RegQueryInfoKeyW(key, achClass, &cchClassName, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, &cValues, &cchMaxValue, &cbMaxValueData, NULL, NULL); + + // Values + if (cValues) + { + for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++) + { + cchValue = 255; + achValue[0] = '\0'; + value = new BYTE[16383]; + retCode = RegEnumValueW(key, i, achValue, &cchValue, NULL, NULL, value, &cchValue); + + if (retCode == ERROR_SUCCESS) + { + stream << wstring(indent, '\t'); + if (achValue[0] == '\0') + { + stream << "Default"; + } + else + { + stream << achValue; + } + + stream << " > " << (LPCTSTR)value << "\n"; + } + else + { + stream << "Error " << retCode << "\n"; + } + } + } + + // Keys + if (cSubKeys) + { + std::vector vecKeys; + vecKeys.reserve(cSubKeys); + + for (i = 0; i < cSubKeys; ++i) + { + cbName = 255; + retCode = RegEnumKeyExW(key, i, achKey, &cbName, NULL, NULL, NULL, NULL); + if (retCode == ERROR_SUCCESS) + { + vecKeys.push_back(achKey); + } + } + + // Parsing subkeys recursively + for (auto& child : vecKeys) + { + HKEY hTestKey; + if (RegOpenKeyExW(key, child.c_str(), 0, KEY_READ, &hTestKey) == ERROR_SUCCESS) + { + stream << wstring(indent, '\t') << child << "\n"; + queryKey(hTestKey, stream, indent + 1); + RegCloseKey(hTestKey); + } + else + { + stream << "Error " << retCode << "\n"; + } + } + } + } +} + +void reportRegistry(const filesystem::path& tmpDir) +{ + auto registryReportPath = tmpDir; + registryReportPath.append("registry-report-info.txt"); + + wofstream registryReport(registryReportPath); + try + { + for (auto [rootKey, subKey] : registryKeys) + { + registryReport << hKeyToString[rootKey] << "\\" << subKey << "\n"; + + HKEY outKey; + LONG result = RegOpenKeyExW(rootKey, subKey.c_str(), 0, KEY_READ, &outKey); + if (result == ERROR_SUCCESS) + { + queryKey(outKey, registryReport); + RegCloseKey(rootKey); + } + else + { + registryReport << "ERROR " << result << "\n"; + } + registryReport << "\n"; + } + + for (auto [rootKey, subKey, value] : registryValues) + { + registryReport << hKeyToString[rootKey] << "\\" << subKey << "\n"; + + // Reading size + DWORD dataSize = 0; + DWORD flags = RRF_RT_ANY; + DWORD type; + LONG result = RegGetValueW(rootKey, subKey.c_str(), value.c_str(), flags, &type, NULL, &dataSize); + if (result == ERROR_SUCCESS) + { + // Reading value + if (type == REG_SZ) // string + { + std::wstring data(dataSize / sizeof(wchar_t) + 1, L' '); + result = RegGetValueW(rootKey, subKey.c_str(), value.c_str(), flags, &type, &data[0], &dataSize); + if (result == ERROR_SUCCESS) + { + registryReport << "\t" << value << " > " << data << "\n"; + } + else + { + registryReport << "ERROR " << result << "\n"; + } + } + else + { + DWORD data = 0; + DWORD dataSize = sizeof(data); + LONG retCode = RegGetValueW(rootKey, subKey.c_str(), value.c_str(), flags, &type, &data, &dataSize); + if (result == ERROR_SUCCESS) + { + registryReport << "\t" << value << " > " << data << "\n"; + } + else + { + registryReport << "ERROR " << result << "\n"; + } + } + RegCloseKey(rootKey); + } + else + { + registryReport << "ERROR " << result << "\n"; + } + registryReport << "\n"; + } + } + catch (...) + { + printf("Failed to get registry keys\n"); + } +} diff --git a/tools/BugReportTool/BugReportTool/ReportRegistry.h b/tools/BugReportTool/BugReportTool/ReportRegistry.h new file mode 100644 index 0000000000..01cd964a3e --- /dev/null +++ b/tools/BugReportTool/BugReportTool/ReportRegistry.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +void reportRegistry(const std::filesystem::path& tmpDir);