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);