无法使用Windows CodeBlocks / MinGW 16.01找到_popen()和_pclose()

时间:2017-09-21 12:20:19

标签: c++ mingw codeblocks popen

我尝试使用" _popen()"来编译函数。使用CodeBlocks / MinGW C ++编译器。但是,编译器无法定位该函数。我grep stdio.h头文件,找到" _popen"但是,由于ifdef的定义,它没有被选中。如何设置编译,以便它可以使用CodeBlocks编译器编译_popen,_wpopen,popen或wpopen或类似的东西?

以下是在CodeBlocks下无法编译的代码示例:

#include <cstdio>
#include <cstdlib>
#include <deque>

using namespace std;

// System(cmd) and capture output of command
int SystemCapture(string cmd, deque<string>& cmdout, int& RetCode )
{
   RetCode = 0;
   FILE* Pipe = _popen(cmd.c_str(), "rt" );
   if(!Pipe)
      return -1;

   char Buffer[128];

   while(fgets(Buffer, 128, Pipe)) {
       cmdout.push_back(Buffer);
   }

   if (feof(Pipe)) {
     RetCode =_pclose(Pipe);
     return 0;
   }
   return -2;
}

我不知道它是否有任何区别,但我的编译器标志启用了c ++ 11。

错误消息显示为_popen的原型未在头文件&#34; stdio.h&#34;中定义。但是,Microsoft文档声明这是_popen()所在的位置。这是来自Codeblocks的错误消息:

BUILD.LOG TAB的错误消息:

mingw32-g++.exe -Wall -fexceptions -g -std=c++11 -g  
    -c MyCode.cpp -o obj\Debug\MyCode.o

MyCode.cpp:270:42: error: '_popen' was not declared in this scope
    FILE* Pipe = _popen(cmd.c_str(), "rt" );
                                      ^
MyCode.cpp:281:27: error: '_pclose' was not declared in this scope
    RetCode =_pclose(Pipe);
                       ^
Process terminated with status 1 (0 minute(s), 1 second(s))
2 error(s), 0 warning(s) (0 minute(s), 1 second(s))

我尝试在#include:

下添加我自己的原型
FILE* _popen  (const char*, const char*);
int   _pclose (FILE*);

然后编译器的链接阶段失败:

undefined reference to _popen(char const*, char const*)
undefined reference to _pclose(_iobuf*)

我尝试将popen重命名为以下变体:    popen,_popen,_wpopen,wpopen

也没有幸运。

然而,如果我grep stdio.h我看到ifdef围绕着popen原型...

1 个答案:

答案 0 :(得分:0)

我无法弄清楚Codeblocks / MinGW的popen / pclose问题。所以我通过使用CreateProcess()和CreatePipe()来解决这个问题。这是对我有用的解决方案:

//C++11
#include <cstdio>
#include <iostream>
#include <windows.h>
#include <cstdint>
#include <deque>
#include <string>
#include <thread>

using namespace std;

