diff --git a/src/MaaCore/Controller/Win32Controller.cpp b/src/MaaCore/Controller/Win32Controller.cpp index 0c1a89e930..c57a353b9e 100644 --- a/src/MaaCore/Controller/Win32Controller.cpp +++ b/src/MaaCore/Controller/Win32Controller.cpp @@ -135,8 +135,72 @@ bool Win32Controller::start_game(const std::string& client_type [[maybe_unused]] bool Win32Controller::stop_game(const std::string& client_type [[maybe_unused]]) { - Log.warn("stop_game is not supported on Win32Controller"); - return false; + LogTraceFunction; + + if (!m_hwnd) { + Log.info("No window handle available, game may already be closed"); + return true; + } + + HWND hwnd = static_cast(m_hwnd); + if (!IsWindow(hwnd)) { + Log.info("Invalid or stale window handle, game may already be closed, hwnd:", m_hwnd); + return true; + } + + DWORD pid = 0; + DWORD tid = GetWindowThreadProcessId(hwnd, &pid); + if (tid == 0) { + DWORD error = GetLastError(); + Log.error("Failed to get thread/process id from hwnd, hwnd:", m_hwnd, "last_error:", error); + return false; + } + + if (pid == 0) { + Log.error("Failed to get process id from hwnd, hwnd:", m_hwnd); + return false; + } + + HANDLE hProcess = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid); + if (!hProcess) { + DWORD error = GetLastError(); + Log.error("Failed to open process, pid:", pid, "last_error:", error); + return false; + } + + if (PostMessage(hwnd, WM_CLOSE, 0, 0)) { + DWORD wait_result = WaitForSingleObject(hProcess, 5000); + if (wait_result == WAIT_OBJECT_0) { + CloseHandle(hProcess); + Log.info("Game process closed gracefully, pid:", pid); + return true; + } + } + + BOOL ok = TerminateProcess(hProcess, 0); + if (!ok) { + DWORD error = GetLastError(); + CloseHandle(hProcess); + Log.error("Failed to terminate process, pid:", pid, "last_error:", error); + return false; + } + + DWORD wait_result = WaitForSingleObject(hProcess, 5000); + CloseHandle(hProcess); + + if (wait_result == WAIT_TIMEOUT) { + Log.error("Terminate process timed out, pid:", pid); + return false; + } + + if (wait_result == WAIT_FAILED) { + DWORD error = GetLastError(); + Log.error("Wait for process termination failed, pid:", pid, "last_error:", error); + return false; + } + + Log.info("Game process terminated, pid:", pid); + return true; } bool Win32Controller::click(const Point& p)