首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何等待ShellExecute运行?

如何等待ShellExecute运行?
EN

Stack Overflow用户
提问于 2013-07-14 18:45:03
回答 3查看 43.1K关注 0票数 28

我已经设法在VC++中使用ShellExecute来启动一个文档。现在,我希望运行一个接收一些参数的命令行工具,并在后台运行(作为隐藏,而不是最小化),并让它阻塞我的程序流,这样我就可以等待它完成。如何修改以下命令行:

代码语言:javascript
复制
ShellExecute(NULL,"open",FULL_PATH_TO_CMD_LINE_TOOL,ARGUMENTS,NULL,SW_HIDE);

问题是,我有一个工具可以将html转换成pdf,我希望一旦这个工具完成,也就是pdf准备好了,就可以有另一个ShellExecute来查看它。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-07-14 19:26:36

有一个CodeProject article展示了如何使用ShellExecuteEx而不是ShellExecute

代码语言:javascript
复制
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);

关键点是标志SEE_MASK_NOCLOSEPROCESS,也就是as MSDN says

用于指示hProcess成员接收进程句柄。此句柄通常用于允许应用程序找出使用ShellExecuteEx创建的进程何时终止

另外,请注意:

调用应用程序负责在不再需要该句柄时将其关闭。

票数 63
EN

Stack Overflow用户

发布于 2015-04-28 02:24:52

您也可以使用CreateProcess代替ShellExecute/ShellExecuteEx。该函数包含一个cmd.exe包装器选项,返回退出代码,并返回标准输出。(包含的内容可能并不完美)。

注意:在我的使用中,我知道必须有标准输出结果,但是PeekedNamePipe函数并不总是在第一次尝试时返回字节计数,因此出现了循环。也许,有人可以解决这个问题,并发布一个修订?另外,也许应该生成一个单独返回stderr的替代版本?

代码语言:javascript
复制
#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;
}
票数 1
EN

Stack Overflow用户

发布于 2020-06-20 09:32:08

如果使用COM,则使用ShellExecuteEx有时不起作用,因此必须考虑以下备注。

由于ShellExecuteEx可以将执行委托给使用组件对象模型( COM )激活的外壳程序扩展(数据源、上下文菜单处理程序、谓词实现),因此应在调用ShellExecuteEx之前初始化COM。某些Shell扩展需要COM单线程单元(STA)类型。在这种情况下,COM应该按如下所示进行初始化:

代码语言:javascript
复制
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)

在某些情况下,ShellExecuteEx不使用这些类型的外壳扩展之一,并且这些实例根本不需要初始化COM。尽管如此,在使用此函数之前始终初始化COM是一种好的做法。

更多来自MSDN这里https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecuteexa

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17638674

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档