<div dir="ltr">Hi,<div><br></div><div>I noticed a handful of differences in the "lifecycle" of named pipes between Windows and Wine, and I figured I'd post about them here.  I wrote a standalone one-file C++ program that demonstrates the differences I found.  (In that test, the pipe handles are always overlapped and PIPE_WAIT.)  I tested using wine-1.9.12.</div><div><br></div><div>The differences were:</div><div><br></div><div><div>1. With Windows, there can be multiple concurrent ConnectNamedPipe operations on a pipe.  With Wine, the second ConnectNamedPipe call fails with ERROR_INVALID_HANDLE.</div><div><br></div><div>2. With Windows, DisconnectNamedPipe aborts ConnectNamedPipe operations with the error ERROR_PIPE_NOT_CONNECTED.  The DisconnectNamedPipe call succeeds, and the pipe is no longer listening.  With Wine, the DisconnectNamedPipe call itself fails with ERROR_PIPE_LISTENING, and the pipe is still listening.</div><div><br></div><div>3. With Windows, if the server breaks the pipe by closing its handle, the client can finish reading the remaining data in the pipe.  Once the data is gone, reading from a broken pipe fails with ERROR_BROKEN_PIPE.  Writing to a broken pipe fails with ERROR_NO_DATA.  With Wine, once the server breaks the pipe, the client cannot read the remaining data, and I/O on a broken pipe fails with ERROR_PIPE_NOT_CONNECTED.  (Exception: ReadFile on a server pipe still returns ERROR_BROKEN_PIPE.)</div></div><div><br></div><div>4. Calling ConnectNamedPipe on a broken server pipe fails with ERROR_NO_DATA on Windows, but ERROR_NO_DATA_DETECTED on Wine.</div><div><br></div><div>My test program is at: <a href="https://gist.github.com/rprichard/8dd8ca134b39534b7da2733994aa07ba">https://gist.github.com/rprichard/8dd8ca134b39534b7da2733994aa07ba</a>.  It passes on XP, Vista, Win7, and Win10, with the exception of testChangeMaxInstancesAfterClosingLastServerHandle, which passes on Vista and up.  A couple of the more interesting tests are testDisconnectAtStartup and testReadFromBrokenClientPipe:</div><div><br></div><div>testDisconnectAtStartup:<br></div><div><br></div><div><div>// Calling DisconnectNamedPipe on a new pipe successfully transitions it to a</div><div>// "Not Connected" state.  The second DisconnectNamedPipe call fails, and the</div><div>// client can't connect.</div><div>void testDisconnectAtStartup() {</div><div>    const HANDLE server = assertValid(openServer(name(0)));</div><div>    CHECK_SUCCESS(DisconnectNamedPipe(server));</div><div>    CHECK(createFile(name(0)) == INVALID_HANDLE_VALUE);</div><div>    CHECK_FAILURE(DisconnectNamedPipe(server), ERROR_PIPE_NOT_CONNECTED);</div><div>    CHECK(createFile(name(0)) == INVALID_HANDLE_VALUE);</div><div>    CHECK_SUCCESS(CloseHandle(server));</div><div>}</div></div><div><br></div><div><div>// If a client pipe is broken, rather than disconnected, the remaining data can</div><div>// still be read.</div><div>void testReadFromBrokenClientPipe() {</div><div>    DWORD actual = 0;</div><div>    Over over;</div><div>    char buf[2] = {};</div><div><br></div><div>    const HANDLE server = assertValid(openServer(name(0)));</div><div>    const HANDLE client = assertValid(createFile(name(0)));</div><div>    CHECK_SUCCESS(WriteFile(server, buf, 1, &actual, &over));</div><div>    CHECK_SUCCESS(CloseHandle(server));</div><div><br></div><div>    CHECK_SUCCESS(ReadFile(client, buf, 2, &actual, &over));</div><div>    CHECK(actual == 1);</div><div>    CHECK_FAILURE(ReadFile(client, buf, 2, &actual, &over), ERROR_BROKEN_PIPE);</div><div><br></div><div>    CHECK_SUCCESS(CloseHandle(client));</div><div>}</div></div><div><br></div><div>I know that item #3 above breaks my winpty project (in principle), where a pipe server signals EOF by closing a pipe without disconnecting it.  The winpty client can read all the output before hitting the broken pipe.  I suspect winpty may not run on Wine anyway, though.</div><div><br></div><div>-Ryan</div><div><br></div></div>