Skip to content

Commit f059e9f

Browse files
Roveyclaude
andcommitted
fix: running installed copies are renamed aside, not deleted under their name at restart
Turning boot-apply off while the tray app runs, then on again before a restart, scheduled the new copy's deletion. Installing over a running copy failed outright. Both now rename the running file aside first. Also: the tray's stock-by-choice notice is no longer accepted from unelevated processes and is only sent after a successful reset, and the tuning lock waits briefly so the watchdog's look cannot refuse an optimize. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 8e088f7 commit f059e9f

5 files changed

Lines changed: 27 additions & 9 deletions

File tree

‎src/app/common.cpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ constexpr wchar_t kTrayWindowClass[] = L"GpuAutoOptimizerWindow";
2424
TuningLock::TuningLock() {
2525
handle_ = CreateMutexW(nullptr, FALSE, kTuningMutex);
2626
if (!handle_) return;
27-
const DWORD r = WaitForSingleObject(handle_, 0);
27+
// Not 0: tuning_in_progress() holds the mutex for an instant while it looks.
28+
const DWORD r = WaitForSingleObject(handle_, 100);
2829
owned_ = r == WAIT_OBJECT_0 || r == WAIT_ABANDONED; // abandoned: the last owner died mid-run
2930
}
3031

‎src/app/gui/main_gui.cpp‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,11 +538,13 @@ int WINAPI wWinMain(HINSTANCE inst, HINSTANCE, PWSTR cmdline, int) {
538538
const BOOL dark = TRUE; // a dark title bar to match the dark window
539539
DwmSetWindowAttribute(g.hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &dark, sizeof(dark));
540540

541-
// Explorer runs unelevated; let its tray notifications, a relaunch's
542-
// "come forward" and gao --reset's notice reach an elevated window.
541+
// Explorer runs unelevated; let its tray notifications and a relaunch's
542+
// "come forward" reach an elevated window. Not the stock-by-choice notice:
543+
// gao --reset is always elevated, and an unelevated process must not be
544+
// able to switch the watchdog off.
543545
g.taskbar_created = RegisterWindowMessageW(L"TaskbarCreated");
544546
g.stock_by_choice = gao::app::stock_by_choice_message();
545-
for (UINT m : {WM_APP_TRAY, g.taskbar_created, WM_APP_SHOW, g.stock_by_choice})
547+
for (UINT m : {WM_APP_TRAY, g.taskbar_created, WM_APP_SHOW})
546548
ChangeWindowMessageFilterEx(g.hwnd, m, MSGFLT_ALLOW, nullptr);
547549

548550
IMGUI_CHECKVERSION();

‎src/app/main.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ static int reset() {
114114
ok = ok && power_ok;
115115
}
116116
// A stock card by choice: a running tray app must not re-apply the tune.
117-
gao::app::tell_tray_stock_by_choice();
117+
if (ok) gao::app::tell_tray_stock_by_choice();
118118
std::printf("%s\n", ok ? "OK" : "MISMATCH");
119119
return ok ? 0 : 1;
120120
}

‎src/hw/boot_task.cpp‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ std::filesystem::path installed_dir() {
4040
std::filesystem::path installed_exe_path() { return installed_dir() / L"gao.exe"; }
4141
std::filesystem::path installed_tray_path() { return installed_dir() / L"GpuAutoOptimizer.exe"; }
4242

43+
namespace {
44+
// A running exe cannot be deleted or overwritten, but it can be renamed.
45+
// Moving it aside frees its name at once; the renamed file goes at the next
46+
// restart. (Deleting it under its own name at restart would also delete a
47+
// copy installed there in the meantime.)
48+
bool move_aside(const std::filesystem::path& p) {
49+
const auto aside = std::filesystem::path(p).concat(L".old-" + std::to_wstring(GetTickCount64()));
50+
if (!MoveFileExW(p.c_str(), aside.c_str(), 0)) return false;
51+
MoveFileExW(aside.c_str(), nullptr, MOVEFILE_DELAY_UNTIL_REBOOT);
52+
return true;
53+
}
54+
}
55+
4356
bool install_app(const std::filesystem::path& from_dir, std::string* why) {
4457
const auto dst = installed_dir();
4558
if (dst.empty()) { if (why) *why = "the Program Files folder could not be resolved"; return false; }
@@ -48,7 +61,8 @@ bool install_app(const std::filesystem::path& from_dir, std::string* why) {
4861
std::filesystem::create_directories(dst, ec);
4962
for (const wchar_t* name : kAppExes) {
5063
const auto src = from_dir / name;
51-
if (!CopyFileW(src.c_str(), (dst / name).c_str(), FALSE)) {
64+
const auto to = dst / name;
65+
if (!CopyFileW(src.c_str(), to.c_str(), FALSE) && !(move_aside(to) && CopyFileW(src.c_str(), to.c_str(), FALSE))) {
5266
if (why) *why = "could not copy " + src.string() + " to " + dst.string() + " (error " + std::to_string(GetLastError()) + ")";
5367
return false;
5468
}
@@ -63,7 +77,7 @@ bool uninstall_app() {
6377
for (const wchar_t* name : kAppExes) {
6478
const auto p = dst / name;
6579
if (DeleteFileW(p.c_str()) || GetLastError() == ERROR_FILE_NOT_FOUND) continue;
66-
MoveFileExW(p.c_str(), nullptr, MOVEFILE_DELAY_UNTIL_REBOOT);
80+
move_aside(p);
6781
all = false;
6882
}
6983
if (all) RemoveDirectoryW(dst.c_str()); // only succeeds when empty

‎src/hw/boot_task.hpp‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ inline constexpr const wchar_t* kAppExes[] = {L"gao.exe", L"GpuAutoOptimizer.exe
1313
std::filesystem::path installed_dir(); // %ProgramFiles%\GpuAutoOptimizer
1414
std::filesystem::path installed_exe_path(); // ...\gao.exe
1515
std::filesystem::path installed_tray_path(); // ...\GpuAutoOptimizer.exe
16-
// Copies both executables from `from_dir` into installed_dir() (overwriting);
16+
// Copies both executables from `from_dir` into installed_dir() (overwriting; a
17+
// running copy is renamed aside first);
1718
// a no-op when `from_dir` already is that folder.
1819
bool install_app(const std::filesystem::path& from_dir, std::string* why);
1920
// Removes both copies and, if empty, the folder. A copy that is running (the
20-
// tray app) is scheduled for deletion at the next restart; returns false then.
21+
// tray app) is renamed aside and deleted at the next restart; returns false then.
2122
bool uninstall_app();
2223
bool files_equal(const std::filesystem::path& a, const std::filesystem::path& b);
2324

0 commit comments

Comments
 (0)