int SystemCapture(
    string         CmdLine,    //Command Line
    string         CmdRunDir,  //set to '.' for current directory
    string&        ListStdOut, //Return List of StdOut
    string&        ListStdErr, //Return List of StdErr
    uint32_t&      RetCode)    //Return Exit Code
{
    int                  Success;
    SECURITY_ATTRIBUTES  security_attributes;
    HANDLE               stdout_rd = INVALID_HANDLE_VALUE;
    HANDLE               stdout_wr = INVALID_HANDLE_VALUE;
    HANDLE               stderr_rd = INVALID_HANDLE_VALUE;
    HANDLE               stderr_wr = INVALID_HANDLE_VALUE;
    PROCESS_INFORMATION  process_info;
    STARTUPINFO          startup_info;
    thread               stdout_thread;
    thread               stderr_thread;

    security_attributes.nLength              = sizeof(SECURITY_ATTRIBUTES);
    security_attributes.bInheritHandle       = TRUE;
    security_attributes.lpSecurityDescriptor = nullptr;

    if (!CreatePipe(&stdout_rd, &stdout_wr, &security_attributes, 0) ||
            !SetHandleInformation(stdout_rd, HANDLE_FLAG_INHERIT, 0)) {
        return -1;
    }

    if (!CreatePipe(&stderr_rd, &stderr_wr, &security_attributes, 0) ||
            !SetHandleInformation(stderr_rd, HANDLE_FLAG_INHERIT, 0)) {
        if (stdout_rd != INVALID_HANDLE_VALUE) CloseHandle(stdout_rd);
        if (stdout_wr != INVALID_HANDLE_VALUE) CloseHandle(stdout_wr);
        return -2;
    }

    ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&startup_info, sizeof(STARTUPINFO));

    startup_info.cb         = sizeof(STARTUPINFO);
    startup_info.hStdInput  = 0;
    startup_info.hStdOutput = stdout_wr;
    startup_info.hStdError  = stderr_wr;

    if(stdout_rd || stderr_rd)
        startup_info.dwFlags |= STARTF_USESTDHANDLES;

    // Make a copy because CreateProcess needs to modify string buffer
    char      CmdLineStr[MAX_PATH];
    strncpy(CmdLineStr, CmdLine.c_str(), MAX_PATH);
    CmdLineStr[MAX_PATH-1] = 0;

    Success = CreateProcess(
        nullptr,
        CmdLineStr,
        nullptr,
        nullptr,
        TRUE,
        0,
        nullptr,
        CmdRunDir.c_str(),
        &startup_info,
        &process_info
    );
    CloseHandle(stdout_wr);
    CloseHandle(stderr_wr);

    if(!Success) {
        CloseHandle(process_info.hProcess);
        CloseHandle(process_info.hThread);
        CloseHandle(stdout_rd);
        CloseHandle(stderr_rd);
        return -4;
    }
    else {
        CloseHandle(process_info.hThread);
    }

    if(stdout_rd) {
        stdout_thread=thread([&]() {
            DWORD  n;
            const size_t bufsize = 1000;
            char         buffer [bufsize];
            for(;;) {
                n = 0;
                int Success = ReadFile(
                    stdout_rd,
                    buffer,
                    (DWORD)bufsize,
                    &n,
                    nullptr
                );
                printf("STDERR: Success:%d n:%d\n", Success, (int)n);
                if(!Success || n == 0)
                    break;
                string s(buffer, n);
                printf("STDOUT:(%s)\n", s.c_str());
                ListStdOut += s;
            }
            printf("STDOUT:BREAK!\n");
        });
    }

    if(stderr_rd) {
        stderr_thread=thread([&]() {
            DWORD        n;
            const size_t bufsize = 1000;
            char         buffer [bufsize];
            for(;;) {
                n = 0;
                int Success = ReadFile(
                    stderr_rd,
                    buffer,
                    (DWORD)bufsize,
                    &n,
                    nullptr
                );
                printf("STDERR: Success:%d n:%d\n", Success, (int)n);
                if(!Success || n == 0)
                    break;
                string s(buffer, n);
                printf("STDERR:(%s)\n", s.c_str());
                ListStdOut += s;
            }
            printf("STDERR:BREAK!\n");
        });
    }

    WaitForSingleObject(process_info.hProcess,    INFINITE);
    if(!GetExitCodeProcess(process_info.hProcess, (DWORD*) &RetCode))
        RetCode = -1;

    CloseHandle(process_info.hProcess);

    if(stdout_thread.joinable())
        stdout_thread.join();

    if(stderr_thread.joinable())
        stderr_thread.join();

    CloseHandle(stdout_rd);
    CloseHandle(stderr_rd);

    return 0;
}

int main()
{
    int            rc;
    uint32_t       RetCode;
    string         ListStdOut;
    string         ListStdErr;

    cout << "STARTING.\n";

    rc = SystemCapture(
        "C:\\Windows\\System32\\ipconfig.exe",    //Command Line
        ".",                                     //CmdRunDir
        ListStdOut,                              //Return List of StdOut
        ListStdErr,                              //Return List of StdErr
        RetCode                                  //Return Exit Code
    );
    if (rc < 0) {
        cout << "ERROR: SystemCapture\n";
    }

    cout << "STDOUT:\n";
    cout << ListStdOut;

    cout << "STDERR:\n";
    cout << ListStdErr;

    cout << "Finished.\n";

    cout << "Press Enter to Continue";
    cin.ignore();

    return 0;
}

现在你可以理解为什么我担心popen不能在Codeblocks中工作。