I'm working some some C++ on Windows that will allow me to launch python.exe (2.7) and interact with it using stdin, stdout, and stderr. I'm using Visual Studio 2015, Boost 1.59, and Boost Process 0.5.
I've been successful in launching python.exe by setting the command line to do something, such as "python -c "print 'hello world'", and the stdout captures "hello world".
Here's that code:
#include <boost/process.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <iostream>
#include <fstream>
namespace bp = boost::process;
namespace io = boost::iostreams;
using namespace bp;
using namespace bp::initializers;
bp::pipe create_async_pipe(std::string desc)
{
#if defined(BOOST_WINDOWS_API)
std::string name = "\\\\.\\pipe\\boost_process_async_io\\" + desc;
HANDLE handle1 = ::CreateNamedPipeA(name.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, NULL);
HANDLE handle2 = ::CreateFileA(name.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
return make_pipe(handle1, handle2);
#elif defined(BOOST_POSIX_API)
return create_pipe();
#endif
}
int main()
{
bp::pipe pIn = create_async_pipe("stdout");
//bp::pipe pOut = create_async_pipe("stdin");
{
//io::file_descriptor_sink stdout_sink("C:\\WA\\output.txt");
io::file_descriptor_sink stdout_sink(pIn.sink, io::close_handle);
//io::file_descriptor_source stdin_source(pOut.source, io::close_handle);
bp::child c = execute(
run_exe("C:\\Python27\\python.exe"),
set_cmd_line(L"python -c \"print 'hello world'\""),
bind_stdout(stdout_sink),
bind_stderr(stdout_sink)//,
//bind_stdin(stdin_source)
);
}
io::file_descriptor_source stdout_source(pIn.source, io::close_handle);
//io::file_descriptor_sink stdin_sink(pOut.sink, io::close_handle);
io::stream<io::file_descriptor_source> is(stdout_source);
//io::stream<io::file_descriptor_sink> os(stdin_sink);
//os << "print 'hello world'\r\nexit()\r\n";
std::string output;
std::getline(is, output);
std::cout << output << std::endl;
}
If I remove the set_cmd_line() or change the string to L"python", I would expect Python to launch into interactive mode, just as if I executed "python.exe" from the command line.
That code being here:
#include <boost/process.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <iostream>
#include <fstream>
namespace bp = boost::process;
namespace io = boost::iostreams;
using namespace bp;
using namespace bp::initializers;
bp::pipe create_async_pipe(std::string desc)
{
#if defined(BOOST_WINDOWS_API)
std::string name = "\\\\.\\pipe\\boost_process_async_io\\" + desc;
HANDLE handle1 = ::CreateNamedPipeA(name.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, NULL);
HANDLE handle2 = ::CreateFileA(name.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
return make_pipe(handle1, handle2);
#elif defined(BOOST_POSIX_API)
return create_pipe();
#endif
}
int main()
{
bp::pipe pIn = create_async_pipe("stdout");
//bp::pipe pOut = create_async_pipe("stdin");
{
//io::file_descriptor_sink stdout_sink("C:\\WA\\output.txt");
io::file_descriptor_sink stdout_sink(pIn.sink, io::close_handle);
//io::file_descriptor_source stdin_source(pOut.source, io::close_handle);
bp::child c = execute(
run_exe("C:\\Python27\\python.exe"),
**//set_cmd_line(L"python -c \"print 'hello world'\""),**
bind_stdout(stdout_sink),
bind_stderr(stdout_sink)//,
//bind_stdin(stdin_source)
);
}
io::file_descriptor_source stdout_source(pIn.source, io::close_handle);
//io::file_descriptor_sink stdin_sink(pOut.sink, io::close_handle);
io::stream<io::file_descriptor_source> is(stdout_source);
//io::stream<io::file_descriptor_sink> os(stdin_sink);
//os << "print 'hello world'\r\nexit()\r\n";
std::string output;
std::getline(is, output);
std::cout << output << std::endl;
}
When I run the second example, python will run just momentarily, and then close.
Some background on this program. I want to create a Python logger that reads a Python file line by line, and executes it line by line as if it's being written in the interpreter. Therefore, there will be code such as:
pyChild.waitForPrompt(); // Waits for >>>, >>?, ..., etc.
pyChild.write("print 'hello world'); // >>> print 'hello world'
std::cout << pyChild.readLine(); // hello world
I'm not tied to boost, and I have tried other options such as Poco and the MSDN Windows example here without success.
Of course, after getting the stdout/stderr piped correctly will be to get stdin working as well. I have tried to get that to work as well, but have failed.
Thanks in advance!