我正在使用_popen来启动一个进程来运行一个命令并收集输出
这是我的C ++代码:
bool exec(string &cmd, string &result) { result = ""; FILE* pipe = _popen(cmd.c_str(), "rt"); if (!pipe) return(false); char buffer[128]; while(!feof(pipe)) { if(fgets(buffer, 128, pipe) != NULL) result += buffer; } _pclose(pipe); return(true); }
有没有办法做到这一点,没有一个DOS窗口打开(因为它目前在_popen声明)?
据我所知,你不能1 :你正在启动一个控制台应用程序(cmd.exe,它将运行指定的命令),并且Windows始终创建一个控制台窗口启动控制台应用程序时。
CreateProcess
,甚至可以隐藏它; 问题是, _popen
不传递这些标志,所以你必须使用Win32 API来代替_popen
来创建你的管道。 在Windows上,具有STARTUPINFO结构的CreateProcess具有dwFlags以包含STARTF_USESSHOWWINDOW。 然后将STARTUPINFO.dwFlags设置为SW_HIDE将触发控制台窗口。 示例代码(可能格式不正确,并且包含C ++和WinAPI的混合):
#include <windows.h> #include <iostream> #include <string> using std::cout; using std::endl; void printError(DWORD); int main() { STARTUPINFOA si = {0}; PROCESS_INFORMATION pi = { 0 }; si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; si.wShowWindow = SW_HIDE; BOOL result = ::CreateProcessA("c:/windows/system32/notepad.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if(result == 0) { DWORD error = ::GetLastError(); printError(error); std::string dummy; std::getline(std::cin, dummy); return error; } LPDWORD retval = new DWORD[1]; ::GetExitCodeProcess(pi.hProcess, retval); cout << "Retval: " << retval[0] << endl; delete[] retval; cout << "Press enter to continue..." << endl; std::string dummy; std::getline(std::cin, dummy); return 0; } void printError(DWORD error) { LPTSTR lpMsgBuf = nullptr; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); cout << reinterpret_cast<char*>(lpMsgBuf) << endl; LocalFree(lpMsgBuf); }
[最终编辑]
一个类似的SO问题合并了上面所说的全部内容,并且在没有控制台的情况下得到你输出的C ++ popen命令
[再次编辑]
ERK。 抱歉,我对产卵过程感到兴奋。 我重读你的q。 除了额外的窗口,你实际上正在试图获得进程的标准输出/标准错误。 我只想补充说,为了这个目的,我所有的建议都是可悲的无关紧要的。 但我会留在这里作为参考。
将帖子
没有什么好的具体原因(除了“打开”适用于Windows和Mac),我使用ShellExecute生成进程而不是CreateProcess。 我会研究以后..但这里是我的StartProcess功能。
隐藏或最小化似乎产生相同的结果。 cmd窗口的确形成了,但是它被最小化,并且不会在桌面上弹出,这可能是你的主要目标。
#if defined(PLATFORM_WIN32) #include <Windows.h> #include <shellapi.h> #elif defined(PLATFORM_OSX) #include <sys/param.h> #endif namespace LGSysUtils { // ----------------------------------------------------------------------- // pWindow : {Optional} - can be NULL // pOperation : "edit", "explore", "find", "open", "print" // pFile : url, local file to execute // pParameters : {Optional} - can be NULL otherwise a string of args to pass to pFile // pDirectory : {Optional} - set cwd for process // type : kProcessWinNormal, kProcessWinMinimized, kProcessWinMaximized, kProcessHidden // bool StartProcess(void* pWindow, const char* pOperation, const char* pFile, const char* pParameters, const char* pDirectory, LGSysUtils::eProcessWin type) { bool rc = false; #if defined(PLATFORM_WIN32) int showCmd; switch(type) { case kProcessWinMaximized: showCmd = SW_SHOWMAXIMIZED; break; case kProcessWinMinimized: showCmd = SW_SHOWMINIMIZED; break; case kProcessHidden: showCmd = SW_HIDE; break; case kProcessWinNormal: default: showCmd = SW_NORMAL; } int shellRC = (int)ShellExecute(reinterpret_cast<HWND>(pWindow), pOperation,pFile,pParameters,pDirectory,showCmd); //Returns a value greater than 32 if successful, or an error value that is less than or equal to 32 otherwise. if( shellRC > 32 ) { rc = true; } #elif defined(PLATFORM_OSX) char cmd[1024]; sprintf(cmd, "%s %s", pOperation, pFile); int sysrc = system( cmd ); dbPrintf("sysrc = %d", sysrc); rc = true; #endif return rc; } }
[和前面提到的]
如果您正在控制已启动的应用程序的源代码,则可以尝试将其添加到main.cpp的顶部(或者您已命名的任何内容)
// make this process windowless/aka no console window #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
您也可以直接将这些选项提供给链接器。 以上更容易发挥不同的构建配置imho。