Skip to content
4 changes: 2 additions & 2 deletions docs/en_us/2.2-IntegratedInterfaceOverview.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,15 +441,15 @@ Asynchronously input text. This is an asynchronous operation that immediately re

- `intent`: Target app
- Adb Controller: package name or activity
- Win32 Controller: not supported yet
- Win32 Controller: path or command of the executable

Asynchronously start app. This is an asynchronous operation that immediately returns an operation id. You can query the status via `MaaControllerStatus` and `MaaControllerWait`.

### MaaControllerPostStopApp

- `intent`: Target app
- Adb Controller: package name
- Win32 Controller: not supported yet
- Win32 Controller: process name (optional), default to the associated window process

Asynchronously stop app. This is an asynchronous operation that immediately returns an operation id. You can query the status via `MaaControllerStatus` and `MaaControllerWait`.

Expand Down
4 changes: 2 additions & 2 deletions docs/zh_cn/2.2-集成接口一览.md
Original file line number Diff line number Diff line change
Expand Up @@ -441,15 +441,15 @@

- `intent`: 目标应用
- Adb 控制器:package name 或 activity
- Win32 控制器:暂不支持
- Win32 控制器:执行文件的路径或命令

异步启动应用。这是一个异步操作,会立即返回一个操作 id,可通过 `MaaControllerStatus` 和 `MaaControllerWait` 查询状态。

### MaaControllerPostStopApp

- `intent`: 目标应用
- Adb 控制器:package name
- Win32 控制器:暂不支持
- Win32 控制器:进程名称(可选),预设为关联的视窗进程

异步关闭应用。这是一个异步操作,会立即返回一个操作 id,可通过 `MaaControllerStatus` 和 `MaaControllerWait` 查询状态。

Expand Down
143 changes: 137 additions & 6 deletions source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include "MaaFramework/MaaMsg.h"
#include "MaaUtils/Logger.h"
#include "MaaUtils/Time.hpp"
#include "MaaUtils/Encoding.h"

#include <tlhelp32.h>

#include "Input/BackgroundManagedKeyInput.h"
#include "Input/LegacyEventInput.h"
Expand Down Expand Up @@ -247,18 +250,146 @@ MaaControllerFeature Win32ControlUnitMgr::get_features() const

bool Win32ControlUnitMgr::start_app(const std::string& intent)
{
// TODO
std::ignore = intent;
LogFunc << VAR(intent);

if (intent.empty()) {
LogError << "intent is empty";
return false;
}

return false;
std::wstring cmd = MAA_NS::to_u16(intent);

STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));

if (CreateProcessW(nullptr, cmd.data(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) {
LogInfo << "CreateProcessW succeeded, PID:" << pi.dwProcessId;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return true;
}

DWORD err = GetLastError();
if (err != ERROR_ELEVATION_REQUIRED) {
LogError << "CreateProcessW failed, error:" << err;
return false;
}
LogInfo << "Elevation required. Falling back to ShellExecuteExW...";
std::wstring file = cmd;
std::wstring args;
// Parse
if (cmd[0] == L'\"') {
auto pos = cmd.find(L'\"', 1);
if (pos == std::wstring::npos) {
LogError << "Mismatched quotes in command, cannot parse file and arguments";
return false;
}
file = cmd.substr(1, pos - 1);
if (pos + 1 < cmd.length()) {
args = cmd.substr(pos + 1);
args.erase(0, args.find_first_not_of(L" \t"));
}
} else if (auto pos = cmd.find(L' '); pos != std::wstring::npos) {
file = cmd.substr(0, pos);
args = cmd.substr(pos + 1);
args.erase(0, args.find_first_not_of(L" \t"));
}
// execute
SHELLEXECUTEINFOW sei = { sizeof(sei) };
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
sei.lpVerb = L"runas";
sei.lpFile = file.c_str();
sei.lpParameters = args.empty() ? nullptr : args.c_str();
sei.nShow = SW_SHOWNORMAL;
if (!ShellExecuteExW(&sei)) {
LogError << "ShellExecuteExW failed, error:" << GetLastError();
return false;
}
LogInfo << "ShellExecuteExW succeeded.";
if (sei.hProcess) {
CloseHandle(sei.hProcess);
}
return true;
}

bool Win32ControlUnitMgr::stop_app(const std::string& intent)
{
// TODO
std::ignore = intent;
LogFunc << VAR(intent);

if (intent.empty()) {
if (!hwnd_ || !IsWindow(hwnd_)) {
LogError << "hwnd_ is invalid and intent is empty";
return false;
}

DWORD processId = 0;
GetWindowThreadProcessId(hwnd_, &processId);
if (processId == 0) {
LogError << "GetWindowThreadProcessId failed, error:" << GetLastError();
return false;
}

HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, processId);
if (!hProcess) {
LogError << "OpenProcess failed, error:" << GetLastError();
return false;
}

if (!TerminateProcess(hProcess, 0)) {
LogError << "TerminateProcess failed, error:" << GetLastError();
CloseHandle(hProcess);
return false;
}

CloseHandle(hProcess);
LogInfo << "Process" << processId << "terminated successfully by hwnd";
return true;
}

std::wstring target_exe = MAA_NS::to_u16(intent);
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE) {
LogError << "CreateToolhelp32Snapshot failed, error:" << GetLastError();
return false;
}

PROCESSENTRY32W pe;
pe.dwSize = sizeof(pe);
bool terminated_any = false;
Comment thread
sourcery-ai[bot] marked this conversation as resolved.

if (!Process32FirstW(hSnap, &pe)) {
LogError << "Process32FirstW failed, error:" << GetLastError();
CloseHandle(hSnap);
return false;
}

do {
if (target_exe != pe.szExeFile) {
continue;
}

HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID);
if (!hProcess) {
LogError << "OpenProcess failed for PID" << pe.th32ProcessID << "error:" << GetLastError();
continue;
}

if (TerminateProcess(hProcess, 0)) {
LogInfo << "Process" << pe.th32ProcessID << "terminated successfully by intent matching";
terminated_any = true;
} else {
LogError << "TerminateProcess failed for PID" << pe.th32ProcessID << "error:" << GetLastError();
}

CloseHandle(hProcess);

} while (Process32NextW(hSnap, &pe));
CloseHandle(hSnap);

return false;
return terminated_any;
}

bool Win32ControlUnitMgr::screencap(cv::Mat& image)
Expand Down
Loading