2 * Unit tests for named pipe functions in Wine
4 * Copyright (c) 2002 Dan Kegel
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/test.h"
30 #define START_TEST(name) main(int argc, char **argv)
31 #define ok(condition, msg) assert(condition)
44 #define PIPENAME "\\\\.\\PiPe\\tests_" __FILE__
46 static void msg(const char *s)
49 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), s, strlen(s), &cbWritten, NULL);
52 void test_CreateNamedPipe(void)
56 const char obuf[] = "Bit Bucket";
61 msg("test_CreateNamedPipe starting\n");
62 /* Bad parameter checks */
63 hnp = CreateNamedPipe("not a named pipe", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
64 /* nMaxInstances */ 1,
65 /* nOutBufSize */ 1024,
66 /* nInBufSize */ 1024,
67 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
68 /* lpSecurityAttrib */ NULL);
70 if (hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) {
71 /* Is this the right way to notify user of skipped tests? */
72 ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED,
73 "CreateNamedPipe not supported on this platform, skipping tests.");
76 ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_INVALID_NAME,
77 "CreateNamedPipe should fail if name doesn't start with \\\\.\\pipe");
79 hnp = CreateNamedPipe(NULL,
80 PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
81 1, 1024, 1024, NMPWAIT_USE_DEFAULT_WAIT, NULL);
82 ok(hnp == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PATH_NOT_FOUND,
83 "CreateNamedPipe should fail if name is NULL");
85 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
86 ok(hFile == INVALID_HANDLE_VALUE
87 && GetLastError() == ERROR_FILE_NOT_FOUND,
88 "connecting to nonexistent named pipe should fail with ERROR_FILE_NOT_FOUND");
90 /* Functional checks */
92 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
93 /* nMaxInstances */ 1,
94 /* nOutBufSize */ 1024,
95 /* nInBufSize */ 1024,
96 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
97 /* lpSecurityAttrib */ NULL);
98 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
100 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
102 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed");
105 /* don't try to do i/o if one side couldn't be opened, as it hangs */
106 if (hFile != INVALID_HANDLE_VALUE) {
109 /* Make sure we can read and write a few bytes in both directions */
110 memset(ibuf, 0, sizeof(ibuf));
111 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile");
112 ok(written == sizeof(obuf), "write file len");
113 ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile");
114 ok(readden == sizeof(obuf), "read file len");
115 ok(memcmp(obuf, ibuf, written) == 0, "content check");
117 memset(ibuf, 0, sizeof(ibuf));
118 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile");
119 ok(written == sizeof(obuf), "write file len");
120 ok(ReadFile(hnp, ibuf, sizeof(obuf), &readden, NULL), "ReadFile");
121 ok(readden == sizeof(obuf), "read file len");
122 ok(memcmp(obuf, ibuf, written) == 0, "content check");
124 /* Picky conformance tests */
126 /* Verify that you can't connect to pipe again
127 * until server calls DisconnectNamedPipe+ConnectNamedPipe
128 * or creates a new pipe
129 * case 1: other client not yet closed
131 hFile2 = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
132 ok(hFile2 == INVALID_HANDLE_VALUE,
133 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
134 ok(GetLastError() == ERROR_PIPE_BUSY,
135 "connecting to named pipe before other client closes should fail with ERROR_PIPE_BUSY");
137 ok(CloseHandle(hFile), "CloseHandle");
139 /* case 2: other client already closed */
140 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
141 ok(hFile == INVALID_HANDLE_VALUE,
142 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
143 ok(GetLastError() == ERROR_PIPE_BUSY,
144 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail with ERROR_PIPE_BUSY");
146 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
148 /* case 3: server has called DisconnectNamedPipe but not ConnectNamed Pipe */
149 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
150 ok(hFile == INVALID_HANDLE_VALUE,
151 "connecting to named pipe after other client closes but before DisconnectNamedPipe should fail");
152 ok(GetLastError() == ERROR_PIPE_BUSY,
153 "connecting to named pipe after other client closes but before ConnectNamedPipe should fail with ERROR_PIPE_BUSY");
155 /* to be complete, we'd call ConnectNamedPipe here and loop,
156 * but by default that's blocking, so we'd either have
157 * to turn on the uncommon nonblocking mode, or
158 * use another thread.
162 ok(CloseHandle(hnp), "CloseHandle");
164 msg("test_CreateNamedPipe returning\n");
167 void test_CreateNamedPipe_instances_must_match(void)
171 /* Check no mismatch */
172 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
173 /* nMaxInstances */ 2,
174 /* nOutBufSize */ 1024,
175 /* nInBufSize */ 1024,
176 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
177 /* lpSecurityAttrib */ NULL);
178 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
180 hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
181 /* nMaxInstances */ 2,
182 /* nOutBufSize */ 1024,
183 /* nInBufSize */ 1024,
184 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
185 /* lpSecurityAttrib */ NULL);
186 ok(hnp2 != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
188 ok(CloseHandle(hnp), "CloseHandle");
189 ok(CloseHandle(hnp2), "CloseHandle");
191 /* Check nMaxInstances */
192 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
193 /* nMaxInstances */ 1,
194 /* nOutBufSize */ 1024,
195 /* nInBufSize */ 1024,
196 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
197 /* lpSecurityAttrib */ NULL);
198 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
201 hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
202 /* nMaxInstances */ 1,
203 /* nOutBufSize */ 1024,
204 /* nInBufSize */ 1024,
205 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
206 /* lpSecurityAttrib */ NULL);
207 ok(hnp2 == INVALID_HANDLE_VALUE
208 && GetLastError() == ERROR_PIPE_BUSY, "nMaxInstances not obeyed");
211 ok(CloseHandle(hnp), "CloseHandle");
213 /* Check PIPE_ACCESS_* */
214 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
215 /* nMaxInstances */ 2,
216 /* nOutBufSize */ 1024,
217 /* nInBufSize */ 1024,
218 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
219 /* lpSecurityAttrib */ NULL);
220 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
223 hnp2 = CreateNamedPipe(PIPENAME, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE | PIPE_WAIT,
224 /* nMaxInstances */ 1,
225 /* nOutBufSize */ 1024,
226 /* nInBufSize */ 1024,
227 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
228 /* lpSecurityAttrib */ NULL);
229 ok(hnp2 == INVALID_HANDLE_VALUE
230 && GetLastError() == ERROR_ACCESS_DENIED, "PIPE_ACCESS_* mismatch allowed");
233 ok(CloseHandle(hnp), "CloseHandle");
238 /** implementation of alarm() */
239 static DWORD CALLBACK alarmThreadMain(LPVOID arg)
241 DWORD timeout = (DWORD) arg;
242 msg("alarmThreadMain\n");
249 HANDLE hnp = INVALID_HANDLE_VALUE;
251 /** Trivial byte echo server - disconnects after each session */
252 static DWORD CALLBACK serverThreadMain1(LPVOID arg)
256 msg("serverThreadMain1 start\n");
257 /* Set up a simple echo server */
258 hnp = CreateNamedPipe(PIPENAME "serverThreadMain1", PIPE_ACCESS_DUPLEX,
259 PIPE_TYPE_BYTE | PIPE_WAIT,
260 /* nMaxInstances */ 1,
261 /* nOutBufSize */ 1024,
262 /* nInBufSize */ 1024,
263 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
264 /* lpSecurityAttrib */ NULL);
266 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
273 /* Wait for client to connect */
274 msg("Server calling ConnectNamedPipe...\n");
275 ok(ConnectNamedPipe(hnp, NULL)
276 || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe");
277 msg("ConnectNamedPipe returned.\n");
279 /* Echo bytes once */
280 memset(buf, 0, sizeof(buf));
282 msg("Server reading...\n");
283 success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
284 msg("Server done reading.\n");
285 ok(success, "ReadFile");
287 msg("Server writing...\n");
288 ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile");
289 msg("Server done writing.\n");
290 ok(written == readden, "write file len");
292 /* finish this connection, wait for next one */
293 ok(FlushFileBuffers(hnp), "FlushFileBuffers");
294 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
298 /** Trivial byte echo server - closes after each connection */
299 static DWORD CALLBACK serverThreadMain2(LPVOID arg)
304 msg("serverThreadMain2\n");
305 /* Set up a simple echo server */
306 hnp = CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
307 PIPE_TYPE_BYTE | PIPE_WAIT,
308 /* nMaxInstances */ 2,
309 /* nOutBufSize */ 1024,
310 /* nInBufSize */ 1024,
311 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
312 /* lpSecurityAttrib */ NULL);
313 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
321 /* Wait for client to connect */
322 msg("Server calling ConnectNamedPipe...\n");
323 ok(ConnectNamedPipe(hnp, NULL)
324 || GetLastError() == ERROR_PIPE_CONNECTED, "ConnectNamedPipe");
325 msg("ConnectNamedPipe returned.\n");
327 /* Echo bytes once */
328 memset(buf, 0, sizeof(buf));
330 msg("Server reading...\n");
331 success = ReadFile(hnp, buf, sizeof(buf), &readden, NULL);
332 msg("Server done reading.\n");
333 ok(success, "ReadFile");
335 msg("Server writing...\n");
336 ok(WriteFile(hnp, buf, readden, &written, NULL), "WriteFile");
337 msg("Server done writing.\n");
338 ok(written == readden, "write file len");
340 /* finish this connection, wait for next one */
341 ok(FlushFileBuffers(hnp), "FlushFileBuffers");
342 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
344 /* Set up next echo server */
346 CreateNamedPipe(PIPENAME "serverThreadMain2", PIPE_ACCESS_DUPLEX,
347 PIPE_TYPE_BYTE | PIPE_WAIT,
348 /* nMaxInstances */ 2,
349 /* nOutBufSize */ 1024,
350 /* nInBufSize */ 1024,
351 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
352 /* lpSecurityAttrib */ NULL);
354 ok(hnpNext != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
356 ok(CloseHandle(hnp), "CloseHandle");
361 /** Trivial byte echo server - uses overlapped named pipe calls */
362 static DWORD CALLBACK serverThreadMain3(LPVOID arg)
367 msg("serverThreadMain3\n");
368 /* Set up a simple echo server */
369 hnp = CreateNamedPipe(PIPENAME "serverThreadMain3", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
370 PIPE_TYPE_BYTE | PIPE_WAIT,
371 /* nMaxInstances */ 1,
372 /* nOutBufSize */ 1024,
373 /* nInBufSize */ 1024,
374 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
375 /* lpSecurityAttrib */ NULL);
376 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
378 hEvent = CreateEvent(NULL, // security attribute
379 TRUE, // manual reset event
380 FALSE, // initial state
382 ok(hEvent != NULL, "CreateEvent");
391 int letWFSOEwait = (i & 2);
392 int letGORwait = (i & 1);
395 memset(&oOverlap, 0, sizeof(oOverlap));
396 oOverlap.hEvent = hEvent;
398 /* Wait for client to connect */
399 msg("Server calling overlapped ConnectNamedPipe...\n");
400 success = ConnectNamedPipe(hnp, &oOverlap);
401 err = GetLastError();
402 ok(success || err == ERROR_IO_PENDING
403 || err == ERROR_PIPE_CONNECTED, "overlapped ConnectNamedPipe");
404 msg("overlapped ConnectNamedPipe returned.\n");
405 if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
406 ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ConnectNamedPipe");
407 success = GetOverlappedResult(hnp, &oOverlap, &dummy, letGORwait);
408 if (!letGORwait && !letWFSOEwait && !success) {
409 ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult");
410 success = GetOverlappedResult(hnp, &oOverlap, &dummy, TRUE);
412 ok(success, "GetOverlappedResult ConnectNamedPipe");
413 msg("overlapped ConnectNamedPipe operation complete.\n");
415 /* Echo bytes once */
416 memset(buf, 0, sizeof(buf));
418 msg("Server reading...\n");
419 success = ReadFile(hnp, buf, sizeof(buf), NULL, &oOverlap);
420 msg("Server ReadFile returned...\n");
421 err = GetLastError();
422 ok(success || err == ERROR_IO_PENDING, "overlapped ReadFile");
423 msg("overlapped ReadFile returned.\n");
424 if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
425 ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait ReadFile");
426 success = GetOverlappedResult(hnp, &oOverlap, &readden, letGORwait);
427 if (!letGORwait && !letWFSOEwait && !success) {
428 ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult");
429 success = GetOverlappedResult(hnp, &oOverlap, &readden, TRUE);
431 msg("Server done reading.\n");
432 ok(success, "overlapped ReadFile");
434 msg("Server writing...\n");
435 success = WriteFile(hnp, buf, readden, NULL, &oOverlap);
436 msg("Server WriteFile returned...\n");
437 err = GetLastError();
438 ok(success || err == ERROR_IO_PENDING, "overlapped WriteFile");
439 msg("overlapped WriteFile returned.\n");
440 if (!success && (err == ERROR_IO_PENDING) && letWFSOEwait)
441 ok(WaitForSingleObjectEx(hEvent, INFINITE, TRUE) == 0, "wait WriteFile");
442 success = GetOverlappedResult(hnp, &oOverlap, &written, letGORwait);
443 if (!letGORwait && !letWFSOEwait && !success) {
444 ok(GetLastError() == ERROR_IO_INCOMPLETE, "GetOverlappedResult");
445 success = GetOverlappedResult(hnp, &oOverlap, &written, TRUE);
447 msg("Server done writing.\n");
448 ok(success, "overlapped WriteFile");
449 ok(written == readden, "write file len");
451 /* finish this connection, wait for next one */
452 ok(FlushFileBuffers(hnp), "FlushFileBuffers");
453 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe");
457 static void exercizeServer(const char *pipename, HANDLE serverThread)
461 msg("exercizeServer starting\n");
462 for (i = 0; i < 8; i++) {
464 const char obuf[] = "Bit Bucket";
470 for (loop = 0; loop < 3; loop++) {
472 msg("Client connecting...\n");
473 /* Connect to the server */
474 hFile = CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0,
475 NULL, OPEN_EXISTING, 0, 0);
476 if (hFile != INVALID_HANDLE_VALUE)
478 err = GetLastError();
480 ok(err == ERROR_PIPE_BUSY || err == ERROR_FILE_NOT_FOUND, "connecting to pipe");
482 ok(err == ERROR_PIPE_BUSY, "connecting to pipe");
483 msg("connect failed, retrying\n");
486 ok(hFile != INVALID_HANDLE_VALUE, "client opening named pipe");
488 /* Make sure it can echo */
489 memset(ibuf, 0, sizeof(ibuf));
490 msg("Client writing...\n");
491 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile to client end of pipe");
492 ok(written == sizeof(obuf), "write file len");
493 msg("Client reading...\n");
494 ok(ReadFile(hFile, ibuf, sizeof(obuf), &readden, NULL), "ReadFile from client end of pipe");
495 ok(readden == sizeof(obuf), "read file len");
496 ok(memcmp(obuf, ibuf, written) == 0, "content check");
498 msg("Client closing...\n");
499 ok(CloseHandle(hFile), "CloseHandle");
502 ok(TerminateThread(serverThread, 0), "TerminateThread");
504 msg("exercizeServer returning\n");
507 void test_NamedPipe_2(void)
510 DWORD serverThreadId;
514 msg("test_NamedPipe_2 starting\n");
515 /* Set up a ten second timeout */
516 alarmThread = CreateThread(NULL, 0, alarmThreadMain, (void *) 10000, 0, &alarmThreadId);
518 /* The servers we're about to exercize do try to clean up carefully,
519 * but to reduce the change of a test failure due to a pipe handle
520 * leak in the test code, we'll use a different pipe name for each server.
524 serverThread = CreateThread(NULL, 0, serverThreadMain1, 0, 0, &serverThreadId);
525 ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread");
526 exercizeServer(PIPENAME "serverThreadMain1", serverThread);
529 serverThread = CreateThread(NULL, 0, serverThreadMain2, 0, 0, &serverThreadId);
530 ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread");
531 exercizeServer(PIPENAME "serverThreadMain2", serverThread);
534 serverThread = CreateThread(NULL, 0, serverThreadMain3, 0, 0, &serverThreadId);
535 ok(serverThread != INVALID_HANDLE_VALUE, "CreateThread");
536 exercizeServer(PIPENAME "serverThreadMain3", serverThread);
538 ok(TerminateThread(alarmThread, 0), "TerminateThread");
539 msg("test_NamedPipe_2 returning\n");
542 void test_DisconnectNamedPipe(void)
546 const char obuf[] = "Bit Bucket";
551 hnp = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_WAIT,
552 /* nMaxInstances */ 1,
553 /* nOutBufSize */ 1024,
554 /* nInBufSize */ 1024,
555 /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT,
556 /* lpSecurityAttrib */ NULL);
557 ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed");
559 ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL) == 0
560 && GetLastError() == ERROR_PIPE_LISTENING, "WriteFile to not-yet-connected pipe");
561 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
562 && GetLastError() == ERROR_PIPE_LISTENING, "ReadFile from not-yet-connected pipe");
564 hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
566 ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed");
569 /* don't try to do i/o if one side couldn't be opened, as it hangs */
570 if (hFile != INVALID_HANDLE_VALUE) {
572 /* see what happens if server calls DisconnectNamedPipe
573 * when there are bytes in the pipe
576 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile");
577 ok(written == sizeof(obuf), "write file len");
578 ok(DisconnectNamedPipe(hnp), "DisconnectNamedPipe while messages waiting");
579 ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL) == 0
580 && GetLastError() == ERROR_PIPE_NOT_CONNECTED, "WriteFile to disconnected pipe");
581 ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL) == 0
582 && GetLastError() == ERROR_PIPE_NOT_CONNECTED,
583 "ReadFile from disconnected pipe with bytes waiting");
584 ok(CloseHandle(hFile), "CloseHandle");
587 ok(CloseHandle(hnp), "CloseHandle");
593 msg("test 1 of 4:\n");
594 test_DisconnectNamedPipe();
595 msg("test 2 of 4:\n");
596 test_CreateNamedPipe_instances_must_match();
597 msg("test 3 of 4:\n");
599 msg("test 4 of 4:\n");
600 test_CreateNamedPipe();
601 msg("all tests done\n");