I am trying to run a process using CreateProcess(...) and run it independently in a seperate console window.
I can achieve this using the system("...") function, but I prefer CreateProcess since it gives me the possibility to specify environment and working directory, get a handle to the process, as well as piping stdin/out when I need to.
All I find on the internet is the inverse problem, which is people having additional console windows and wanting to get rid of them! It appears it was the normal behavior in earlier versions of Windows to open and show a new console window(s)?
Right now, I am unable to get an additional window, even if I run "cmd.exe /c ..."
I tried using the STARTF_USESHOWWINDOW flag with no luck.
Has anyone had this problem?
PS.: GUI windows are shown eg. notepad.exe will appear normally.
This is my code (in essence)
PROCESS_INFORMATION processInfo;
STARTUPINFOA startupInfo;
ZeroMemory(&startupInfo,sizeof(startupInfo));
startupInfo.dwFlags |= CREATE_NEW_CONSOLE;
startupInfo.dwFlags |= DETACHED_PROCESS;
ok&=CreateProcessA( NULL,
const_cast<char*>(comand.c_str()), // safe for CreateProcessA
NULL, NULL, TRUE, NULL, NULL, NULL,
&startupInfo, &processInfo);
I'm trying to run C:/Windows/system32/cmd.exe /c help The program runs and I can read the output from a pipe. Still no window.
MSDN is really your best friend while working with Win32 API. Now, the relevant creation flags for you are the following:
(no flags set)
— the child process (the one being started with CreateProcess()
) will share the console with the parent process (the process which called CreateProcess()
).
CREATE_NEW_CONSOLE
— the child process will receive a new console, open in a new window. As the MSDN explicitly says, this flag MUST NOT be used together with DETACHED_PROCESS
! And that's exactly the flag that you want to use.
CREATE_NO_WINDOW
— the child process will receive a new console, but without any window for it. That's quite a surprising flag, so I will restate it again: the child process will have a console, to which you can write your output, from which you can try to read input, etc; this console is different from the parent process's console; this console is invisible, it has no visible window, but it exists. It's useful for, say, silently running child processes in background. Note that this flag has no effect when used with CREATE_NEW_CONSOLE
or DETACHED_PROCESS
— those flags override this one. Also keep in mind that this flag is ignored when you launch a GUI application: it won't receive an invisible console.
DETACHED_PROCESS
— the child process will not receive any console whatsoever. You must not use this flag together with CREATE_NEW_CONSOLE
.
And now a bit more about correct invocation of CreateProcess()
. First of all, you should use CreateProcessW()
. I am particularly tired of apps that can't access files in a directory named 日本語αβηλ
.
Second, even if you use the ANSI version, specify CREATE_UNICODE_ENVIRONMENT
flag if you pass NULL
for the environment. If you don't do this, PATH
may end up broken in the child process, and this bug is extremely annoying to trace down.
Third, don't const_cast<char*>command.c_str()
. Just call strdup()/wcsdup()
on it, and then free()
after the CreateProcess()
call returned. Or if you really insists on modifying command
in place, pass &command[0]
as the parameter.
Fourth, don't forget to set the size of your STARTUPINFO
structure: startupInfo.cb = sizeof(startupInfo)
. Modern Windows (XP and 7, at least) actually allow you to leave this field to be a zero without any harmful consequences, but it's a bit of a sloppy programming to rely on this.
Oh, and while we are here: you mentioned that you use CreateProcess()
because, among other things, it allows you to specify environment for the child explicitly. Well, there is a slight gotcha about lpEnvironment
parameter which is documented, but quite easily overlooked. When you specify NULL
, the child inherits the parent's environment. When you specify something non-NULL
, the parent's environment IS NOT ADDED to it. If you want to add to the parent's environment, you'd have to use GetEnvironmentStrings()
to obtain it and then explicitly tweak it.