Maybe Im being dense (its been a long day)

But where is pipe defined ?

       std::memcpy(&handles.Handles[1], &pipe.Write, 4);
       std::memcpy(&handles.Handles[2], &pipe.Write, 4);

-- Scott
-----Original Message-----
From: Björn Schäpers <qt-maill...@hazardy.de> 
Sent: Tuesday, March 7, 2023 12:58 PM
To: Scott Bloom <sc...@towel42.com>; interest@qt-project.org
Subject: Re: [Interest] QProcess unbuffered

So here is what I have:

struct __attribute__((packed)) HackedHandlePasser {
          using HANDLE32 = std::int32_t;

          DWORD    NumberOfHandles = 3; // 4 Byte
          BYTE     FlagsPerHandle[3];   // 3 * 1 Byte
          HANDLE32 Handles[3];          // 3 * 4 Byte
       };

       static_assert(sizeof(HackedHandlePasser) == 19);
       HackedHandlePasser handles;

       #ifndef FOPEN
#define FOPEN 0x01
       #endif
       #ifndef FDEV
#define FDEV 0x40
       #endif

       handles.FlagsPerHandle[0] = 0;
       std::memset(&handles.FlagsPerHandle[1], FOPEN | FDEV, 2);

       const HANDLE invalid = INVALID_HANDLE_VALUE;
       std::memcpy(&handles.Handles[0], &invalid, 4);
       std::memcpy(&handles.Handles[1], &pipe.Write, 4);
       std::memcpy(&handles.Handles[2], &pipe.Write, 4);

       startInf.cbReserved2 = sizeof(HackedHandlePasser);
       startInf.lpReserved2 = reinterpret_cast<LPBYTE>(&handles);

Some explanations:
* I have the HANDLE32 because I start a 32 bit application from within a 64 
bit, as far as I understood the structure needs the right HANDLE size, thus for 
a 64 bit application it should be std:int64_t, but since I don't need that I 
never tested it.
* In cbReserved2 there is the size of the data in lpReserved2.
* The data in lpReserved2 starts with 2 bytes which indicate how many handles 
are passed to the spawned process (they may be INVALID_HANDLE_VALUE). Followed 
by one byte per handle with the opened flags - and here comes the trick: If it 
has the flag FDEV the ms runtime printf assumes it writes to a console and thus 
flushes. And then followed by the handles.
* My use case needs only stdout (and I also open stderr, in my case to the same 
handle), these are the handles number 1 and 2. Number 0 would be stdin.

So when using it with QProcess I think one should copy the handles from the 
STARTUPINFOW structure into this struct, then I think the normal QIODevice 
interface should keep working. If one should clear the STARTF_USESTDHANDLES 
flag I also don't know. I stopped my experiments when I achieved success for my 
"simple" use case.

Let me know what works for you.

And last but not least some sources:
https://stackoverflow.com/questions/40965496/windows-how-to-stop-buffering-of-redirected-stdout-using-createprocess
which apparently now also has a C/C++ answer, when I needed it there was only 
the python code.
http://www.catch22.net/tuts/undocumented-createprocess does use the fields for 
some other stuff, but explains a bit of background.
https://github.com/cansou/msvcrt/blob/master/src/isatty.c One if the involved 
files to handle the input.

Kind Regards,
Björn.
_______________________________________________
Interest mailing list
Interest@qt-project.org
https://lists.qt-project.org/listinfo/interest

Reply via email to