mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 02:36:19 +02:00
Report tool improvements (#8709)
* bugreport: move to tools * bugreport: skip packaging installers, format time with seconds, remove monitor-info-report tool * bugreport: move BugReportTool to Tools folder * fix CI * fix CDPX
This commit is contained in:
69
tools/BugReportTool/BugReportTool/BugReportTool.vcxproj
Normal file
69
tools/BugReportTool/BugReportTool/BugReportTool.vcxproj
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{99126840-5c30-4e9e-ac6c-e73dded5c3bd}</ProjectGuid>
|
||||
<RootNamespace>BugReportTool</RootNamespace>
|
||||
<ProjectName>BugReportTool</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup>
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<IntDir>$(SolutionDir)..\..\$(Platform)\$(Configuration)\obj\$(ProjectName)\</IntDir>
|
||||
<OutDir>$(SolutionDir)..\..\$(Platform)\$(Configuration)\$(ProjectName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>../../../src/</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c">
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="ZipTools\zipfolder.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\common\SettingsAPI\SetttingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\deps\cziplib\src\miniz.h" />
|
||||
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
||||
<ClInclude Include="ReportMonitorInfo.h" />
|
||||
<ClInclude Include="..\..\..\common\utils\json.h" />
|
||||
<ClInclude Include="ZipTools\zipfolder.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="ZipTools\zipfolder.cpp">
|
||||
<Filter>ZipTools</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\deps\cziplib\src\zip.c" />
|
||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="ZipTools">
|
||||
<UniqueIdentifier>{3ae1b6aa-4134-47b1-afdf-dfb3b5901dcc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="MonitorReportTool">
|
||||
<UniqueIdentifier>{83b7e7d9-49b7-4fc8-9853-9dbb8f2c0e76}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ZipTools\zipfolder.h">
|
||||
<Filter>ZipTools</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\common\utils\json.h" />
|
||||
<ClInclude Include="..\..\..\deps\cziplib\src\miniz.h" />
|
||||
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
||||
<ClInclude Include="ReportMonitorInfo.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
279
tools/BugReportTool/BugReportTool/Main.cpp
Normal file
279
tools/BugReportTool/BugReportTool/Main.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <Shlobj.h>
|
||||
#include <winrt/Windows.Data.Json.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
|
||||
#include "ZipTools/ZipFolder.h"
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
#include <common/utils/json.h>
|
||||
#include <common/utils/timeutil.h>
|
||||
|
||||
#include "ReportMonitorInfo.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::filesystem;
|
||||
using namespace winrt::Windows::Data::Json;
|
||||
|
||||
map<wstring, vector<wstring>> escapeInfo = {
|
||||
{ L"FancyZones\\app-zone-history.json", { L"app-zone-history/app-path" } },
|
||||
{ L"PowerRename\\replace-mru.json", { L"MRUList" } },
|
||||
{ L"PowerRename\\search-mru.json", { L"MRUList" } },
|
||||
{ L"FancyZones\\settings.json", { L"properties/fancyzones_excluded_apps" } },
|
||||
{ L"PowerToys Run\\Settings\\QueryHistory.json", { L"Items" } },
|
||||
};
|
||||
|
||||
vector<wstring> filesToDelete = {
|
||||
L"PowerToys Run\\Cache\\Image.cache"
|
||||
};
|
||||
|
||||
vector<wstring> getXpathArray(wstring xpath)
|
||||
{
|
||||
vector<wstring> result;
|
||||
wstring cur = L"";
|
||||
for (auto ch : xpath)
|
||||
{
|
||||
if (ch == L'/')
|
||||
{
|
||||
result.push_back(cur);
|
||||
cur = L"";
|
||||
continue;
|
||||
}
|
||||
|
||||
cur += ch;
|
||||
}
|
||||
|
||||
if (!cur.empty())
|
||||
{
|
||||
result.push_back(cur);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void hideByXPath(IJsonValue& val, vector<wstring>& xpathArray, int p)
|
||||
{
|
||||
if (val.ValueType() == JsonValueType::Array)
|
||||
{
|
||||
for (auto it : val.GetArray())
|
||||
{
|
||||
hideByXPath(it, xpathArray, p);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (p == xpathArray.size() - 1)
|
||||
{
|
||||
if (val.ValueType() == JsonValueType::Object)
|
||||
{
|
||||
auto obj = val.GetObjectW();
|
||||
if (obj.HasKey(xpathArray[p]))
|
||||
{
|
||||
auto privateDatavalue = JsonValue::CreateStringValue(L"<private_data>");
|
||||
obj.SetNamedValue(xpathArray[p], privateDatavalue);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (val.ValueType() == JsonValueType::Object)
|
||||
{
|
||||
IJsonValue newVal;
|
||||
try
|
||||
{
|
||||
newVal = val.GetObjectW().GetNamedValue(xpathArray[p]);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
hideByXPath(newVal, xpathArray, p + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void hideForFile(const path& dir, const wstring& relativePath)
|
||||
{
|
||||
path jsonPath = dir;
|
||||
jsonPath.append(relativePath);
|
||||
auto jObject = json::from_file(jsonPath.wstring());
|
||||
if (!jObject.has_value())
|
||||
{
|
||||
wprintf(L"Can not parse file %s\n", jsonPath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
JsonValue jValue = json::value(jObject.value());
|
||||
for (auto xpath : escapeInfo[relativePath])
|
||||
{
|
||||
vector<wstring> xpathArray = getXpathArray(xpath);
|
||||
hideByXPath(jValue, xpathArray, 0);
|
||||
}
|
||||
|
||||
json::to_file(jsonPath.wstring(), jObject.value());
|
||||
}
|
||||
|
||||
bool del(wstring path)
|
||||
{
|
||||
error_code err;
|
||||
remove_all(path, err);
|
||||
if (err.value() != 0)
|
||||
{
|
||||
wprintf_s(L"Can not delete %s. Error code: %d", path.c_str(), err.value());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void hideUserPrivateInfo(const filesystem::path& dir)
|
||||
{
|
||||
// Replace data in json files
|
||||
for (auto& it : escapeInfo)
|
||||
{
|
||||
hideForFile(dir, it.first);
|
||||
}
|
||||
|
||||
// delete files
|
||||
for (auto it : filesToDelete)
|
||||
{
|
||||
auto path = dir;
|
||||
path = path.append(it);
|
||||
del(path);
|
||||
}
|
||||
}
|
||||
|
||||
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("Can not report monitor info. %s\n", ex.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
printf("Can not report monitor info\n");
|
||||
}
|
||||
}
|
||||
|
||||
void reportWindowsVersion(const filesystem::path& tmpDir)
|
||||
{
|
||||
auto versionReportPath = tmpDir;
|
||||
versionReportPath = versionReportPath.append("windows-version.txt");
|
||||
OSVERSIONINFOEXW osInfo;
|
||||
|
||||
try
|
||||
{
|
||||
NTSTATUS(WINAPI * RtlGetVersion)
|
||||
(LPOSVERSIONINFOEXW) = nullptr;
|
||||
*(FARPROC*)&RtlGetVersion = GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");
|
||||
if (RtlGetVersion)
|
||||
{
|
||||
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
|
||||
RtlGetVersion(&osInfo);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
printf("Cannot get windows version info\n");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
wofstream versionReport(versionReportPath);
|
||||
versionReport << "MajorVersion: " << osInfo.dwMajorVersion << endl;
|
||||
versionReport << "MinorVersion: " << osInfo.dwMinorVersion << endl;
|
||||
versionReport << "BuildNumber: " << osInfo.dwBuildNumber << endl;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
printf("Can not write to %s", versionReportPath.string().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t* argv[], wchar_t*)
|
||||
{
|
||||
// Get path to save zip
|
||||
wstring saveZipPath;
|
||||
if (argc > 1)
|
||||
{
|
||||
saveZipPath = argv[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t buffer[MAX_PATH];
|
||||
if (SHGetSpecialFolderPath(HWND_DESKTOP, buffer, CSIDL_DESKTOP, FALSE))
|
||||
{
|
||||
saveZipPath = buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Can not retrieve a desktop path. Error code: %d", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
auto powerToys = PTSettingsHelper::get_root_save_folder_location();
|
||||
|
||||
// Copy to a temp folder
|
||||
auto tmpDir = temp_directory_path();
|
||||
tmpDir = tmpDir.append("PowerToys\\");
|
||||
powerToys = powerToys + L"\\";
|
||||
if (!del(tmpDir))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
copy(powerToys, tmpDir, copy_options::recursive);
|
||||
// Remove updates folder contents
|
||||
del(tmpDir / "Updates");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
printf("Copy PowerToys directory failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Hide sensitive information
|
||||
hideUserPrivateInfo(tmpDir);
|
||||
|
||||
// Write monitors info to the temporary folder
|
||||
reportMonitorInfo(tmpDir);
|
||||
|
||||
// Write windows version info to the temporary folder
|
||||
reportWindowsVersion(tmpDir);
|
||||
|
||||
// Zip folder
|
||||
auto zipPath = path::path(saveZipPath);
|
||||
std::string reportFilename{"PowerToysReport_"};
|
||||
reportFilename += timeutil::format_as_local("%F-%H-%M-%S", timeutil::now());
|
||||
reportFilename += ".zip";
|
||||
zipPath /= reportFilename;
|
||||
|
||||
try
|
||||
{
|
||||
zipFolder(zipPath, tmpDir);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
printf("Zip folder failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
del(tmpDir);
|
||||
return 0;
|
||||
}
|
||||
60
tools/BugReportTool/BugReportTool/ReportMonitorInfo.cpp
Normal file
60
tools/BugReportTool/BugReportTool/ReportMonitorInfo.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#include "ReportMonitorInfo.h"
|
||||
#include <Windows.h>
|
||||
#include "../../../src/common/utils/winapi_error.h"
|
||||
|
||||
int report(std::wostream& os)
|
||||
{
|
||||
auto callback = [](HMONITOR monitor, HDC, RECT*, LPARAM prm) -> BOOL {
|
||||
std::wostream& os = *(std::wostream*)prm;
|
||||
MONITORINFOEX mi;
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (GetMonitorInfo(monitor, &mi))
|
||||
{
|
||||
os << "GetMonitorInfo OK\n";
|
||||
DISPLAY_DEVICE displayDevice = { sizeof(displayDevice) };
|
||||
|
||||
if (EnumDisplayDevices(mi.szDevice, 0, &displayDevice, 1))
|
||||
{
|
||||
if (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER)
|
||||
{
|
||||
os << "EnumDisplayDevices OK[MIRRORING_DRIVER]: \n"
|
||||
<< "\tDeviceID = " << displayDevice.DeviceID << '\n'
|
||||
<< "\tDeviceKey = " << displayDevice.DeviceKey << '\n'
|
||||
<< "\tDeviceName = " << displayDevice.DeviceName << '\n'
|
||||
<< "\tDeviceString = " << displayDevice.DeviceString << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
os << "EnumDisplayDevices OK:\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 << "EnumDisplayDevices FAILED: " << (message.has_value() ? message.value() : L"") << '\n';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto message = get_last_error_message(GetLastError());
|
||||
os << "GetMonitorInfo FAILED: " << (message.has_value() ? message.value() : L"") << '\n';
|
||||
}
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
if (EnumDisplayMonitors(nullptr, nullptr, callback, (LPARAM)&os))
|
||||
{
|
||||
os << "EnumDisplayMonitors OK\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
auto message = get_last_error_message(GetLastError());
|
||||
os << "EnumDisplayMonitors FAILED: " << (message.has_value() ? message.value() : L"") << '\n';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
4
tools/BugReportTool/BugReportTool/ReportMonitorInfo.h
Normal file
4
tools/BugReportTool/BugReportTool/ReportMonitorInfo.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <fstream>
|
||||
|
||||
int report(std::wostream& os);
|
||||
28
tools/BugReportTool/BugReportTool/ZipTools/zipfolder.cpp
Normal file
28
tools/BugReportTool/BugReportTool/ZipTools/zipfolder.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "zipfolder.h"
|
||||
#include "..\..\..\..\deps\cziplib\src\zip.h"
|
||||
|
||||
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');
|
||||
if (!zip)
|
||||
{
|
||||
printf("Can not open zip.");
|
||||
throw -1;
|
||||
}
|
||||
|
||||
using recursive_directory_iterator = std::filesystem::recursive_directory_iterator;
|
||||
const size_t rootSize = folderPath.wstring().size();
|
||||
for (const auto& dirEntry : recursive_directory_iterator(folderPath))
|
||||
{
|
||||
if (dirEntry.is_regular_file())
|
||||
{
|
||||
auto path = dirEntry.path().string();
|
||||
auto relativePath = path.substr(rootSize, path.size());
|
||||
zip_entry_open(zip, relativePath.c_str());
|
||||
zip_entry_fwrite(zip, path.c_str());
|
||||
zip_entry_close(zip);
|
||||
}
|
||||
}
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
4
tools/BugReportTool/BugReportTool/ZipTools/zipfolder.h
Normal file
4
tools/BugReportTool/BugReportTool/ZipTools/zipfolder.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
|
||||
void zipFolder(std::filesystem::path zipPath, std::filesystem::path folderPath);
|
||||
4
tools/BugReportTool/BugReportTool/packages.config
Normal file
4
tools/BugReportTool/BugReportTool/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.200729.8" targetFramework="native" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user