mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-06-07 17:42:45 +08:00
[Bug Report Tool] Report installation folder structure (#12425)
* Report installation folder structure * Hanlde case when GetModuleFileName fails * spelling * PR comments
This commit is contained in:
parent
e6ffbcf315
commit
91797669ee
5
.github/actions/spell-check/expect.txt
vendored
5
.github/actions/spell-check/expect.txt
vendored
@ -192,6 +192,7 @@ buildtools
|
||||
buildtransitive
|
||||
BValue
|
||||
bytearray
|
||||
CALG
|
||||
callbackptr
|
||||
Camer
|
||||
Cangjie
|
||||
@ -707,6 +708,7 @@ Hardlines
|
||||
HARDWAREINPUT
|
||||
hashcode
|
||||
Hashset
|
||||
HASHVAL
|
||||
hbitmap
|
||||
hbmp
|
||||
hbr
|
||||
@ -714,6 +716,8 @@ HBRBACKGROUND
|
||||
HBRUSH
|
||||
hcblack
|
||||
HCERTSTORE
|
||||
HCRYPTHASH
|
||||
HCRYPTPROV
|
||||
hcwhite
|
||||
hdc
|
||||
HDF
|
||||
@ -2214,6 +2218,7 @@ VDId
|
||||
vec
|
||||
VERBSONLY
|
||||
VERBW
|
||||
VERIFYCONTEXT
|
||||
verrsrc
|
||||
VERSIONINFO
|
||||
Versioning
|
||||
|
@ -30,7 +30,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>Wevtapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Version.lib;Wevtapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@ -38,6 +38,7 @@
|
||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EventViewer.cpp" />
|
||||
<ClCompile Include="InstallationFolder.cpp" />
|
||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="RegistryUtils.cpp" />
|
||||
@ -56,6 +57,7 @@
|
||||
<ClInclude Include="..\..\..\deps\cziplib\src\miniz.h" />
|
||||
<ClInclude Include="..\..\..\deps\cziplib\src\zip.h" />
|
||||
<ClInclude Include="EventViewer.h" />
|
||||
<ClInclude Include="InstallationFolder.h" />
|
||||
<ClInclude Include="ReportMonitorInfo.h" />
|
||||
<ClInclude Include="..\..\..\common\utils\json.h" />
|
||||
<ClInclude Include="RegistryUtils.h" />
|
||||
|
@ -13,6 +13,7 @@
|
||||
<ClCompile Include="RegistryUtils.cpp" />
|
||||
<ClCompile Include="EventViewer.cpp" />
|
||||
<ClCompile Include="XmlDocumentEx.cpp" />
|
||||
<ClCompile Include="InstallationFolder.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="ZipTools">
|
||||
@ -30,5 +31,6 @@
|
||||
<ClInclude Include="RegistryUtils.h" />
|
||||
<ClInclude Include="EventViewer.h" />
|
||||
<ClInclude Include="XmlDocumentEx.h" />
|
||||
<ClInclude Include="InstallationFolder.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
216
tools/BugReportTool/BugReportTool/InstallationFolder.cpp
Normal file
216
tools/BugReportTool/BugReportTool/InstallationFolder.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
#include "InstallationFolder.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <Windows.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
|
||||
using namespace std;
|
||||
using std::filesystem::directory_iterator;
|
||||
using std::filesystem::path;
|
||||
|
||||
wstring GetVersion(path filePath)
|
||||
{
|
||||
DWORD verHandle = 0;
|
||||
UINT size = 0;
|
||||
LPVOID lpBuffer = nullptr;
|
||||
DWORD verSize = GetFileVersionInfoSize(filePath.c_str(), &verHandle);
|
||||
wstring version = L"None";
|
||||
|
||||
if (verSize != 0)
|
||||
{
|
||||
LPSTR verData = new char[verSize];
|
||||
|
||||
if (GetFileVersionInfo(filePath.c_str(), verHandle, verSize, verData))
|
||||
{
|
||||
if (VerQueryValue(verData, L"\\", &lpBuffer, &size))
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
VS_FIXEDFILEINFO* verInfo = (VS_FIXEDFILEINFO*)lpBuffer;
|
||||
if (verInfo->dwSignature == 0xfeef04bd)
|
||||
{
|
||||
version =
|
||||
std::to_wstring((verInfo->dwFileVersionMS >> 16) & 0xffff) + L"." +
|
||||
std::to_wstring((verInfo->dwFileVersionMS >> 0) & 0xffff) + L"." +
|
||||
std::to_wstring((verInfo->dwFileVersionLS >> 16) & 0xffff) + L"." +
|
||||
std::to_wstring((verInfo->dwFileVersionLS >> 0) & 0xffff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] verData;
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
optional<path> GetRootPath()
|
||||
{
|
||||
WCHAR modulePath[MAX_PATH];
|
||||
if (!GetModuleFileName(NULL, modulePath, MAX_PATH))
|
||||
{
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
path rootPath = path(modulePath);
|
||||
rootPath = rootPath.remove_filename();
|
||||
rootPath = rootPath.append("..");
|
||||
return std::filesystem::canonical(rootPath);
|
||||
}
|
||||
|
||||
wstring GetChecksum(path filePath)
|
||||
{
|
||||
DWORD dwStatus = 0;
|
||||
BOOL bResult = FALSE;
|
||||
HCRYPTPROV hProv = 0;
|
||||
HCRYPTHASH hHash = 0;
|
||||
HANDLE hFile = NULL;
|
||||
constexpr int bufferSize = 1024;
|
||||
BYTE rgbFile[bufferSize];
|
||||
DWORD cbRead = 0;
|
||||
constexpr int md5Length = 16;
|
||||
BYTE rgbHash[md5Length];
|
||||
DWORD cbHash = 0;
|
||||
CHAR rgbDigits[] = "0123456789abcdef";
|
||||
LPCWSTR filename = filePath.c_str();
|
||||
hFile = CreateFile(filename,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_SEQUENTIAL_SCAN,
|
||||
NULL);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == hFile)
|
||||
{
|
||||
return L"CreateFile() failed. " + get_last_error_or_default(GetLastError());
|
||||
}
|
||||
|
||||
// Get handle to the crypto provider
|
||||
if (!CryptAcquireContext(&hProv,
|
||||
NULL,
|
||||
NULL,
|
||||
PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT))
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
return L"CryptAcquireContext() failed. " + get_last_error_or_default(GetLastError());
|
||||
}
|
||||
|
||||
if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
CryptReleaseContext(hProv, 0);
|
||||
return L"CryptCreateHash() failed. " + get_last_error_or_default(GetLastError());
|
||||
}
|
||||
|
||||
while (bResult = ReadFile(hFile, rgbFile, bufferSize, &cbRead, NULL))
|
||||
{
|
||||
if (0 == cbRead)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!CryptHashData(hHash, rgbFile, cbRead, 0))
|
||||
{
|
||||
CryptReleaseContext(hProv, 0);
|
||||
CryptDestroyHash(hHash);
|
||||
CloseHandle(hFile);
|
||||
return L"CryptHashData() failed. " + get_last_error_or_default(GetLastError());;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bResult)
|
||||
{
|
||||
CryptReleaseContext(hProv, 0);
|
||||
CryptDestroyHash(hHash);
|
||||
CloseHandle(hFile);
|
||||
return L"ReadFile() failed. " + get_last_error_or_default(GetLastError());;
|
||||
}
|
||||
|
||||
cbHash = md5Length;
|
||||
std::wstring result = L"";
|
||||
if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
|
||||
{
|
||||
for (DWORD i = 0; i < cbHash; i++)
|
||||
{
|
||||
result += rgbDigits[rgbHash[i] >> 4];
|
||||
result += rgbDigits[rgbHash[i] & 0xf];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wstring result = L"CryptGetHashParam() failed. " + get_last_error_or_default(GetLastError());;
|
||||
}
|
||||
|
||||
CryptDestroyHash(hHash);
|
||||
CryptReleaseContext(hProv, 0);
|
||||
CloseHandle(hFile);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
class Reporter
|
||||
{
|
||||
private:
|
||||
std::wofstream os;
|
||||
std::wofstream GetOutputStream(const path& tmpDir)
|
||||
{
|
||||
auto path = tmpDir;
|
||||
path += "installationFolderStructure.txt";
|
||||
std::wofstream os = std::wofstream(path);
|
||||
return os;
|
||||
}
|
||||
public:
|
||||
Reporter(const path& tmpDir)
|
||||
{
|
||||
os = GetOutputStream(tmpDir);
|
||||
}
|
||||
|
||||
void Report(path dirPath, int indentation = 0)
|
||||
{
|
||||
set<pair<path, bool>> paths;
|
||||
try
|
||||
{
|
||||
directory_iterator end_it;
|
||||
for (directory_iterator it(dirPath); it != end_it; ++it)
|
||||
{
|
||||
paths.insert({ it->path(), it->is_directory() });
|
||||
}
|
||||
}
|
||||
catch (filesystem::filesystem_error err)
|
||||
{
|
||||
os << err.what() << endl;
|
||||
}
|
||||
|
||||
for (auto filePair : paths)
|
||||
{
|
||||
auto filePath = filePair.first;
|
||||
auto isDirectory = filePair.second;
|
||||
|
||||
auto fileName = filePath.wstring().substr(dirPath.wstring().size() + 1);
|
||||
os << wstring(indentation, ' ') << fileName << " ";
|
||||
if (!isDirectory)
|
||||
{
|
||||
os << GetVersion(filePath) << " " << GetChecksum(filePath);
|
||||
}
|
||||
|
||||
os << endl;
|
||||
if (isDirectory)
|
||||
{
|
||||
Report(filePath, indentation + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void InstallationFolder::ReportStructure(const path& tmpDir)
|
||||
{
|
||||
auto rootPath = GetRootPath();
|
||||
if (rootPath)
|
||||
{
|
||||
Reporter(tmpDir).Report(rootPath.value());
|
||||
}
|
||||
}
|
7
tools/BugReportTool/BugReportTool/InstallationFolder.h
Normal file
7
tools/BugReportTool/BugReportTool/InstallationFolder.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
|
||||
namespace InstallationFolder
|
||||
{
|
||||
void ReportStructure(const std::filesystem::path& tmpDir);
|
||||
};
|
@ -17,6 +17,7 @@
|
||||
#include "ReportMonitorInfo.h"
|
||||
#include "RegistryUtils.h"
|
||||
#include "EventViewer.h"
|
||||
#include "InstallationFolder.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::filesystem;
|
||||
@ -298,6 +299,8 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
||||
return 1;
|
||||
}
|
||||
|
||||
InstallationFolder::ReportStructure(reportDir);
|
||||
|
||||
// Hide sensitive information
|
||||
HideUserPrivateInfo(reportDir);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user