mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-08 01:52:52 +08:00
[BugReportTool] Report compatibility tabs (#11375)
This commit is contained in:
parent
601da71f15
commit
d55badf14a
1
.github/actions/spell-check/expect.txt
vendored
1
.github/actions/spell-check/expect.txt
vendored
@ -2231,6 +2231,7 @@ workaround
|
|||||||
workflow
|
workflow
|
||||||
workspaces
|
workspaces
|
||||||
wostream
|
wostream
|
||||||
|
wostringstream
|
||||||
wox
|
wox
|
||||||
wparam
|
wparam
|
||||||
wpf
|
wpf
|
||||||
|
@ -38,8 +38,8 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||||
<ClCompile Include="Main.cpp" />
|
<ClCompile Include="Main.cpp" />
|
||||||
<ClCompile Include="ReportRegistry.cpp" />
|
<ClCompile Include="RegistryUtils.cpp" />
|
||||||
<ClCompile Include="ZipTools\zipfolder.cpp" />
|
<ClCompile Include="ZipTools\ZipFolder.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
@ -54,8 +54,8 @@
|
|||||||
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
||||||
<ClInclude Include="ReportMonitorInfo.h" />
|
<ClInclude Include="ReportMonitorInfo.h" />
|
||||||
<ClInclude Include="..\..\..\common\utils\json.h" />
|
<ClInclude Include="..\..\..\common\utils\json.h" />
|
||||||
<ClInclude Include="ReportRegistry.h" />
|
<ClInclude Include="RegistryUtils.h" />
|
||||||
<ClInclude Include="ZipTools\zipfolder.h" />
|
<ClInclude Include="ZipTools\ZipFolder.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Main.cpp" />
|
<ClCompile Include="Main.cpp" />
|
||||||
<ClCompile Include="ZipTools\zipfolder.cpp">
|
<ClCompile Include="ZipTools\ZipFolder.cpp">
|
||||||
<Filter>ZipTools</Filter>
|
<Filter>ZipTools</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c" />
|
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c" />
|
||||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||||
<ClCompile Include="ReportRegistry.cpp" />
|
<ClCompile Include="RegistryUtils.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="ZipTools">
|
<Filter Include="ZipTools">
|
||||||
@ -18,13 +18,13 @@
|
|||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="ZipTools\zipfolder.h">
|
<ClInclude Include="ZipTools\ZipFolder.h">
|
||||||
<Filter>ZipTools</Filter>
|
<Filter>ZipTools</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\..\common\utils\json.h" />
|
<ClInclude Include="..\..\..\common\utils\json.h" />
|
||||||
<ClInclude Include="..\..\..\deps\cziplib\src\miniz.h" />
|
<ClInclude Include="..\..\..\deps\cziplib\src\miniz.h" />
|
||||||
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
||||||
<ClInclude Include="ReportMonitorInfo.h" />
|
<ClInclude Include="ReportMonitorInfo.h" />
|
||||||
<ClInclude Include="ReportRegistry.h" />
|
<ClInclude Include="RegistryUtils.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -15,7 +15,7 @@
|
|||||||
#include <common/utils/exec.h>
|
#include <common/utils/exec.h>
|
||||||
|
|
||||||
#include "ReportMonitorInfo.h"
|
#include "ReportMonitorInfo.h"
|
||||||
#include "ReportRegistry.h"
|
#include "RegistryUtils.h"
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::filesystem;
|
using namespace std::filesystem;
|
||||||
using namespace winrt::Windows::Data::Json;
|
using namespace winrt::Windows::Data::Json;
|
||||||
@ -33,7 +33,7 @@ vector<wstring> filesToDelete = {
|
|||||||
L"PowerToys Run\\Settings\\QueryHistory.json"
|
L"PowerToys Run\\Settings\\QueryHistory.json"
|
||||||
};
|
};
|
||||||
|
|
||||||
vector<wstring> getXpathArray(wstring xpath)
|
vector<wstring> GetXpathArray(wstring xpath)
|
||||||
{
|
{
|
||||||
vector<wstring> result;
|
vector<wstring> result;
|
||||||
wstring cur = L"";
|
wstring cur = L"";
|
||||||
@ -57,13 +57,13 @@ vector<wstring> getXpathArray(wstring xpath)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hideByXPath(IJsonValue& val, vector<wstring>& xpathArray, int p)
|
void HideByXPath(IJsonValue& val, vector<wstring>& xpathArray, int p)
|
||||||
{
|
{
|
||||||
if (val.ValueType() == JsonValueType::Array)
|
if (val.ValueType() == JsonValueType::Array)
|
||||||
{
|
{
|
||||||
for (auto it : val.GetArray())
|
for (auto it : val.GetArray())
|
||||||
{
|
{
|
||||||
hideByXPath(it, xpathArray, p);
|
HideByXPath(it, xpathArray, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -96,11 +96,11 @@ void hideByXPath(IJsonValue& val, vector<wstring>& xpathArray, int p)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hideByXPath(newVal, xpathArray, p + 1);
|
HideByXPath(newVal, xpathArray, p + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hideForFile(const path& dir, const wstring& relativePath)
|
void HideForFile(const path& dir, const wstring& relativePath)
|
||||||
{
|
{
|
||||||
path jsonPath = dir;
|
path jsonPath = dir;
|
||||||
jsonPath.append(relativePath);
|
jsonPath.append(relativePath);
|
||||||
@ -114,14 +114,14 @@ void hideForFile(const path& dir, const wstring& relativePath)
|
|||||||
JsonValue jValue = json::value(jObject.value());
|
JsonValue jValue = json::value(jObject.value());
|
||||||
for (auto xpath : escapeInfo[relativePath])
|
for (auto xpath : escapeInfo[relativePath])
|
||||||
{
|
{
|
||||||
vector<wstring> xpathArray = getXpathArray(xpath);
|
vector<wstring> xpathArray = GetXpathArray(xpath);
|
||||||
hideByXPath(jValue, xpathArray, 0);
|
HideByXPath(jValue, xpathArray, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
json::to_file(jsonPath.wstring(), jObject.value());
|
json::to_file(jsonPath.wstring(), jObject.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deleteFolder(wstring path)
|
bool DeleteFolder(wstring path)
|
||||||
{
|
{
|
||||||
error_code err;
|
error_code err;
|
||||||
remove_all(path, err);
|
remove_all(path, err);
|
||||||
@ -134,12 +134,12 @@ bool deleteFolder(wstring path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hideUserPrivateInfo(const filesystem::path& dir)
|
void HideUserPrivateInfo(const filesystem::path& dir)
|
||||||
{
|
{
|
||||||
// Replace data in json files
|
// Replace data in json files
|
||||||
for (auto& it : escapeInfo)
|
for (auto& it : escapeInfo)
|
||||||
{
|
{
|
||||||
hideForFile(dir, it.first);
|
HideForFile(dir, it.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete files
|
// delete files
|
||||||
@ -147,11 +147,11 @@ void hideUserPrivateInfo(const filesystem::path& dir)
|
|||||||
{
|
{
|
||||||
auto path = dir;
|
auto path = dir;
|
||||||
path = path.append(it);
|
path = path.append(it);
|
||||||
deleteFolder(path);
|
DeleteFolder(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reportWindowsVersion(const filesystem::path& tmpDir)
|
void ReportWindowsVersion(const filesystem::path& tmpDir)
|
||||||
{
|
{
|
||||||
auto versionReportPath = tmpDir;
|
auto versionReportPath = tmpDir;
|
||||||
versionReportPath = versionReportPath.append("windows-version.txt");
|
versionReportPath = versionReportPath.append("windows-version.txt");
|
||||||
@ -187,7 +187,7 @@ void reportWindowsVersion(const filesystem::path& tmpDir)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reportWindowsSettings(const filesystem::path& tmpDir)
|
void ReportWindowsSettings(const filesystem::path& tmpDir)
|
||||||
{
|
{
|
||||||
std::wstring userLanguage;
|
std::wstring userLanguage;
|
||||||
std::wstring userLocale;
|
std::wstring userLocale;
|
||||||
@ -221,7 +221,7 @@ void reportWindowsSettings(const filesystem::path& tmpDir)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reportDotNetInstallationInfo(const filesystem::path& tmpDir)
|
void ReportDotNetInstallationInfo(const filesystem::path& tmpDir)
|
||||||
{
|
{
|
||||||
auto dotnetInfoPath = tmpDir;
|
auto dotnetInfoPath = tmpDir;
|
||||||
dotnetInfoPath.append("dotnet-installation-info.txt");
|
dotnetInfoPath.append("dotnet-installation-info.txt");
|
||||||
@ -271,7 +271,7 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
|||||||
// Copy to a temp folder
|
// Copy to a temp folder
|
||||||
auto tmpDir = temp_directory_path();
|
auto tmpDir = temp_directory_path();
|
||||||
tmpDir = tmpDir.append("PowerToys\\");
|
tmpDir = tmpDir.append("PowerToys\\");
|
||||||
if (!deleteFolder(tmpDir))
|
if (!DeleteFolder(tmpDir))
|
||||||
{
|
{
|
||||||
printf("Failed to delete temp folder\n");
|
printf("Failed to delete temp folder\n");
|
||||||
return 1;
|
return 1;
|
||||||
@ -281,7 +281,7 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
|||||||
{
|
{
|
||||||
copy(settingsRootPath, tmpDir, copy_options::recursive);
|
copy(settingsRootPath, tmpDir, copy_options::recursive);
|
||||||
// Remove updates folder contents
|
// Remove updates folder contents
|
||||||
deleteFolder(tmpDir / "Updates");
|
DeleteFolder(tmpDir / "Updates");
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -290,22 +290,25 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hide sensitive information
|
// Hide sensitive information
|
||||||
hideUserPrivateInfo(tmpDir);
|
HideUserPrivateInfo(tmpDir);
|
||||||
|
|
||||||
// Write windows settings to the temporary folder
|
// Write windows settings to the temporary folder
|
||||||
reportWindowsSettings(tmpDir);
|
ReportWindowsSettings(tmpDir);
|
||||||
|
|
||||||
// Write monitors info to the temporary folder
|
// Write monitors info to the temporary folder
|
||||||
reportMonitorInfo(tmpDir);
|
reportMonitorInfo(tmpDir);
|
||||||
|
|
||||||
// Write windows version info to the temporary folder
|
// Write windows version info to the temporary folder
|
||||||
reportWindowsVersion(tmpDir);
|
ReportWindowsVersion(tmpDir);
|
||||||
|
|
||||||
// Write dotnet installation info to the temporary folder
|
// Write dotnet installation info to the temporary folder
|
||||||
reportDotNetInstallationInfo(tmpDir);
|
ReportDotNetInstallationInfo(tmpDir);
|
||||||
|
|
||||||
// Write registry to the temporary folder
|
// Write registry to the temporary folder
|
||||||
reportRegistry(tmpDir);
|
ReportRegistry(tmpDir);
|
||||||
|
|
||||||
|
// Write compatibility tab info to the temporary folder
|
||||||
|
ReportCompatibilityTab(tmpDir);
|
||||||
|
|
||||||
// Zip folder
|
// Zip folder
|
||||||
auto zipPath = path::path(saveZipPath);
|
auto zipPath = path::path(saveZipPath);
|
||||||
@ -316,7 +319,7 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
zipFolder(zipPath, tmpDir);
|
ZipFolder(zipPath, tmpDir);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@ -324,6 +327,6 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteFolder(tmpDir);
|
DeleteFolder(tmpDir);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#include "ReportRegistry.h"
|
#include "RegistryUtils.h"
|
||||||
|
#include <common/utils/winapi_error.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -38,7 +40,35 @@ namespace
|
|||||||
{ HKEY_USERS, L"HKEY_USERS"},
|
{ HKEY_USERS, L"HKEY_USERS"},
|
||||||
};
|
};
|
||||||
|
|
||||||
void queryKey(HKEY key, wofstream& stream, int indent = 1)
|
vector<pair<wstring, wstring>> QueryValues(HKEY key)
|
||||||
|
{
|
||||||
|
DWORD cValues;
|
||||||
|
DWORD retCode = RegQueryInfoKeyW(key, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &cValues, nullptr, nullptr, nullptr, nullptr);
|
||||||
|
TCHAR achValue[255];
|
||||||
|
DWORD cchValue = 255;
|
||||||
|
LPBYTE value;
|
||||||
|
vector<pair<wstring, wstring>> results;
|
||||||
|
// Values
|
||||||
|
if (cValues)
|
||||||
|
{
|
||||||
|
for (DWORD 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)
|
||||||
|
{
|
||||||
|
results.push_back({ achValue, (LPCTSTR)value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryKey(HKEY key, wostream& stream, int indent = 1)
|
||||||
{
|
{
|
||||||
TCHAR achKey[255];
|
TCHAR achKey[255];
|
||||||
DWORD cbName;
|
DWORD cbName;
|
||||||
@ -114,7 +144,7 @@ namespace
|
|||||||
if (RegOpenKeyExW(key, child.c_str(), 0, KEY_READ, &hTestKey) == ERROR_SUCCESS)
|
if (RegOpenKeyExW(key, child.c_str(), 0, KEY_READ, &hTestKey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
stream << wstring(indent, '\t') << child << "\n";
|
stream << wstring(indent, '\t') << child << "\n";
|
||||||
queryKey(hTestKey, stream, indent + 1);
|
QueryKey(hTestKey, stream, indent + 1);
|
||||||
RegCloseKey(hTestKey);
|
RegCloseKey(hTestKey);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -126,7 +156,74 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void reportRegistry(const filesystem::path& tmpDir)
|
void ReportCompatibilityTab(HKEY key, wofstream& report)
|
||||||
|
{
|
||||||
|
vector<std::wstring> apps
|
||||||
|
{
|
||||||
|
L"PowerToys.exe",
|
||||||
|
L"ColorPickerUI.exe",
|
||||||
|
L"FancyZonesEditor.exe",
|
||||||
|
L"PowerToys.KeyboardManagerEditor.exe",
|
||||||
|
L"PowerToys.KeyboardManagerEditor.exe",
|
||||||
|
L"PowerLauncher.exe",
|
||||||
|
L"PowerToys.ShortcutGuide.exe"
|
||||||
|
};
|
||||||
|
|
||||||
|
map<wstring, wstring> flags;
|
||||||
|
for (auto app : apps)
|
||||||
|
{
|
||||||
|
flags[app] = L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HKEY outKey;
|
||||||
|
LONG result = RegOpenKeyExW(key, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers", 0, KEY_READ, &outKey);
|
||||||
|
if (result == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
auto values = QueryValues(outKey);
|
||||||
|
for (auto value : values)
|
||||||
|
{
|
||||||
|
for (auto app : apps)
|
||||||
|
{
|
||||||
|
if (value.first.find(app) != wstring::npos)
|
||||||
|
{
|
||||||
|
flags[app] += value.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
report << "Failed to get the report. " << get_last_error_or_default(GetLastError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
report << "Failed to get the report";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto flag : flags)
|
||||||
|
{
|
||||||
|
report << flag.first << ": " << flag.second << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportCompatibilityTab(const std::filesystem::path& tmpDir)
|
||||||
|
{
|
||||||
|
auto reportPath = tmpDir;
|
||||||
|
reportPath.append(L"compatibility-tab-info.txt");
|
||||||
|
wofstream report(reportPath);
|
||||||
|
report << "Current user report" << endl;
|
||||||
|
ReportCompatibilityTab(HKEY_CURRENT_USER, report);
|
||||||
|
report << endl << endl;
|
||||||
|
report << "Local machine report" << endl;
|
||||||
|
ReportCompatibilityTab(HKEY_LOCAL_MACHINE, report);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportRegistry(const filesystem::path& tmpDir)
|
||||||
{
|
{
|
||||||
auto registryReportPath = tmpDir;
|
auto registryReportPath = tmpDir;
|
||||||
registryReportPath.append("registry-report-info.txt");
|
registryReportPath.append("registry-report-info.txt");
|
||||||
@ -142,7 +239,7 @@ void reportRegistry(const filesystem::path& tmpDir)
|
|||||||
LONG result = RegOpenKeyExW(rootKey, subKey.c_str(), 0, KEY_READ, &outKey);
|
LONG result = RegOpenKeyExW(rootKey, subKey.c_str(), 0, KEY_READ, &outKey);
|
||||||
if (result == ERROR_SUCCESS)
|
if (result == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
queryKey(outKey, registryReport);
|
QueryKey(outKey, registryReport);
|
||||||
RegCloseKey(rootKey);
|
RegCloseKey(rootKey);
|
||||||
}
|
}
|
||||||
else
|
else
|
@ -7,4 +7,5 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
void reportRegistry(const std::filesystem::path& tmpDir);
|
void ReportRegistry(const std::filesystem::path& tmpDir);
|
||||||
|
void ReportCompatibilityTab(const std::filesystem::path& tmpDir);
|
@ -1,7 +1,7 @@
|
|||||||
#include "zipfolder.h"
|
#include "ZipFolder.h"
|
||||||
#include "..\..\..\..\deps\cziplib\src\zip.h"
|
#include "..\..\..\..\deps\cziplib\src\zip.h"
|
||||||
|
|
||||||
void zipFolder(std::filesystem::path zipPath, std::filesystem::path folderPath)
|
void ZipFolder(std::filesystem::path zipPath, std::filesystem::path folderPath)
|
||||||
{
|
{
|
||||||
struct zip_t* zip = zip_open(zipPath.string().c_str(), ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
struct zip_t* zip = zip_open(zipPath.string().c_str(), ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
if (!zip)
|
if (!zip)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
void zipFolder(std::filesystem::path zipPath, std::filesystem::path folderPath);
|
void ZipFolder(std::filesystem::path zipPath, std::filesystem::path folderPath);
|
Loading…
Reference in New Issue
Block a user