I figured out how to open a process using CreateProcessAsUserA()
from this:
Now, I need to add process arguments to run the program correctly, I mean arguments like -steam
.
I can't find any solution to do it on Google. Please help me.
I figured out how to open a process using CreateProcessAsUserA()
from this:
Now, I need to add process arguments to run the program correctly, I mean arguments like -steam
.
I can't find any solution to do it on Google. Please help me.
The API is defined as so:
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
);
You can just tack the command line on to the end of the target EXE.
So, using the example from above, it would look like this:
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);
The "A" version of this method doesn't need to be non-const for lpCommandLine
, the "W" version, on the other hand, does.
If the path to the executable has spaces in it, you will want to surround it in quotes:
(LPSTR)"\"c:\\my files\\foo.exe\" -steam"
There was some confusion about how the commandline would be generated for the target program. To keep things C-style (argv[0]
being the path to the target executable), you should not use the lpApplication
parameter, and if you do, you would still want the lpCommandLine
to look as it does above.
Info from the docs:
If both lpApplicationName
and lpCommandLine
are non-NULL, *lpApplicationName
specifies the module to execute, and *lpCommandLine
specifies the command line. The new process can use GetCommandLine
to retrieve the entire command line. Console processes written in C can use the argc
and argv
arguments to parse the command line. Because argv[0]
is the module name, C programmers generally repeat the module name as the first token in the command line.
If you find it tricky to get the quotes right, you could create a function to do it.
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
}
Then call it:
auto[AppName, CmdLine] = prep_cmd({
R"aw(C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Global Offensive\csgo.exe)aw",
"-steam"
});
Use the result:
CreateProcessAsUserA(
hToken,
AppName.c_str(), // const char*
CmdLine.data(), // char*
...
);