Boost logo

Boost :

Subject: Re: [boost] [gsoc] Boost.Process done
From: Jeff Flinn (TriumphSprint2000_at_[hidden])
Date: 2010-08-31 09:08:37


Wolfgang Fertsak wrote:
> Hi, I ran into a problem when using the 2010 boost.process library
> within a Windows GUI application with WinMain() instead of main()
> without a console.
>
> When I construct a context object the std[in|out|err]_behavior members
> are initialized in the constructor with calls to
> behavior::inherit::create(GetStdHandle(...)), which calls
> DuplicateHandle(). DuplicateHandle() fails with error 6 (invalid handle)
> since the application has no console and an exception is thrown.
>
> So currently I don't see how I could use a context object from within a
> Windows GUI application since its constructor will always throw this
> exception.
>
> What I want to do is start a child process and read its stdout as in the
> example "Communicating with child processes".

I've run into the same problem. It points out, IMHO, a major weakness in
the design of the fundamental classes, which requires all context's to
provide stream behaviors. To work around this issue I needed to create a
null stream behavior, and a nullio_context. As in:

namespace boost {
namespace process {
namespace behavior {

class null : public stream
{
public:

     static boost::shared_ptr<null> create()
     {
         return boost::make_shared<null>();
     }
};

}}}

namespace boost {
namespace process {

struct nullio_context
{
     boost::shared_ptr<boost::process::behavior::stream> stdin_behavior;
     boost::shared_ptr<boost::process::behavior::stream> stdout_behavior;
     boost::shared_ptr<boost::process::behavior::stream> stderr_behavior;
     std::string process_name;
     std::string work_dir;
     boost::process::environment env;

     nullio_context()
     : stdin_behavior(boost::process::behavior::null::create())
     , stdout_behavior(boost::process::behavior::null::create())
     , stderr_behavior(boost::process::behavior::null::create())
     , work_dir(boost::process::self::get_work_dir())
     , env(boost::process::self::get_environment())
     {}

#if defined(BOOST_POSIX_API)
     void setup(std::vector<bool> &closeflags)
     {
     }
#elif defined(BOOST_WINDOWS_API)
     void setup(STARTUPINFOA& )
     {
     }
#endif
};
}}

These are required because create_child reaches into context and asserts
that there are instances of std in/out/err. It then directly accesses
each of these

I initially tried using the provided dummy behavior, which is a misnomer
since it actually created temporary files and streams. I was an
unhandled win32 exception when shutting down.

The funny thing is there is already a context::setup method that would -
at least on windows - allow the stream behavior to be fully
encapsulated. A context could set the handle members of STARTUPINFOA
only instantiating those boost::process::behavior::streams that are
needed. On posix, setup could do all of the dup'ing of filenumbers, as
it's called between fork and execve already.

I've got a feeling there is a much better design lurking in the existing
one, that would give a much more natural abstraction of the
posix/windows requirements.

Jeff


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk