【发布时间】:2020-08-13 20:14:56
【问题描述】:
我从这里想出了如何使用CreateProcessAsUserA() 打开一个进程:
现在,我需要添加进程参数以正确运行程序,我的意思是像 -steam 这样的参数。
我在 Google 上找不到任何解决方案。请帮帮我。
【问题讨论】:
-
@ikegami:问题是关于 API 的。只要语言有绑定,具体的就无关紧要了。问题或其答案与调用者使用的是 C 还是 C++ 无关。
我从这里想出了如何使用CreateProcessAsUserA() 打开一个进程:
现在,我需要添加进程参数以正确运行程序,我的意思是像 -steam 这样的参数。
我在 Google 上找不到任何解决方案。请帮帮我。
【问题讨论】:
API is defined 是这样的:
BOOL CreateProcessAsUserA(
HANDLE hToken,
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
您可以将命令行添加到目标 EXE 的末尾。
因此,使用上面的示例,它看起来像这样:
rc = CreateProcessAsUserA(hUserToken, // user token
0, // app name
(LPSTR)"c:\\foo.exe -steam", // command line
0, // process attributes
0, // thread attributes
FALSE, // don't inherit handles
DETACHED_PROCESS, // flags
0, // environment block
0, // current dir
&si, // startup info
&pi);
对于lpCommandLine,此方法的“A”版本不需要是非常量,而“W”版本则需要。
如果可执行文件的路径中有空格,您需要用引号将其括起来:
(LPSTR)"\"c:\\my files\\foo.exe\" -steam"
对于如何为目标程序生成命令行存在一些困惑。为了保持 C 风格(argv[0] 是目标可执行文件的路径),你不应该使用 lpApplication 参数,如果你这样做了,你仍然希望 lpCommandLine 看起来像上面那样。
来自文档的信息:
如果lpApplicationName 和lpCommandLine 都不是NULL,则*lpApplicationName 指定要执行的模块,*lpCommandLine 指定命令行。新进程可以使用GetCommandLine 检索整个命令行。用 C 编写的控制台进程可以使用 argc 和 argv 参数来解析命令行。因为argv[0]是模块名,所以C程序员一般会重复模块名作为命令行的第一个记号。
【讨论】:
如果您发现正确引用引号很棘手,您可以创建一个函数来做到这一点。
C++17:
#include <initializer_list>
#include <string_view>
#include <utility>
// A function to prepare a commandline for execution by quoting
auto prep_cmd(std::initializer_list<std::string_view> args) {
if(args.size()==0) throw std::runtime_error("No command, no fun");
auto it = args.begin();
std::string AppName(*it); // AppName is returned unchanged
std::string CmdLine('"' + AppName + '"'); // but quoted when used in the commandline
for(++it; it != args.end(); ++it) {
CmdLine += ' ' + std::string(*it); // add argument unquoted
// CmdLine += " \"" + std::string(*it) + '"'; // or quote the argument too
}
return std::pair{AppName, CmdLine}; // return the result
}
然后调用它:
auto[AppName, CmdLine] = prep_cmd({
R"aw(C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Global Offensive\csgo.exe)aw",
"-steam"
});
使用结果:
CreateProcessAsUserA(
hToken,
AppName.c_str(), // const char*
CmdLine.data(), // char*
...
);
【讨论】:
ERROR_INVALID_HANDLE。在调用CreateProcessAsUserA 之前,您需要检查您是否从LogonUser 或DuplicateTokenEx 获得了有效句柄。 prep_cmd 返回的字符串看起来正确吗?你能把它们作为评论粘贴在这里吗?