How close message box after closing parent process opened using CreateProcess() - c++

I want auto check bad or good for run my .exe files. For example for this binaries I have missing dll's, and when I use CreateProcess it's not return error and provide me system MessageBox("Dll is missing"). If I close it by hand, methods return exitCode STATUS_DLL_NOT_FOUND. I want that from some timeout all system message boxes will be closed with closing parent process and i can get my STATUS_DLL_NOT_FOUND. Me need full automatically work from my code.This code can closed opened sub dialogs, but can't close messageboxes.
int main()
{
HANDLE hJob;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { 0 };
hJob = CreateJobObject(NULL, NULL);
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli));
TCHAR szCmdline[] = TEXT(" -R:mm");
si.cb = sizeof(si);
CreateProcess(
executableFiles[0].c_str(),
szCmdline,
NULL,
NULL,
FALSE,
CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB /*Important*/,
NULL,
NULL,
&si,
&pi);
AssignProcessToJobObject(hJob, pi.hProcess); // Does not work if without CREATE_BREAKAWAY_FROM_JOB
ResumeThread(pi.hThread);
if (WaitForSingleObject(pi.hProcess, 3000) == WAIT_TIMEOUT)
{
EnumWindows(&SendWMCloseMsg, pi.dwProcessId);
if (WaitForSingleObject(pi.hProcess, 2000) == WAIT_TIMEOUT)
{
TerminateProcess(pi.hProcess, 0);
DWORD dwExitCode = 0;
GetExitCodeProcess(pi.hProcess, &dwExitCode);
const DWORD result = WaitForSingleObject(pi.hProcess, 2000);
if (result == WAIT_OBJECT_0)
{
if (dwExitCode == STATUS_DLL_NOT_FOUND)
{
std::cout << "Dll is missing" << std::endl;
}
}
else
{
std::cout << "bad case" << std::endl;
}
}
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(hJob);
return 0;
}

Call UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); before CreateProcess, and make sure that CREATE_DEFAULT_ERROR_MODE is not set in the dwCreationFlags parameter, so that the child process inherits the error mode of the parent. Per docs, this "does not display the critical-error-handler message box, instead, the system sends the error to the calling process".
Optionally SetErrorMode(oldErrorMode); after CreateProcess to restore the previous setting.

Related

createProcess Restart when closed/crashed

