c ++获取控制台输出而不显示控制台

时间:2015-02-16 10:40:34

标签: c++ console

在SO上有一些类似的主题,但我还没有找到我需要的所有内容。
我有以下C ++代码:

    string getConsoleOutput(string command)
    {
        string data;
        File *fp;
        char var[512];

        fp = _popen(command.c_str(), "r");
        while (fgets(var, sizeof(var), fp) != NULL)
        {
            data += var;
        }
       _pclose(fp);

       return data;
    }

问题是每次我向此功能发送控制台命令时,都会弹出命令行。

我想向控制台发送命令并获取输出,而不会看到控制台窗口。

编辑: 我尝试了libexec,但它太复杂了我的需求 我还读到了关于WinExec和CreateProcess的内容,但我还没有找到获得输出的方法

1 个答案:

答案 0 :(得分:0)

如果屏幕上有一点闪光就可以了,那么只需要包含一个隐藏窗口的命令即可。由于AFAIK Windows本身并不提供这样的命令(虽然它可能潜伏在Powershell的深处),你将不得不创建它。但那是微不足道的:

#define UNICODE
#define NOMINMAX
#include <windows.h>

auto main() -> int
{
    ShowWindow( GetConsoleWindow(), SW_HIDE );
}

我已经测试了_popen功能在隐藏窗口下正常工作。

与文档相反,它显然也适用于GUI子系统应用程序,尽管我没有测试多于dir命令。


如果闪存是不可接受的,那么您可以使用CreateProcess启动隐藏的命令解释器窗口,并使用低级Windows管道来捕获输出。

对不起,我首先在这里写了一个关于COMSPEC和GUI子系统 faux 命令解释器的建议,这个解释器在我测试它的时候起作用,但它只会涉及到上面的内容捕获命令解释器输出。即然后在主程序中使用_popen只会增加复杂性和低效率。最好直接在API级别进行。


一个例子。

免责声明:我很确定我在这里做错了,因为当命令进程终止时,管道应生成EOF,不读取任何字节。相反,ReadFile调用只会挂起,因此我必须在调用ReadFile之前添加一个非常难看的等待数据或进程终止循环。另一方面,我记得Windows有一些与管道和EOF相关的错误。所以非常肯定不是100%肯定,但我没有时间查看MS示例。

#define NOMINMAX
#define STRICT
#define UNICODE
#include <windows.h>

#include <stdexcept>
#include <stdio.h>
#include <string>
using namespace std;

auto hopefully( const bool condition ) -> bool { return condition; }
auto fail( const string& message ) -> bool { throw runtime_error( message ); }

struct Non_copyable
{
    Non_copyable& operator=( const Non_copyable& ) = delete;
    Non_copyable( const Non_copyable& ) = delete;
    Non_copyable() {}
    Non_copyable( Non_copyable&& ) {}
};

struct Process
    : Non_copyable
{
    HANDLE handle;

    ~Process() { CloseHandle( handle ); }

    Process( const HANDLE h = 0 ): handle( h ) {}
    Process( Process&& other ): handle( other.handle ) { other.handle = 0; }
};

auto environment_var( const wstring& name )
    -> wstring
{
    const DWORD buffer_size = GetEnvironmentVariable( name.c_str(), nullptr, 0 );
    hopefully( buffer_size > 0 )
        || fail( "environment_var: GetEnvironmentVariable failed 1st call." );
    wstring result( buffer_size + 1, L'#' );
    const DWORD n_characters = GetEnvironmentVariable(
        name.c_str(), &result[0], result.size()
        );
    hopefully( n_characters > 0 )
        || fail( "environment_var: GetEnvironmentVariable failed 2nd call." );
    result.resize( n_characters );      // Just for good measure.
    return result;
}

auto exit_code_of( const HANDLE process )
    -> int
{
    DWORD code = E_FAIL;
    GetExitCodeProcess( process, &code );
    return code;
}

