在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的内容,但我还没有找到获得输出的方法
答案 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,
¶ms, // 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, ¶ms, 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;
}