I would like to know how would i restart a program that i have created with CreateProcess.
I need the program to restart if its closed or if it crashed
int main(int argc, char* argv[])
{
HANDLE ghJob = CreateJobObject(NULL, NULL); // GLOBAL
if (ghJob == NULL)
::MessageBox(0, "Could not create job object", "TEST", MB_OK);
else {
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
// Configure all child processes associated with the job to terminate when the
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if (0 == SetInformationJobObject(ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
::MessageBox(0, "Could not SetInformationJobObject", "TEST", MB_OK);
}
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
char cmdArgs[] = "notepad.exe";
// Launch child process - example is notepad.exe
if (::CreateProcess(NULL, cmdArgs, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo)) {
::MessageBox(0, "CreateProcess succeeded.", "TEST", MB_OK);
if (ghJob) {
if (0 == AssignProcessToJobObject(ghJob, processInfo.hProcess))
::MessageBox(0, "Could not AssignProcessToObject", "TEST", MB_OK);
}
WaitForSingleObject(processInfo.hProcess, INFINITE);
//Restart process here if its closed
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
return 0;
}
You can run the code in a cycle. WaitForSingleObject waits till child process exits, CloseHandle calls are closing the handles and the child process code is running another time. I've created an eternal cycle, so this program will never exit. Add exiting conditions to this cycle according to your requirements, for example a MessageBox asking if it should exit or run another time
int main(int argc, char* argv[])
{
HANDLE ghJob = CreateJobObject(NULL, NULL); // GLOBAL
if (ghJob == NULL)
::MessageBox(0, "Could not create job object", "TEST", MB_OK);
else {
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
// Configure all child processes associated with the job to terminate when the
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if (0 == SetInformationJobObject(ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
::MessageBox(0, "Could not SetInformationJobObject", "TEST", MB_OK);
}
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
char cmdArgs[] = "notepad.exe";
// Launch child process - example is notepad.exe
do
{
if (::CreateProcess(NULL, cmdArgs, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo)) {
::MessageBox(0, "CreateProcess succeeded.", "TEST", MB_OK);
if (ghJob) {
if (0 == AssignProcessToJobObject(ghJob, processInfo.hProcess))
::MessageBox(0, "Could not AssignProcessToObject", "TEST", MB_OK);
}
WaitForSingleObject(processInfo.hProcess, INFINITE);
//Restart process here if its closed
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
} while (1);
return 0;
}

Create process without having keyboard and mouse, interaction and focus

How to create/spawn Win32 process without mouse and keyboard focus and interaction?
Can some one mentioned most appropriate Win API function to create window process without having it display as top most window ,but stay behind in other opened windows?
(Assume you have to spawn/create a process of windowed(not fullscreen) Direct3D program executable and that program terminate by parent program therfore no need of user interaction but automated therefore when it gets created it should display behind other already opened windows).
Starting a process with a inactive SW_* value is not enough but if you are the foreground window you can also call LockSetForegroundWindow to disable SetForegroundWindow:
void backgroundcalc_simple()
{
LockSetForegroundWindow(LSFW_LOCK);
ShellExecute(NULL, NULL, TEXT("Calc"), NULL, NULL, SW_SHOWNA);
// Cannot unlock here without a hacky call to Sleep
}
If your application does not need SetForegroundWindow then you don't have to unlock but it is probably a good idea to do so anyway:
BOOL CALLBACK ProcessHasVisibleWindowProc(HWND hWnd, LPARAM Param)
{
if (IsWindowVisible(hWnd) && (WS_CAPTION & GetWindowLongPtr(hWnd, GWL_STYLE)))
{
DWORD thispid, *wantedpid = (DWORD*) Param;
if (GetWindowThreadProcessId(hWnd, &thispid) && thispid == *wantedpid)
{
*wantedpid = 0;
return FALSE;
}
}
return TRUE;
}
BOOL ProcessHasVisibleWindow(DWORD Pid)
{
if (!Pid) return FALSE;
EnumWindows(ProcessHasVisibleWindowProc, (LPARAM) &Pid);
return Pid == 0;
}
BOOL WaitForVisibleProcessWindow(DWORD Pid, DWORD Timeout)
{
DWORD start = GetTickCount();
for (;;)
{
if (ProcessHasVisibleWindow(Pid)) return TRUE;
if (GetTickCount() - start >= Timeout && Timeout != INFINITE) break;
Sleep(50);
}
return FALSE;
}
void backgroundcalc()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_FORCEOFFFEEDBACK|STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNA;
WCHAR cmd[MAX_PATH];
lstrcpy(cmd, TEXT("Calc"));
LockSetForegroundWindow(LSFW_LOCK);
if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
WaitForInputIdle(pi.hProcess, 3333);
WaitForVisibleProcessWindow(pi.dwProcessId, 1000*10);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
LockSetForegroundWindow(LSFW_UNLOCK);
}

ReadConsoleInput read only first symbol after press Enter

Excuse me for my English, but I can't solve a problem. Now I am writing Remote Console. It uses QTcpSocket and functions for work with windows console. Almost work perfect, but when I try read from console I need first press Enter and only after this my first letter will read. If I want input second letter I need press Enter again. How can I read every letters that I write?
It's my constructor:
FreeConsole();
dwProcessId = 0 ;
dwErrorId = 0;
std::wstring path = L"cmd.exe";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
SECURITY_ATTRIBUTES security = {
sizeof(security), NULL, TRUE
};
if(CreateProcess(NULL, (LPWSTR)path.c_str(), NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
dwProcessId = pi.dwProcessId;
}
else
{
dwErrorId = GetLastError();
printf("CreateProcess failed (%d).\n", dwErrorId);
return;
}
Sleep(1000);
if(!AttachConsole(pi.dwProcessId))
{
dwErrorId = GetLastError();
printf( "AttachConsole failed (%d).\n", dwErrorId);
return;
}
and here function where i have a problem:
int Console::readInputFromConsole(DataIn& data)
{
data.inputRecords.resize(40);
HANDLE inputHandle = GetStdHandle(STD_INPUT_HANDLE);
DWORD events = 0;
DWORD unread = 0;
DWORD fdwMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;
//fdwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
BOOL bMode = SetConsoleMode(inputHandle, fdwMode);
if(!bMode)
{
std::runtime_error("error with mode");
}
Sleep(20);
BOOL statusUnread = TRUE;
statusUnread = GetNumberOfConsoleInputEvents(inputHandle, &unread);
if(!statusUnread)
throw std::runtime_error("GetNumberOfConsoleInputEvents failed.");
data.inputRecords.resize(unread);
BOOL statusRead = TRUE;
statusRead = ReadConsoleInput(inputHandle, &data.inputRecords[0], unread, &events);
if(!statusRead)
throw std::runtime_error("ReadConsoleInput failed.");
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &data.consoleScreenBufferInfo);
return 0;
}
I solved problem. I just created unnecessary process on a client computer. It's very stupid, but in this way I just tried to start process in new window.

How do you write to a second console?

I had the idea of using a second console in my programs for the purpose of logging programming activity. I looked around on msdn for related functions/examples and tried to put together a simple program to do so:
//function in parent that communicates with child
void writeToChild()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
HANDLE inWrite, inRead,
outWrite, outRead;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&inRead, &inWrite, &saAttr, 0))
{
exit(0xbad);
}
if ( ! SetHandleInformation(inRead, HANDLE_FLAG_INHERIT, 0) )
{
exit(0xbad);
}
if (!CreatePipe(&outRead, &outWrite, &saAttr, 0))
{
exit(0xbad);
}
if ( ! SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0) )
{
exit(0xbad);
}
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
si.lpTitle = "Log";
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = outWrite;
si.hStdError = outWrite;
si.hStdInput = inRead;
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL,
"Logger",
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi )
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
exit(0xbad);
}
unsigned long numWritten = 0;
WriteFile(inWrite, "Test", 4, &numWritten, NULL);
cout<<"wrote "<<numWritten<<" characters"<<endl;
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
//Logger
#include <windows.h>
#define BUFSIZE 4096
int main()
{
HANDLE stdin, stdout;
stdin = GetStdHandle(STD_INPUT_HANDLE);
stdout = GetStdHandle(STD_OUTPUT_HANDLE);
char buffer[BUFSIZE];
unsigned long numRead;
while (true)
{
ReadFile(stdin, buffer, BUFSIZE, &numRead, NULL);
if (numRead > 0)
WriteFile(stdout, buffer, numRead, NULL, NULL);
}
return 0;
}
The problem is that while the parent displays that 4 characters were written, nothing appears on the child console. I'm not sure how to go about debugging this because I have next to no experience with windows programming.
I am not quite sure where you are going with the separate process in your code snippet. However, you can't have more than one console associated with a single process in Windows, although you can have multiple screen buffers associated with a single console and toggle between them (see SetConsoleActiveScreenBuffer and go from there), but you'll have to implement a user-interface for that toggling; it's not a built-in thing.
If the screen buffers do not work for you, you could have a second logger process that you communicate with via pipes or loopback sockets or some other IPC method, though, e.g.:
You can use syslog, which is a common logging facility used by various applications and hardware.
You can also write to a log file and use a program to watch the file, e.g. the Windows equivalent of tail -f. This has the bonus of storing the logged data in a file for easy review later.
You could have your application act as a TCP server, telnet to it, and dump log messages via telnet.
Note that for any of the above options, as a convenience to your user, you can have your application start the second log watching process separately (with just a simple call to ShellExecute, don't go overboard).
Other options include:
You could use the Windows event log, although it can be a bit cumbersome.
You could create a separate GUI window with a text field or a list in it that displays log messages.
If your program is a GUI application that doesn't have its own console (from your description, this does not seem to be the case, but just for completeness) you can create a single console for it with AllocConsole and friends (but note that closing that console while it is still attached will also terminate your application).
There are many choices here. But you can't have two consoles for the same process.
Here is a summary of how I've managed to do it:
//parent process
YourString pipeName = format(L"\\\\.\\pipe\\%s", pName);
HANDLE hPipe = CreateNamedPipe(pipeName, /*dwOpenMode*/PIPE_ACCESS_OUTBOUND,
/*dwPipeMode*/PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
/*nMaxInstances*/PIPE_UNLIMITED_INSTANCES,
/*nOutBufferSize*/10000, /*nInBufferSize*/10000, /*nDefaultTimeOut*/50,
/*lpSecurityAttributes*/NULL);
//[check return value]
PROCESS_INFORMATION pi = {};
STARTUPINFOW si = {};
YourString commandLine = format(L"\"%s\" \"%s\"", childProcessExeFileName, pipeName);
HANDLE hProcess = CreateProcess(
/*lpApplicationName*/NULL, /*lpCommandLine*/commandLine,
/*lpProcessAttributes*/NULL, /*lpThreadAttributes*/NULL,
/*bInheritHandles*/TRUE, /*dwCreationFlags*/CREATE_NEW_CONSOLE,
/*lpEnvironment*/NULL, /*lpCurrentDirectory*/NULL,
&si, &pi);
//[check return value]
lpBuffer = ...
nNumberOfBytesToWrite = len(lpBuffer);
WriteFile(hPipe, lpBuffer, nNumberOfBytesToWrite, /*lpNumberOfBytesWritten*/NULL, /*lpOverlapped*/NULL);
//child process
int main(int argc, char ** argv) {
HANDLE hPipe = CreateFile(argv[1], GENERIC_READ, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
//[check return value]
ULONG PID;
BOOL ok = GetNamedPipeServerProcessId(hPipe, &PID);
//[check return value]
HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, PID);
//[check return value]
char buffer[1000];
DWORD nByteRead;
while (WaitForSingleObject(hProcess, 0) == WAIT_TIMEOUT) {
if (hPipe) {
ok = ReadFile(hPipe, buffer,
sizeof(buffer) - 1, &nByteRead, NULL);
buffer[nByteRead] = 0;
if (!ok) {
if (GetLastError() != ERROR_BROKEN_PIPE) ERROR();
hPipe = NULL;
}
else printf("%s", buffer);
}
else Sleep(1000);
}
return 1;
}
If you are interested I could send you a class that uses this, with a simple syntax:
WinConsole secondConsole;
secondConsole.Printf("Hello %s\n", "World");
This let you have as many consoles as you want.

How do I call ::CreateProcess in c++ to launch a Windows executable?

Looking for an example that:
Launches an EXE
Waits for the EXE to finish.
Properly closes all the handles when the executable finishes.
Something like this:
STARTUPINFO info={sizeof(info)};
PROCESS_INFORMATION processInfo;
if (CreateProcess(path, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
There is an example at http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
Just replace the argv[1] with your constant or variable containing the program.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if( argc != 2 )
{
printf("Usage: %s [cmdline]\n", argv[0]);
return;
}
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
If you application is a Windows GUI application then using the code below to do the waiting is not ideal as messages for your application will not be getting processing. To the user it will look like your application has hung.
WaitForSingleObject(&processInfo.hProcess, INFINITE)
Something like the untested code below might be better as it will keep processing the windows message queue and your application will remain responsive:
//-- wait for the process to finish
while (true)
{
//-- see if the task has terminated
DWORD dwExitCode = WaitForSingleObject(ProcessInfo.hProcess, 0);
if ( (dwExitCode == WAIT_FAILED )
|| (dwExitCode == WAIT_OBJECT_0 )
|| (dwExitCode == WAIT_ABANDONED) )
{
DWORD dwExitCode;
//-- get the process exit code
GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
//-- the task has ended so close the handle
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
//-- save the exit code
lExitCode = dwExitCode;
return;
}
else
{
//-- see if there are any message that need to be processed
while (PeekMessage(&message.msg, 0, 0, 0, PM_NOREMOVE))
{
if (message.msg.message == WM_QUIT)
{
return;
}
//-- process the message queue
if (GetMessage(&message.msg, 0, 0, 0))
{
//-- process the message
TranslateMessage(&pMessage->msg);
DispatchMessage(&pMessage->msg);
}
}
}
}
if your exe happens to be a console app, you might be interested in reading the stdout and stderr -- for that, I'll humbly refer you to this example:
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q190351
It's a bit of a mouthful of code, but I've used variations of this code to spawn and read.
On a semi-related note, if you want to start a process that has more privileges than your current process (say, launching an admin app, which requires Administrator rights, from the main app running as a normal user), you can't do so using CreateProcess() on Vista since it won't trigger the UAC dialog (assuming it is enabled). The UAC dialog is triggered when using ShellExecute(), though.
Here is a new example that works on windows 10. When using the windows10 sdk you have to use CreateProcessW instead. This example is commented and hopefully self explanatory.
#ifdef _WIN32
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <cstdlib>
#include <string>
#include <algorithm>
class process
{
public:
static PROCESS_INFORMATION launchProcess(std::string app, std::string arg)
{
// Prepare handles.
STARTUPINFO si;
PROCESS_INFORMATION pi; // The function returns this
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
//Prepare CreateProcess args
std::wstring app_w(app.length(), L' '); // Make room for characters
std::copy(app.begin(), app.end(), app_w.begin()); // Copy string to wstring.
std::wstring arg_w(arg.length(), L' '); // Make room for characters
std::copy(arg.begin(), arg.end(), arg_w.begin()); // Copy string to wstring.
std::wstring input = app_w + L" " + arg_w;
wchar_t* arg_concat = const_cast<wchar_t*>( input.c_str() );
const wchar_t* app_const = app_w.c_str();
// Start the child process.
if( !CreateProcessW(
app_const, // app path
arg_concat, // Command line (needs to include app path as first argument. args seperated by whitepace)
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
throw std::exception("Could not create child process");
}
else
{
std::cout << "[ ] Successfully launched child process" << std::endl;
}
// Return process handle
return pi;
}
static bool checkIfProcessIsActive(PROCESS_INFORMATION pi)
{
// Check if handle is closed
if ( pi.hProcess == NULL )
{
printf( "Process handle is closed or invalid (%d).\n", GetLastError());
return FALSE;
}
// If handle open, check if process is active
DWORD lpExitCode = 0;
if( GetExitCodeProcess(pi.hProcess, &lpExitCode) == 0)
{
printf( "Cannot return exit code (%d).\n", GetLastError() );
throw std::exception("Cannot return exit code");
}
else
{
if (lpExitCode == STILL_ACTIVE)
{
return TRUE;
}
else
{
return FALSE;
}
}
}
static bool stopProcess( PROCESS_INFORMATION &pi)
{
// Check if handle is invalid or has allready been closed
if ( pi.hProcess == NULL )
{
printf( "Process handle invalid. Possibly allready been closed (%d).\n");
return 0;
}
// Terminate Process
if( !TerminateProcess(pi.hProcess,1))
{
printf( "ExitProcess failed (%d).\n", GetLastError() );
return 0;
}
// Wait until child process exits.
if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_FAILED)
{
printf( "Wait for exit process failed(%d).\n", GetLastError() );
return 0;
}
// Close process and thread handles.
if( !CloseHandle( pi.hProcess ))
{
printf( "Cannot close process handle(%d).\n", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
if( !CloseHandle( pi.hThread ))
{
printf( "Cannot close thread handle (%d).\n", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
return 1;
}
};//class process
#endif //win32
Perhaps this is the most complete?
http://goffconcepts.com/techarticles/createprocess.html
Bear in mind that using WaitForSingleObject can get you into trouble in this scenario. The following is snipped from a tip on my website:
The problem arises because your application has a window but isn't pumping messages. If the spawned application invokes SendMessage with one of the broadcast targets (HWND_BROADCAST or HWND_TOPMOST), then the SendMessage won't return to the new application until all applications have handled the message - but your app can't handle the message because it isn't pumping messages.... so the new app locks up, so your wait never succeeds.... DEADLOCK.
If you have absolute control over the spawned application, then there are measures you can take, such as using SendMessageTimeout rather than SendMessage (e.g. for DDE initiations, if anybody is still using that). But there are situations which cause implicit SendMessage broadcasts over which you have no control, such as using the SetSysColors API for instance.
The only safe ways round this are:
split off the Wait into a separate thread, or
use a timeout on the Wait and use PeekMessage in your Wait loop to ensure that you pump messages, or
use the MsgWaitForMultipleObjects API.
Here is a solution for CreateProcessA
STARTUPINFOW initInfo = { 0 };
initInfo.cb = sizeof(initInfo);
PROCESS_INFORMATION procInfo = { 0 };
CreateProcessA(PATH_FOR_EXE, NULL, NULL, NULL, FALSE, 0, NULL, NULL, (LPSTARTUPINFOA)&initInfo, &procInfo);
#include <Windows.h>
void my_cmd()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// CMD command here
char arg[] = "cmd.exe /c E:/Softwares/program.exe";
// Convert char string to required LPWSTR string
wchar_t text[500];
mbstowcs(text, arg, strlen(arg) + 1);
LPWSTR command = text;
// Run process
CreateProcess (NULL, command, NULL, NULL, 0,
CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
}
This works fine for me. No popup windows and cmd command runs as expected. Just needed to convert the CHAR pointer into WCHAR pointer and add extra "cmd.exe /c" before every command.