winapi - Can not read from child process pipe -


i'm desperately trying create child process , redirect output new pipes , read pipes, can't work. new win32api, please nice me. :)

after having failed on using win32api "normally", created wrappers focus on finding error in logic and/or order of api calls. can find interface wrappers below. since of methods directly translate win32api calls, should (hopefully) not obstacle answering question.

i same behaviour using wrapper classes have experienced originally.

i've read lot of online resources topic , 1 says different other. 1 has been useful until https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx, information (emphasis mine):

the parent process uses opposite ends of these 2 pipes write child process's input , read child process's output. specified in startupinfo structure, these handles inheritable. however, these handles must not inherited. therefore, before creating child process, parent process uses sethandleinformation function ensure write handle child process's standard input , read handle child process's standard input cannot inherited. more information, see pipes.

before found topic , closed ends i'm not using parent process side, head readfile() blocking forever on standard output read handle of child process. now, returns pipe broken.

this how create pipes , process:

popen(const string& command, const string& args,       bool use_current_pipes = false, bool merge_stderr = true) {     bool ok = true;     _error = 0;     zeromemory(&_pi, sizeof(_pi));     startupinfo si;     zeromemory(&si, sizeof(si));     si.cb = sizeof(si);      if (!use_current_pipes) {         // create pipes standard input, output , error.         _stdin = pipe(true);         _stdout = pipe(true);         if (_stdout && merge_stderr)             _stderr = _stdout.duplicate();         else             _stderr = pipe(true);          if (_stdin && _stdout && _stderr) {             _stdin.w.setinheritable(false);             _stderr.r.setinheritable(false);             _stdout.r.setinheritable(false);              si.hstdinput = _stdin.r.get();             si.hstdoutput = _stdout.w.get();             si.hstderror = _stderr.w.get();             si.dwflags |= startf_usestdhandles;         }         else {             ok = false;         }     }     else {         si.hstdinput = getstdhandle(std_input_handle);         si.hstdoutput = getstdhandle(std_output_handle);         si.hstderror = getstdhandle(std_error_handle);         si.dwflags |= startf_usestdhandles;     }      // create process. enclose actual command in quotes.     ok = ok && createprocess(         nullptr,  // command might contain whitespace, pass quoted in arg 2 instead.         autostring("\"" + command + "\" " + args),         nullptr,  // process handle not inheritable         nullptr,  // thread handle not inheritable         true,     // handles inherited         0,        // no creation flags         nullptr,  // use parent's environment block         nullptr,  // use parent's starting directory         &si,      // pointer startupinfo         &_pi);    // pointer process_information      // went wrong? well, bad.     if (!ok) {         _error = getlasterror();     }      // close handles have been inherited child process     // , don't need access to, otherwise not     // close when child exits.     _stdin.r.close();     _stdout.w.close();     _stderr.w.close(); } 

and how read standard output (_stdout.r):

uint read(uint num_bytes, char* buffer) {     if (!_stdout.r) return 0;     dword bytes_read = 0;     if (!readfile(_stdout.r.get(), buffer, num_bytes - 1, &bytes_read, nullptr)) {         _error = getlasterror();         consoleout("[error]: readfile() : " + string::inttostring((int32) _error));         if (_error == error_broken_pipe) {             consoleout("no wait, pipe broken.");             _error = 0;  // that's fine         }         return 0;     }     buffer[bytes_read] = '\0';     return bytes_read; } 

when comment out last lines of popen constructor (closing pipe handles not used parent process) readfile() blocks forever. these lines enabled, pipe broken (the child process exits pretty quickly).

question

  • can see wrong in code/logic?
  • if not, appreciate if there complete working example of opening child process , reading output

wrapper interface

struct handle {     handle h;     explicit handle();     explicit handle(handle h);     handle(handle&& other);     handle& operator = (handle&& other);     ~handle();     void close();     handle get();     handle release();     handle duplicate(dword options = duplicate_same_access, handle src_proc = nullptr, handle dst_proc = nullptr) const;     dword getinfo() const;                        // uses gethandleinformation     void setinheritable(bool inheritable) const;  // uses sethandleinformation     bool getinheritable() const;     operator bool() const;      explicit handle(const handle&) = delete;     handle* operator = (const handle&) = delete; }; struct pipe {     handle r, w;     dword error;     explicit pipe();     explicit pipe(bool inheritable);     pipe(pipe&& other);     pipe& operator = (pipe&& other);     ~pipe();     void close();     pipe duplicate(dword options = duplicate_same_access, handle src_proc = nullptr, handle dst_proc = nullptr) const;     operator bool() const;     explicit pipe(const pipe&) = delete;     pipe* operator = (const pipe&) = delete; }; 

without using either threads or overlapped i/o, risk deadlock. child process trying read stdin or waiting space in stdout buffer can write, cannot tell which, , when choose wrong, observed behavior. blocking read on child's output means guessed wrong, , waiting input.

read raymond chen's blog article be careful when redirecting both process's stdin , stdout pipes, can deadlock linked in earlier question today. calls out horrible brokenness in same sample linked in question.


Comments

Popular posts from this blog

jquery - How do you format the date used in the popover widget title of FullCalendar? -

asp.net mvc - SSO between MVCForum and Umbraco7 -

Python Tkinter keyboard using bind -