mirror of
https://github.com/microsoft/PowerToys
synced 2025-08-24 19:17:39 +00:00
## Summary of the Pull Request Removes all C++/CX code, replacing it with C++/WinRT. ## Detailed Description of the Pull Request / Additional comments Removes all C++/CX code. Renames interop namespaces to be better consumed by CsWinRT. Standardizes all projects on net8.0-windows10.0.20348.0, which is a requirement for C++/WinRT usage. FileLocksmithLibInterop brought to stdcpplatest and static analysis errors were corrected. Removed now unneeded string conversion code from FileLocksmithLibInterop. Changed interop KeyboardHook to use a single hook across all instances. Required because on C++/WinRT we don't have the .NET runtime to bind a object instance to a delegate and be able to pass it to a C function pointer argument (still no idea why this worked correctly on C++/CX to be honest). This change actually makes us create less low level keyboard hooks. Changed some code that depended on arrays since WinRT/C++ returns null instead of an empty array through the interface. ## Validation Steps Performed Built and tested runtime.
130 lines
3.8 KiB
C++
130 lines
3.8 KiB
C++
#include "pch.h"
|
|
|
|
#include "FileLocksmith.h"
|
|
#include "NtdllExtensions.h"
|
|
|
|
static bool is_directory(const std::wstring path)
|
|
{
|
|
DWORD attributes = GetFileAttributesW(path.c_str());
|
|
return attributes != INVALID_FILE_ATTRIBUTES && attributes & FILE_ATTRIBUTE_DIRECTORY;
|
|
}
|
|
|
|
// C++20 method
|
|
static constexpr bool starts_with(std::wstring_view whole, std::wstring_view part)
|
|
{
|
|
return whole.size() >= part.size() && whole.substr(0, part.size()) == part;
|
|
}
|
|
|
|
std::vector<ProcessResult> find_processes_recursive(const std::vector<std::wstring>& paths)
|
|
{
|
|
NtdllExtensions nt_ext;
|
|
|
|
// TODO use a trie!
|
|
|
|
// This maps kernel names of files within `paths` to their normal paths.
|
|
std::map<std::wstring, std::wstring> kernel_names_files;
|
|
|
|
// This maps kernel names of directories within `paths` to their normal paths.
|
|
std::map<std::wstring, std::wstring> kernel_names_dirs;
|
|
|
|
for (const auto& path : paths)
|
|
{
|
|
auto kernel_path = nt_ext.path_to_kernel_name(path.c_str());
|
|
if (!kernel_path.empty())
|
|
{
|
|
(is_directory(path) ? kernel_names_dirs : kernel_names_files)[kernel_path] = path;
|
|
}
|
|
}
|
|
|
|
std::map<ULONG_PTR, std::set<std::wstring>> pid_files;
|
|
|
|
// Returns a normal path of the file specified by kernel_name, if it matches
|
|
// the search criteria. Otherwise, return an empty string.
|
|
auto kernel_paths_contain = [&](const std::wstring& kernel_name) -> std::wstring
|
|
{
|
|
// Normal equivalence
|
|
if (auto it = kernel_names_files.find(kernel_name); it != kernel_names_files.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
if (auto it = kernel_names_dirs.find(kernel_name); it != kernel_names_dirs.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
for (const auto& [dir_kernel_name, dir_path] : kernel_names_dirs)
|
|
{
|
|
if (starts_with(kernel_name, dir_kernel_name + (dir_kernel_name.length()>0&&dir_kernel_name[dir_kernel_name.length()-1]!=L'\\' ? L"\\" : L"")))
|
|
{
|
|
return dir_path + kernel_name.substr(dir_kernel_name.size());
|
|
}
|
|
}
|
|
|
|
return {};
|
|
};
|
|
|
|
for (const auto& handle_info : nt_ext.handles())
|
|
{
|
|
if (handle_info.type_name == L"File")
|
|
{
|
|
auto path = kernel_paths_contain(handle_info.kernel_file_name);
|
|
if (!path.empty())
|
|
{
|
|
pid_files[handle_info.pid].insert(std::move(path));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check all modules used by processes
|
|
auto processes = nt_ext.processes();
|
|
|
|
for (const auto& process : processes)
|
|
{
|
|
for (const auto& path : process.modules)
|
|
{
|
|
auto kernel_name = nt_ext.path_to_kernel_name(path.c_str());
|
|
|
|
auto found_path = kernel_paths_contain(kernel_name);
|
|
if (!found_path.empty())
|
|
{
|
|
pid_files[process.pid].insert(std::move(found_path));
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<ProcessResult> result;
|
|
|
|
for (const auto& process_info : processes)
|
|
{
|
|
if (auto it = pid_files.find(process_info.pid); it != pid_files.end())
|
|
{
|
|
result.push_back(ProcessResult
|
|
{
|
|
process_info.name,
|
|
process_info.pid,
|
|
process_info.user,
|
|
std::vector(it->second.begin(), it->second.end())
|
|
});
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
constexpr size_t LongMaxPathSize = 65536;
|
|
|
|
std::wstring pid_to_full_path(DWORD pid)
|
|
{
|
|
HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
|
|
|
|
std::wstring result(LongMaxPathSize, L'\0');
|
|
|
|
// Returns zero on failure, so it's okay to resize to zero.
|
|
auto length = GetModuleFileNameExW(process, NULL, result.data(), static_cast<DWORD>(result.size()));
|
|
result.resize(length);
|
|
|
|
CloseHandle(process);
|
|
return result;
|
|
}
|