mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01: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:
5
.github/actions/spell-check/expect.txt
vendored
5
.github/actions/spell-check/expect.txt
vendored
@@ -192,6 +192,7 @@ buildtools
|
|||||||
buildtransitive
|
buildtransitive
|
||||||
BValue
|
BValue
|
||||||
bytearray
|
bytearray
|
||||||
|
CALG
|
||||||
callbackptr
|
callbackptr
|
||||||
Camer
|
Camer
|
||||||
Cangjie
|
Cangjie
|
||||||
@@ -707,6 +708,7 @@ Hardlines
|
|||||||
HARDWAREINPUT
|
HARDWAREINPUT
|
||||||
hashcode
|
hashcode
|
||||||
Hashset
|
Hashset
|
||||||
|
HASHVAL
|
||||||
hbitmap
|
hbitmap
|
||||||
hbmp
|
hbmp
|
||||||
hbr
|
hbr
|
||||||
@@ -714,6 +716,8 @@ HBRBACKGROUND
|
|||||||
HBRUSH
|
HBRUSH
|
||||||
hcblack
|
hcblack
|
||||||
HCERTSTORE
|
HCERTSTORE
|
||||||
|
HCRYPTHASH
|
||||||
|
HCRYPTPROV
|
||||||
hcwhite
|
hcwhite
|
||||||
hdc
|
hdc
|
||||||
HDF
|
HDF
|
||||||
@@ -2214,6 +2218,7 @@ VDId
|
|||||||
vec
|
vec
|
||||||
VERBSONLY
|
VERBSONLY
|
||||||
VERBW
|
VERBW
|
||||||
|
VERIFYCONTEXT
|
||||||
verrsrc
|
verrsrc
|
||||||
VERSIONINFO
|
VERSIONINFO
|
||||||
Versioning
|
Versioning
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<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>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="EventViewer.cpp" />
|
<ClCompile Include="EventViewer.cpp" />
|
||||||
|
<ClCompile Include="InstallationFolder.cpp" />
|
||||||
<ClCompile Include="ReportMonitorInfo.cpp" />
|
<ClCompile Include="ReportMonitorInfo.cpp" />
|
||||||
<ClCompile Include="Main.cpp" />
|
<ClCompile Include="Main.cpp" />
|
||||||
<ClCompile Include="RegistryUtils.cpp" />
|
<ClCompile Include="RegistryUtils.cpp" />
|
||||||
@@ -56,6 +57,7 @@
|
|||||||
<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="EventViewer.h" />
|
<ClInclude Include="EventViewer.h" />
|
||||||
|
<ClInclude Include="InstallationFolder.h" />
|
||||||
<ClInclude Include="ReportMonitorInfo.h" />
|
<ClInclude Include="ReportMonitorInfo.h" />
|
||||||
<ClInclude Include="..\..\..\common\utils\json.h" />
|
<ClInclude Include="..\..\..\common\utils\json.h" />
|
||||||
<ClInclude Include="RegistryUtils.h" />
|
<ClInclude Include="RegistryUtils.h" />
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<ClCompile Include="RegistryUtils.cpp" />
|
<ClCompile Include="RegistryUtils.cpp" />
|
||||||
<ClCompile Include="EventViewer.cpp" />
|
<ClCompile Include="EventViewer.cpp" />
|
||||||
<ClCompile Include="XmlDocumentEx.cpp" />
|
<ClCompile Include="XmlDocumentEx.cpp" />
|
||||||
|
<ClCompile Include="InstallationFolder.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="ZipTools">
|
<Filter Include="ZipTools">
|
||||||
@@ -30,5 +31,6 @@
|
|||||||
<ClInclude Include="RegistryUtils.h" />
|
<ClInclude Include="RegistryUtils.h" />
|
||||||
<ClInclude Include="EventViewer.h" />
|
<ClInclude Include="EventViewer.h" />
|
||||||
<ClInclude Include="XmlDocumentEx.h" />
|
<ClInclude Include="XmlDocumentEx.h" />
|
||||||
|
<ClInclude Include="InstallationFolder.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</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 "ReportMonitorInfo.h"
|
||||||
#include "RegistryUtils.h"
|
#include "RegistryUtils.h"
|
||||||
#include "EventViewer.h"
|
#include "EventViewer.h"
|
||||||
|
#include "InstallationFolder.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace std::filesystem;
|
using namespace std::filesystem;
|
||||||
@@ -298,6 +299,8 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstallationFolder::ReportStructure(reportDir);
|
||||||
|
|
||||||
// Hide sensitive information
|
// Hide sensitive information
|
||||||
HideUserPrivateInfo(reportDir);
|
HideUserPrivateInfo(reportDir);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user