sheredom / subprocess.h

🐜 single header process launching solution for C and C++
The Unlicense
1.1k stars 97 forks source link

Windows subprocess_stdin and subprocess_option_enable_async? #74

Closed g40 closed 1 year ago

g40 commented 1 year ago

Hello.

A question:

For a complete ready to bake example see final code block. Short story, using the handle returned from subprocess_stdin(&process);, a call like int ret = fputs(text.c_str(), p_stdin); always returns 0, as does the subsequent subprocess_read_stdout().

Any thoughts on this? Have I missed something in the documentation?

And a suggestion:

subprocess_read_stdout() blocks. On Windows, at least, it can be made non-blocking by changing the last argument to 0. Might this not be made an optional argument?

Many thanks.

   // Means we've got an async read!
    if (error == errorIoPending) {
      if (!GetOverlappedResult(handle,
                               SUBPROCESS_PTR_CAST(LPOVERLAPPED, &overlapped),
                               &bytes_read, 0)) { // changed from 1 (wait) to 0 (don't wait)
        const unsigned long errorIoIncomplete = 996;
        const unsigned long errorHandleEOF = 38;
        error = GetLastError();

Built with cl main.cpp in a VS2022 command shell.

#include <iostream>
#include <sstream>
#include "subprocess.h"

int main(int argc,char* argv[])
{
    int ret = -1;
    try
    {
        struct subprocess_s process { 0 };
        // run a basic shell
        //const char* command_line[] = { "cmd.exe", "/K", nullptr};
        //const char* command_line[] = { "cmd.exe", "/K r:\\apps\\mingw\\msys\\1.0\\bin\\ls.exe -als", nullptr};
        const char* command_line[] = { "cmd.exe", "/K ls.exe -als", nullptr}; // this correctly says ls.exe cannot be found so is alive
        //const char* command_line[] = { "cmd.exe", "/K", "echo %path%", nullptr };
        int result = subprocess_create(command_line,
            subprocess_option_combined_stdout_stderr |
            subprocess_option_no_window |
            subprocess_option_enable_async,
            &process);
        if (0 != result) {
            // an error occurred!
        }

        // hack for the moment.
        _sleep(1000);

        char buffer[255];
        int chars = 0;
        do
        {
            // modified to NOT block
            chars = subprocess_read_stdout(&process, buffer, 254);
            if (chars)
            {
                buffer[chars] = '\0';
                std::cout << buffer;
            }
        } while (chars > 0);

        while (true)
        {
            std::string text;
            std::getline(std::cin, text);

            FILE* p_stdin = subprocess_stdin(&process);
            int ret = fputs(text.c_str(), p_stdin);
            std::cout << "Wrote " << ret << std::endl;
            if (ret)
            {
                do
                {
                    chars = subprocess_read_stdout(&process, buffer, 254);
                    if (chars)
                    {
                        buffer[chars] = '\0';
                        std::cout << buffer;
                    }
                } while (chars > 0);
            }
        }

        //
        result = subprocess_destroy(&process);
        if (0 != result) {
            // an error occurred!
        }

        ret = 0;
    }
    catch (std::exception& ex)
    {
        std::cout << "exception: " << ex.what();
    }
    catch (...)
    {
        std::cout << "unknown exception.";
    }
    return ret;
}
g40 commented 1 year ago

Requires a more complex solution sadly. Thank you.

sheredom commented 1 year ago

On holiday right now so didn't get a chance to look at this sorry!