auto has_terminated( const HANDLE process )
    -> bool
{ return exit_code_of( process ) != STILL_ACTIVE; }

auto start_command( const wstring& command, const HANDLE output_handle = INVALID_HANDLE_VALUE )
    -> Process
{
    const wstring com_spec = environment_var( L"COMSPEC" );
    wstring command_line = com_spec + L" /c " + command;    // Can not be `const`.

    STARTUPINFO params = { sizeof( STARTUPINFO ) };
    if( output_handle != INVALID_HANDLE_VALUE )
    {
        const HANDLE nul = CreateFile( L"nul", GENERIC_ALL, 0, nullptr, OPEN_EXISTING, 0, 0 );
        params.dwFlags = STARTF_USESTDHANDLES;
        params.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
        params.hStdOutput = output_handle;
        params.hStdError = GetStdHandle( STD_ERROR_HANDLE );
    }

    PROCESS_INFORMATION info = {};

    bool const process_was_created = !!CreateProcess(
        nullptr,                // LPCTSTR lpApplicationName,
        &command_line[0],       // LPTSTR lpCommandLine,
        nullptr,                // LPSECURITY_ATTRIBUTES lpProcessAttributes,
        nullptr,                // LPSECURITY_ATTRIBUTES lpThreadAttributes,
        true,                   // BOOL bInheritHandles,
        CREATE_NO_WINDOW,       // DWORD dwCreationFlags,
        nullptr,                // LPVOID lpEnvironment,
        nullptr,                // LPCTSTR lpCurrentDirectory,
        &params,                // LPSTARTUPINFO lpStartupInfo,
        &info                   // LPPROCESS_INFORMATION lpProcessInformation
        );
    if( not process_was_created ) { return 0; }
    CloseHandle( info.hThread );
    return info.hProcess;
}

auto command_result( const wstring& command )
    -> string
{
    struct Pipe
    {
        HANDLE read_handle  = 0;
        HANDLE write_handle = 0;
        ~Pipe() { CloseHandle( read_handle ); CloseHandle( write_handle ); }
    };

    Pipe pipe;
    SECURITY_ATTRIBUTES params = { sizeof( SECURITY_ATTRIBUTES ) };
    params.bInheritHandle = TRUE;
    CreatePipe( &pipe.read_handle, &pipe.write_handle, &params, 0 )
        || fail( "command_result: CreatePipe failed" );
    SetHandleInformation( pipe.read_handle, HANDLE_FLAG_INHERIT, 0 );   // Inheritance ungood.
    const Process process = { start_command( command, pipe.write_handle ) };
    if( process.handle == 0 ) { return ""; }
    string result;
    for( ;; )
    {
        // Wait for data to become available or process terminated, to avoid hanging.
        for( ;; )
        {
            DWORD n_bytes_available = 0;
            const bool ok = !!PeekNamedPipe(
                pipe.read_handle, nullptr, 0, nullptr, &n_bytes_available, nullptr
                );
            if( ok && n_bytes_available > 0 ) { break; }
            if( has_terminated( process.handle ) ) { return result; }
            Sleep( 125 );
        }
        char buffer[4096];
        DWORD n_bytes_read = 0;
        SetLastError( 0 );
        ReadFile( pipe.read_handle, buffer, sizeof( buffer ), &n_bytes_read, nullptr )
            || fail( "command_result: ReadFile failed" );
        const auto last_read_error = GetLastError();
        if( last_read_error != 0 ) { break; }
        if( n_bytes_read == 0 ) { break; }
        result.append( buffer, n_bytes_read );
    }
    return result;    
}

auto main() -> int
{
    try
    {
        const string result = command_result( L"dir *" );
        const wstring text( result.begin(), result.end() );
        MessageBox( 0, text.c_str(), L"Result:", MB_SETFOREGROUND );
        return 0;
    }
    catch( const exception& x )
    {
        MessageBoxA( 0, x.what(), "Oops, an exception", MB_ICONERROR | MB_SETFOREGROUND );
    }
    return E_FAIL;
}