visual-c++ - sintaxis - shellexecute vba
¿Cómo esperar a que ShellExecute se ejecute? (2)
Logré usar ShellExecute en VC ++ para lanzar un documento. Ahora deseo ejecutar una herramienta de línea de comandos que recibe algunos argumentos, y ejecutarla en segundo plano (como oculta, no minimizada) y dejar que bloquee el flujo de mi programa, de modo que pueda esperar a que termine. Cómo alterar la línea de comandos de:
ShellExecute(NULL,"open",FULL_PATH_TO_CMD_LINE_TOOL,ARGUMENTS,NULL,SW_HIDE);
El problema es que tengo una herramienta que convierte html a pdf, y deseo que una vez que la herramienta haya terminado, también conocido como pdf, tenga otro ShellExecute para verlo.
Hay un artículo de CodeProject que muestra cómo, usando ShellExecuteEx
lugar de ShellExecute
:
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = "c://MyProgram.exe";
ShExecInfo.lpParameters = "";
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
CloseHandle(ShExecInfo.hProcess);
El punto crucial es la bandera SEE_MASK_NOCLOSEPROCESS
, que, como dice MSDN
Se usa para indicar que el miembro hProcess recibe el identificador de proceso. Este identificador se usa normalmente para permitir que una aplicación descubra cuándo finaliza un proceso creado con
ShellExecuteEx
Además, tenga en cuenta que:
La aplicación que realiza la llamada es responsable de cerrar el identificador cuando ya no se necesita.
También puede usar CreateProcess en lugar de ShellExecute / ShellExecuteEx. Esta función incluye una opción de contenedor cmd.exe, que devuelve el código de salida y devuelve stdout. (Los incluidos pueden no ser perfectos).
Notas: En mi uso, sabía que tenía que haber resultados stdout, pero la función PeekedNamePipe no siempre devolvería el recuento de bytes en el primer intento, por lo tanto, el bucle allí. Tal vez, alguien puede resolver esto y publicar una revisión? Además, ¿tal vez debería producirse una versión alternativa que devuelva stderr por separado?
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <Shellapi.h>
/*
Note:
The exitCode for a "Cmd Process" is not the exitCode
for a sub process launched from it! That can be retrieved
via the errorlevel variable in the command line like so:
set errorlevel=&[launch command]&echo.&echo exitCode=%errorlevel%&echo.
The stdOut vector will then contain the exitCode on a seperate line
*/
BOOL executeCommandLine( const CStringW &command,
DWORD &exitCode,
const BOOL asCmdProcess=FALSE,
std::vector<CStringW> *stdOutLines=NULL )
{
// Init return values
BOOL bSuccess = FALSE;
exitCode = 0;
if( stdOutLines ) stdOutLines->clear();
// Optionally prepend cmd.exe to command line to execute
CStringW cmdLine( (asCmdProcess ? L"cmd.exe /C " : L"" ) +
command );
// Create a pipe for the redirection of the STDOUT
// of a child process.
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
bSuccess = CreatePipe( &g_hChildStd_OUT_Rd,
&g_hChildStd_OUT_Wr, &saAttr, 0);
if( !bSuccess ) return bSuccess;
bSuccess = SetHandleInformation( g_hChildStd_OUT_Rd,
HANDLE_FLAG_INHERIT, 0 );
if( !bSuccess ) return bSuccess;
// Setup the child process to use the STDOUT redirection
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Execute a synchronous child process & get exit code
bSuccess = CreateProcess( NULL,
cmdLine.GetBuffer(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent''s environment
NULL, // use parent''s current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo ); // receives PROCESS_INFORMATION
if( !bSuccess ) return bSuccess;
WaitForSingleObject( piProcInfo.hProcess, (DWORD)(-1L) );
GetExitCodeProcess( piProcInfo.hProcess, &exitCode );
CloseHandle( piProcInfo.hProcess );
CloseHandle( piProcInfo.hThread );
// Return if the caller is not requesting the stdout results
if( !stdOutLines ) return TRUE;
// Read the data written to the pipe
DWORD bytesInPipe = 0;
while( bytesInPipe==0 ){
bSuccess = PeekNamedPipe( g_hChildStd_OUT_Rd, NULL, 0, NULL,
&bytesInPipe, NULL );
if( !bSuccess ) return bSuccess;
}
if( bytesInPipe == 0 ) return TRUE;
DWORD dwRead;
CHAR *pipeContents = new CHAR[ bytesInPipe ];
bSuccess = ReadFile( g_hChildStd_OUT_Rd, pipeContents,
bytesInPipe, &dwRead, NULL);
if( !bSuccess || dwRead == 0 ) return FALSE;
// Split the data into lines and add them to the return vector
std::stringstream stream( pipeContents );
std::string str;
while( getline( stream, str ) )
stdOutLines->push_back( CStringW( str.c_str() ) );
return TRUE;
}