win-icon: no more visible pre-icon duplicate next to the exe
This commit is contained in:
parent
ff669422b3
commit
a5805ef440
1 changed files with 73 additions and 11 deletions
|
|
@ -141,22 +141,70 @@ struct GrpIconDir {
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
// The renamed-aside original exe (still the locked running image) cannot be
|
||||||
|
// deleted from this process. Hand it to a detached waiter that deletes it
|
||||||
|
// the moment this process exits (clean exit or crash), so a freshly
|
||||||
|
// deployed exe does not leave a .pre-icon copy sitting next to it between
|
||||||
|
// runs. The next-run cleanup in EnsureExeIconResource stays as the backstop
|
||||||
|
// if the helper never gets to run.
|
||||||
|
void SpawnPreIconDeleter(const std::filesystem::path& pre) {
|
||||||
|
// PowerShell single-quoted literal: double any embedded single quotes.
|
||||||
|
std::wstring esc;
|
||||||
|
for (wchar_t c : pre.wstring()) {
|
||||||
|
esc += c;
|
||||||
|
if (c == L'\'') {
|
||||||
|
esc += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::wstring cmd =
|
||||||
|
L"powershell.exe -NoProfile -WindowStyle Hidden -Command "
|
||||||
|
L"\"Wait-Process -Id " +
|
||||||
|
std::to_wstring(GetCurrentProcessId()) +
|
||||||
|
L" -ErrorAction SilentlyContinue; Remove-Item -LiteralPath '" + esc +
|
||||||
|
L"' -Force -ErrorAction SilentlyContinue\"";
|
||||||
|
std::vector<wchar_t> mutable_cmd(cmd.begin(), cmd.end());
|
||||||
|
mutable_cmd.push_back(L'\0');
|
||||||
|
STARTUPINFOW si{};
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
PROCESS_INFORMATION pi{};
|
||||||
|
if (CreateProcessW(nullptr, mutable_cmd.data(), nullptr, nullptr, FALSE,
|
||||||
|
CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi)) {
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// One-time self-patch: write RT_ICON entries + a MAINICON RT_GROUP_ICON into
|
// One-time self-patch: write RT_ICON entries + a MAINICON RT_GROUP_ICON into
|
||||||
// the exe file. The running image is write-locked but RENAMABLE: patch a
|
// the exe file. The running image is write-locked but RENAMABLE: patch a
|
||||||
// copy, then swap it into place. The renamed original stays locked until
|
// copy, then swap it into place. The renamed original stays locked until
|
||||||
// exit and is deleted by the NEXT (already-patched) run.
|
// exit; a detached helper deletes it at process exit (next run = backstop).
|
||||||
void EnsureExeIconResource(const std::vector<uint8_t>& png) {
|
void EnsureExeIconResource(const std::vector<uint8_t>& png) {
|
||||||
wchar_t exe_w[MAX_PATH];
|
wchar_t exe_w[MAX_PATH];
|
||||||
if (GetModuleFileNameW(nullptr, exe_w, MAX_PATH) == 0) {
|
if (GetModuleFileNameW(nullptr, exe_w, MAX_PATH) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const std::filesystem::path exe(exe_w);
|
const std::filesystem::path exe(exe_w);
|
||||||
const std::filesystem::path pre = exe.wstring() + L".pre-icon";
|
const std::filesystem::path pre_local = exe.wstring() + L".pre-icon";
|
||||||
|
wchar_t temp_dir[MAX_PATH];
|
||||||
|
const bool have_temp = GetTempPathW(MAX_PATH, temp_dir) != 0;
|
||||||
if (FindResourceW(GetModuleHandleW(nullptr), L"MAINICON",
|
if (FindResourceW(GetModuleHandleW(nullptr), L"MAINICON",
|
||||||
reinterpret_cast<LPCWSTR>(RT_GROUP_ICON)) != nullptr) {
|
reinterpret_cast<LPCWSTR>(RT_GROUP_ICON)) != nullptr) {
|
||||||
// Already patched (or a build that ships an icon): just clean up any
|
// Already patched (or a build that ships an icon): backstop-sweep any
|
||||||
// leftover pre-patch original from the run that performed the swap.
|
// leftover pre-patch original the exit-time deleter didn't get to:
|
||||||
DeleteFileW(pre.c_str());
|
// the exe-adjacent legacy name and the temp-dir parking spots (a
|
||||||
|
// still-running other instance's parked file just fails the delete).
|
||||||
|
DeleteFileW(pre_local.c_str());
|
||||||
|
if (have_temp) {
|
||||||
|
WIN32_FIND_DATAW fd;
|
||||||
|
const std::wstring pattern = std::wstring(temp_dir) + L"skate3-pre-icon-*.old";
|
||||||
|
HANDLE find = FindFirstFileW(pattern.c_str(), &fd);
|
||||||
|
if (find != INVALID_HANDLE_VALUE) {
|
||||||
|
do {
|
||||||
|
DeleteFileW((std::wstring(temp_dir) + fd.cFileName).c_str());
|
||||||
|
} while (FindNextFileW(find, &fd));
|
||||||
|
FindClose(find);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,20 +283,34 @@ void EnsureExeIconResource(const std::vector<uint8_t>& png) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Swap: rename the (locked but renamable) running exe aside, move the
|
// Swap: rename the (locked but renamable) running exe aside, move the
|
||||||
// patched copy into place. On the second step failing, restore.
|
// patched copy into place. On the second step failing, restore. Parking
|
||||||
|
// spot: %TEMP% (a locked image can be renamed anywhere on the same
|
||||||
|
// volume, metadata-only op), so no duplicate ever shows up next to the
|
||||||
|
// exe; falls back to exe-adjacent when temp is on another volume.
|
||||||
|
std::filesystem::path pre =
|
||||||
|
have_temp ? std::filesystem::path(std::wstring(temp_dir) +
|
||||||
|
L"skate3-pre-icon-" +
|
||||||
|
std::to_wstring(GetCurrentProcessId()) +
|
||||||
|
L".old")
|
||||||
|
: pre_local;
|
||||||
if (!MoveFileExW(exe.c_str(), pre.c_str(), MOVEFILE_REPLACE_EXISTING)) {
|
if (!MoveFileExW(exe.c_str(), pre.c_str(), MOVEFILE_REPLACE_EXISTING)) {
|
||||||
REXLOG_INFO("win-icon: could not move running exe aside ({}); skipping",
|
pre = pre_local;
|
||||||
GetLastError());
|
if (!MoveFileExW(exe.c_str(), pre.c_str(), MOVEFILE_REPLACE_EXISTING)) {
|
||||||
DeleteFileW(temp.c_str());
|
REXLOG_INFO("win-icon: could not move running exe aside ({}); skipping",
|
||||||
return;
|
GetLastError());
|
||||||
|
DeleteFileW(temp.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!MoveFileW(temp.c_str(), exe.c_str())) {
|
if (!MoveFileW(temp.c_str(), exe.c_str())) {
|
||||||
MoveFileW(pre.c_str(), exe.c_str());
|
MoveFileW(pre.c_str(), exe.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
SetFileAttributesW(pre.c_str(), FILE_ATTRIBUTE_HIDDEN);
|
||||||
|
SpawnPreIconDeleter(pre);
|
||||||
REXLOG_INFO(
|
REXLOG_INFO(
|
||||||
"win-icon: Explorer icon patched into {} from the game's own art "
|
"win-icon: Explorer icon patched into {} from the game's own art "
|
||||||
"(one-time; {} removed on next launch)",
|
"(one-time; {} removed when this process exits)",
|
||||||
exe.filename().string(), pre.filename().string());
|
exe.filename().string(), pre.filename().string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue