8

Recently boost 1.64 released, including boost::process. This provides an easy interface for starting processes. Previously I used the stand-alone version of the boost::process library (see here). This worked well. I would like to change to the new edition so I can drop the stand-alone dependency.

The API is a bit different but everything works fine, except for on thing. In the old version I was able to pass a windows-specific context object which allowed me the hide any console windows openened by the process.

boost::process::win32_context ctx;
ctx.environment = boost::process::self::get_environment();

STARTUPINFOA stup;
ZeroMemory(&stup, sizeof(stup));
stup.cb = sizeof(stup);
stup.dwFlags = STARTF_USESHOWWINDOW;
stup.wShowWindow = SW_HIDE;
ctx.startupinfo = &stup;

std::vector<std::string> args;
boost::process:child process = boost::process::win32_launch("myprogram", args, ctx);

Using the new version it looks like this:

boost::process::environment env = boost::this_process::environment();
boost::process:child process(boost::filesystem::path("myprogram"), env);

Everything works fine except for hiding the console window. Is it possible to achieve this?

Aart Stuurman
  • 3,188
  • 4
  • 26
  • 44

2 Answers2

10

child constructor accepts a list of types that will be later converted using fancy ::boost::fusion methods into chain of calls performing actual initializations. So you can just push arguments of supported kind in any order:

#include <boost/process.hpp>
#include <boost/process/windows.hpp> // for windows::hide that can only be used on Windows

...

::boost::process::environment env = ::boost::this_process::environment();
::boost::process::child ch1("cmd", env, ::boost::process::windows::hide); // ok
::boost::process::child ch2(::boost::filesystem::path("C:\\Windows\\System32\\cmd.exe"), ::boost::process::windows::hide, env); // fine too

Hiding window conditionally is not that straightforward though because windows::hide and windows::show are of different types and can not be passed at the same function parameter. In this case it is required to write custom setup handler:

struct show_window
:   ::boost::process::detail::handler_base
{
    private: ::boost::detail::winapi::WORD_ const m_flag;

    public: explicit
    show_window(bool const show) noexcept
    :   m_flag{show ? ::boost::detail::winapi::SW_SHOWNORMAL_ : ::boost::detail::winapi::SW_HIDE_}
    {}

    // this function will be invoked at child process constructor before spawning process
    template <class WindowsExecutor>
    void on_setup(WindowsExecutor &e) const
    {
        // we have a chance to adjust startup info
        e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESHOWWINDOW_;
        e.startup_info.wShowWindow |= m_flag;
    }
};

auto const need_to_show{false};
auto env{::boost::this_process::environment()};
::boost::process::child ch("cmd", env, show_window{need_to_show});
user7860670
  • 35,849
  • 4
  • 58
  • 84
  • 1
    That is so much nicer than the old library! – Aart Stuurman Apr 24 '17 at 08:46
  • 1
    Note that - in principle - the setups/error/success handlers can be expected to be invoked in (reverse) order. That is, unless the library or extension specifically overrides that logic for some critical internal logic. – sehe Apr 24 '17 at 09:52
  • @VTT: How can one handle this if he gets a boolean (`bShowWindow`) to conditionnaly set SW_HIDE or SW_SHOW? I tried `(bShowWindow) ? ::boost::process::windows::show : ::boost::process::windows::hide` but it does not compile as a `child` construction argument... – jpo38 Dec 04 '17 at 10:14
  • @VTT: Great, thanks! By the way, if you know if/how the same approach could conditionnally set other paramaters such as stream redirection, you may try to answer this question: https://stackoverflow.com/q/47630796/3336423 – jpo38 Dec 05 '17 at 07:14
4

user7860670's answer is correct, but I like create_no_window better.

::boost::process::child ch1("myApp.exe", ::boost::process::windows::create_no_window); 

If you don't need the window throughout, you do not need to create it at all.

Zhang
  • 3,030
  • 2
  • 14
  • 31