Как мне вызвать ::CreateProcess на c ++ для запуска исполняемого файла Windows?
Вопрос
Ищете пример, который:
- Запускает исполняемый файл
- Ожидает завершения выполнения EXE-файла.
- Правильно закрывает все дескрипторы, когда исполняемый файл завершается.
Решение
Что - то вроде этого:
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);
}
Другие советы
Есть пример по адресу http://msdn.microsoft.com/en-us/library/ms682512 (ПРОТИВ 85).aspx
Просто замените argv[1]
с вашей константой или переменной, содержащей программу.
#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 );
}
Если ваше приложение является приложением с графическим интерфейсом Windows, то использование приведенного ниже кода для выполнения ожидания не идеально, так как сообщения для вашего приложения не будут обрабатываться.Для пользователя это будет выглядеть так, как будто ваше приложение зависло.
WaitForSingleObject(&processInfo.hProcess, INFINITE)
Что-то вроде непроверенный приведенный ниже код может быть лучше, поскольку он будет продолжать обрабатывать очередь сообщений Windows, и ваше приложение останется отзывчивым:
//-- 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);
}
}
}
}
если ваш exe-файл является консольным приложением, вам может быть интересно ознакомиться с stdout и stderr - для этого я скромно отсылаю вас к этому примеру:
http://support.microsoft.com/default.aspx?scid=kb ; RU-США;q190351
Это немного перегруженный код, но я использовал вариации этого кода для создания и чтения.
В связи с этим, если вы хотите запустить процесс, который имеет больше привилегий, чем ваш текущий процесс (скажем, запустить приложение администратора, для которого требуются права администратора, из основного приложения, запущенного от имени обычного пользователя), вы не можете сделать это с помощью CreateProcess() в Vista, поскольку это не вызовет диалоговое окно UAC (при условии, что оно включено).Однако диалоговое окно UAC запускается при использовании ShellExecute().
Может быть, это самый полный?http://goffconcepts.com/techarticles/development/cpp/createprocess.html
Имейте в виду, что использование WaitForSingleObject
при таком раскладе у вас могут возникнуть неприятности.Следующее взято из подсказки на моем веб-сайте:
Проблема возникает из-за того, что ваше приложение имеет окно, но не перекачивает сообщения.Если созданное приложение вызывает SendMessage с одним из целевых объектов широковещательной рассылки (HWND_BROADCAST - ТРАНСЛЯЦИЯ или HWND_TOPМОСТ), тогда отправленное сообщение не вернется в новое приложение до тех пор, пока все приложения не обработают сообщение, но ваше приложение не может обработать сообщение, потому что оно не перекачивает сообщения....таким образом, новое приложение блокируется, так что ваше ожидание никогда не увенчается успехом....ТУПИК.
Если у вас есть абсолютный контроль над созданным приложением, то вы можете предпринять некоторые меры, такие как использование SendMessageTimeout вместо SendMessage (напримердля инициализации DDE, если кто-то все еще этим пользуется).Но есть ситуации, которые вызывают неявные широковещательные рассылки SendMessage, над которыми вы не имеете никакого контроля, например, с помощью SetSysColors API.
Единственными безопасными способами обойти это являются:
- разделите ожидание на отдельный поток, или
- установите тайм-аут для ожидания и используйте PeekMessage в цикле ожидания, чтобы гарантировать перекачку сообщений, или
- используйте
MsgWaitForMultipleObjects
API.
Вот новый пример, который работает в Windows 10.При использовании windows10 sdk вы должны вместо этого использовать CreateProcessW.Этот пример прокомментирован и, надеюсь, не требует пояснений.
#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