:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / lib / kernel32 / file / npipe.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS system libraries
5  * FILE:            lib/kernel32/file/npipe.c
6  * PURPOSE:         Directory functions
7  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
8  * UPDATE HISTORY:
9  */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <ntdll/rtl.h>
15 #include <windows.h>
16 #include <kernel32/error.h>
17 //#include <wchar.h>
18 //#include <string.h>
19 #include <limits.h>
20 #include <napi/npipe.h>
21
22 //#define NDEBUG
23 #include <kernel32/kernel32.h>
24
25 /* FUNCTIONS ****************************************************************/
26
27 HANDLE STDCALL
28 CreateNamedPipeA(LPCSTR lpName,
29                  DWORD dwOpenMode,
30                  DWORD dwPipeMode,
31                  DWORD nMaxInstances,
32                  DWORD nOutBufferSize,
33                  DWORD nInBufferSize,
34                  DWORD nDefaultTimeOut,
35                  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
36 {
37    HANDLE NamedPipeHandle;
38    UNICODE_STRING NameU;
39    ANSI_STRING NameA;
40    
41    RtlInitAnsiString(&NameA, (LPSTR)lpName);
42    RtlAnsiStringToUnicodeString(&NameU, &NameA, TRUE);
43    
44    NamedPipeHandle = CreateNamedPipeW(NameU.Buffer,
45                                       dwOpenMode,
46                                       dwPipeMode,
47                                       nMaxInstances,
48                                       nOutBufferSize,
49                                       nInBufferSize,
50                                       nDefaultTimeOut,
51                                       lpSecurityAttributes);
52    
53    RtlFreeUnicodeString(&NameU);
54    
55    return(NamedPipeHandle);
56 }
57
58
59 HANDLE STDCALL
60 CreateNamedPipeW(LPCWSTR lpName,
61                  DWORD dwOpenMode,
62                  DWORD dwPipeMode,
63                  DWORD nMaxInstances,
64                  DWORD nOutBufferSize,
65                  DWORD nInBufferSize,
66                  DWORD nDefaultTimeOut,
67                  LPSECURITY_ATTRIBUTES lpSecurityAttributes)
68 {
69    UNICODE_STRING NamedPipeName;
70    BOOL Result;
71    NTSTATUS Status;
72    OBJECT_ATTRIBUTES ObjectAttributes;
73    HANDLE PipeHandle;
74    ACCESS_MASK DesiredAccess;
75    ULONG CreateOptions;
76    ULONG CreateDisposition;
77    BOOLEAN WriteModeMessage;
78    BOOLEAN ReadModeMessage;
79    BOOLEAN NonBlocking;
80    IO_STATUS_BLOCK Iosb;
81    ULONG ShareAccess;
82    LARGE_INTEGER DefaultTimeOut;
83    
84    Result = RtlDosPathNameToNtPathName_U((LPWSTR)lpName,
85                                          &NamedPipeName,
86                                          NULL,
87                                          NULL);
88    if (!Result)
89      {
90         SetLastError(ERROR_PATH_NOT_FOUND);
91         return(INVALID_HANDLE_VALUE);
92      }
93    
94    DPRINT("Pipe name: %wZ\n", &NamedPipeName);
95    DPRINT("Pipe name: %S\n", NamedPipeName.Buffer);
96    
97    InitializeObjectAttributes(&ObjectAttributes,
98                               &NamedPipeName,
99                               OBJ_CASE_INSENSITIVE,
100                               NULL,
101                               NULL);
102    
103    DesiredAccess = 0;
104    
105    ShareAccess = 0;
106    
107    CreateDisposition = FILE_OPEN_IF;
108    
109    CreateOptions = 0;
110    if (dwOpenMode & FILE_FLAG_WRITE_THROUGH)
111      {
112         CreateOptions = CreateOptions | FILE_WRITE_THROUGH;
113      }
114    if (dwOpenMode & FILE_FLAG_OVERLAPPED)
115      {
116         CreateOptions = CreateOptions | FILE_SYNCHRONOUS_IO_ALERT;
117      }
118    if (dwOpenMode & PIPE_ACCESS_DUPLEX)
119      {
120         CreateOptions = CreateOptions | FILE_PIPE_FULL_DUPLEX;
121      }
122    else if (dwOpenMode & PIPE_ACCESS_INBOUND)
123      {
124         CreateOptions = CreateOptions | FILE_PIPE_INBOUND;
125      }
126    else if (dwOpenMode & PIPE_ACCESS_OUTBOUND)
127      {
128         CreateOptions = CreateOptions | FILE_PIPE_OUTBOUND;
129      }
130    
131    if (dwPipeMode & PIPE_TYPE_BYTE)
132      {
133         WriteModeMessage = FALSE;
134      }
135    else if (dwPipeMode & PIPE_TYPE_MESSAGE)
136      {
137         WriteModeMessage = TRUE;
138      }
139    else
140      {
141         WriteModeMessage = FALSE;
142      }
143    
144    if (dwPipeMode & PIPE_READMODE_BYTE)
145      {
146         ReadModeMessage = FALSE;
147      }
148    else if (dwPipeMode & PIPE_READMODE_MESSAGE)
149      {
150         ReadModeMessage = TRUE;
151      }
152    else
153      {
154         ReadModeMessage = FALSE;
155      }
156    
157    if (dwPipeMode & PIPE_WAIT)
158      {
159         NonBlocking = FALSE;
160      }
161    else if (dwPipeMode & PIPE_NOWAIT)
162      {
163         NonBlocking = TRUE;
164      }
165    else
166      {
167         NonBlocking = FALSE;
168      }
169    
170    if (nMaxInstances >= PIPE_UNLIMITED_INSTANCES)
171      {
172         nMaxInstances = ULONG_MAX;
173      }
174    
175    DefaultTimeOut.QuadPart = nDefaultTimeOut * -10000;
176    
177    Status = NtCreateNamedPipeFile(&PipeHandle,
178                                   DesiredAccess,
179                                   &ObjectAttributes,
180                                   &Iosb,
181                                   ShareAccess,
182                                   CreateDisposition,
183                                   CreateOptions,
184                                   WriteModeMessage,
185                                   ReadModeMessage,
186                                   NonBlocking,
187                                   nMaxInstances,
188                                   nInBufferSize,
189                                   nOutBufferSize,
190                                   &DefaultTimeOut);
191    
192    RtlFreeUnicodeString(&NamedPipeName);
193    
194    if (!NT_SUCCESS(Status))
195      {
196         DPRINT("NtCreateNamedPipe failed (Status %x)!\n", Status);
197         SetLastErrorByStatus (Status);
198         return(INVALID_HANDLE_VALUE);
199      }
200    
201    return(PipeHandle);
202 }
203
204
205 BOOL STDCALL
206 WaitNamedPipeA(LPCSTR lpNamedPipeName,
207                DWORD nTimeOut)
208 {
209    BOOL r;
210    UNICODE_STRING NameU;
211    ANSI_STRING NameA;
212    
213    RtlInitAnsiString(&NameA, (LPSTR)lpNamedPipeName);
214    RtlAnsiStringToUnicodeString(&NameU, &NameA, TRUE);
215    
216    r = WaitNamedPipeW(NameU.Buffer, nTimeOut);
217    
218    RtlFreeUnicodeString(&NameU);
219    
220    return(r);
221 }
222
223
224 BOOL STDCALL
225 WaitNamedPipeW(LPCWSTR lpNamedPipeName,
226                DWORD nTimeOut)
227 {
228    UNICODE_STRING NamedPipeName;
229    BOOL r;
230    NTSTATUS Status;
231    OBJECT_ATTRIBUTES ObjectAttributes;
232    NPFS_WAIT_PIPE WaitPipe;
233    HANDLE FileHandle;
234    IO_STATUS_BLOCK Iosb;
235    
236    r = RtlDosPathNameToNtPathName_U((LPWSTR)lpNamedPipeName,
237                                     &NamedPipeName,
238                                     NULL,
239                                     NULL);
240    
241    if (!r)
242      {
243         return(FALSE);
244      }
245    
246    InitializeObjectAttributes(&ObjectAttributes,
247                               &NamedPipeName,
248                               OBJ_CASE_INSENSITIVE,
249                               NULL,
250                               NULL);
251    Status = NtOpenFile(&FileHandle,
252                        FILE_GENERIC_READ,
253                        &ObjectAttributes,
254                        &Iosb,
255                        0,
256                        FILE_SYNCHRONOUS_IO_ALERT);
257    if (!NT_SUCCESS(Status))
258      {
259         SetLastErrorByStatus (Status);
260         return(FALSE);
261      }
262    
263    WaitPipe.Timeout.QuadPart = nTimeOut * -10000;
264    
265    Status = NtFsControlFile(FileHandle,
266                             NULL,
267                             NULL,
268                             NULL,
269                             &Iosb,
270                             FSCTL_PIPE_WAIT,
271                             &WaitPipe,
272                             sizeof(WaitPipe),
273                             NULL,
274                             0);
275    NtClose(FileHandle);
276    if (!NT_SUCCESS(Status))
277      {
278         SetLastErrorByStatus (Status);
279         return(FALSE);
280      }
281    
282    return(TRUE);
283 }
284
285
286 BOOL STDCALL
287 ConnectNamedPipe(HANDLE hNamedPipe,
288                  LPOVERLAPPED lpOverlapped)
289 {
290   PIO_STATUS_BLOCK IoStatusBlock;
291   IO_STATUS_BLOCK Iosb;
292   HANDLE hEvent;
293   NTSTATUS Status;
294
295   if (lpOverlapped != NULL)
296     {
297       lpOverlapped->Internal = STATUS_PENDING;
298       hEvent = lpOverlapped->hEvent;
299       IoStatusBlock = (PIO_STATUS_BLOCK)lpOverlapped;
300     }
301   else
302     {
303       IoStatusBlock = &Iosb;
304       hEvent = NULL;
305     }
306
307   Status = NtFsControlFile(hNamedPipe,
308                            hEvent,
309                            NULL,
310                            NULL,
311                            IoStatusBlock,
312                            FSCTL_PIPE_LISTEN,
313                            NULL,
314                            0,
315                            NULL,
316                            0);
317   if ((lpOverlapped == NULL) && (Status == STATUS_PENDING))
318     {
319       Status = NtWaitForSingleObject(hNamedPipe,
320                                      FALSE,
321                                      NULL);
322       if (!NT_SUCCESS(Status))
323         {
324           SetLastErrorByStatus(Status);
325           return(FALSE);
326         }
327       Status = Iosb.Status;
328     }
329   if ((!NT_SUCCESS(Status) && Status != STATUS_PIPE_CONNECTED) ||
330       (Status == STATUS_PENDING))
331     {
332       SetLastErrorByStatus(Status);
333       return(FALSE);
334     }
335   return(TRUE);
336 }
337
338
339 BOOL STDCALL
340 SetNamedPipeHandleState(HANDLE hNamedPipe,
341                         LPDWORD lpMode,
342                         LPDWORD lpMaxCollectionCount,
343                         LPDWORD lpCollectDataTimeout)
344 {
345    NPFS_GET_STATE GetState;
346    NPFS_SET_STATE SetState;
347    IO_STATUS_BLOCK Iosb;
348    NTSTATUS Status;
349
350    Status = NtFsControlFile(hNamedPipe,
351                             NULL,
352                             NULL,
353                             NULL,
354                             &Iosb,
355                             FSCTL_PIPE_GET_STATE,
356                             NULL,
357                             0,
358                             &GetState,
359                             sizeof(NPFS_GET_STATE));
360    if (Status == STATUS_PENDING)
361      {
362         Status = NtWaitForSingleObject(hNamedPipe,
363                                        FALSE,
364                                        NULL);
365         if (!NT_SUCCESS(Status))
366           {
367              SetLastErrorByStatus(Status);
368              return(FALSE);
369           }
370      }
371
372    if (lpMode != NULL)
373      {
374         if ((*lpMode) & PIPE_READMODE_MESSAGE)
375           {
376              SetState.ReadModeMessage = TRUE;
377           }
378         else
379           {
380              SetState.ReadModeMessage = FALSE;
381           }
382         if ((*lpMode) & PIPE_NOWAIT)
383           {
384              SetState.NonBlocking = TRUE;
385           }
386         else
387           {
388              SetState.NonBlocking = FALSE;
389           }
390         SetState.WriteModeMessage = GetState.WriteModeMessage;
391      }
392    else
393      {
394         SetState.ReadModeMessage = GetState.ReadModeMessage;
395         SetState.WriteModeMessage = GetState.WriteModeMessage;
396         SetState.NonBlocking = SetState.NonBlocking;
397      }
398    
399    if (lpMaxCollectionCount != NULL)
400      {
401         SetState.InBufferSize = *lpMaxCollectionCount;
402      }
403    else
404      {
405         SetState.InBufferSize = GetState.InBufferSize;
406      }
407    
408    SetState.OutBufferSize = GetState.OutBufferSize;
409    
410    if (lpCollectDataTimeout != NULL)
411      {
412         SetState.Timeout.QuadPart = (*lpCollectDataTimeout) * -10000;
413      }
414    else
415      {
416         SetState.Timeout = GetState.Timeout;
417      }
418
419    Status = NtFsControlFile(hNamedPipe,
420                             NULL,
421                             NULL,
422                             NULL,
423                             &Iosb,
424                             FSCTL_PIPE_SET_STATE,
425                             &SetState,
426                             sizeof(NPFS_SET_STATE),
427                             NULL,
428                             0);
429    if (Status == STATUS_PENDING)
430      {
431         Status = NtWaitForSingleObject(hNamedPipe,
432                                        FALSE,
433                                        NULL);
434         if (!NT_SUCCESS(Status))
435           {
436              SetLastErrorByStatus(Status);
437              return(FALSE);
438           }
439      }
440
441   return(TRUE);
442 }
443
444
445 BOOL STDCALL
446 CallNamedPipeA(LPCSTR lpNamedPipeName,
447                LPVOID lpInBuffer,
448                DWORD nInBufferSize,
449                LPVOID lpOutBuffer,
450                DWORD nOutBufferSize,
451                LPDWORD lpBytesRead,
452                DWORD nTimeOut)
453 {
454   UNICODE_STRING PipeName;
455   BOOL Result;
456   
457   RtlCreateUnicodeStringFromAsciiz(&PipeName,
458                                    (LPSTR)lpNamedPipeName);
459   
460   Result = CallNamedPipeW(PipeName.Buffer,
461                           lpInBuffer,
462                           nInBufferSize,
463                           lpOutBuffer,
464                           nOutBufferSize,
465                           lpBytesRead,
466                           nTimeOut);
467   
468   RtlFreeUnicodeString(&PipeName);
469   
470   return(Result);
471 }
472
473
474 BOOL STDCALL
475 CallNamedPipeW(LPCWSTR lpNamedPipeName,
476                LPVOID lpInBuffer,
477                DWORD nInBufferSize,
478                LPVOID lpOutBuffer,
479                DWORD nOutBufferSize,
480                LPDWORD lpBytesRead,
481                DWORD nTimeOut)
482 {
483   HANDLE hPipe = INVALID_HANDLE_VALUE;
484   BOOL bRetry = TRUE;
485   BOOL bError = FALSE;
486   DWORD dwPipeMode;
487
488   while (TRUE)
489     {
490       hPipe = CreateFileW(lpNamedPipeName,
491                           GENERIC_READ | GENERIC_WRITE,
492                           FILE_SHARE_READ | FILE_SHARE_WRITE,
493                           NULL,
494                           OPEN_EXISTING,
495                           FILE_ATTRIBUTE_NORMAL,
496                           NULL);
497       if (hPipe != INVALID_HANDLE_VALUE)
498         break;
499
500       if (bRetry == FALSE)
501         return(FALSE);
502
503       WaitNamedPipeW(lpNamedPipeName,
504                      nTimeOut);
505
506       bRetry = FALSE;
507     }
508
509   dwPipeMode = PIPE_READMODE_MESSAGE;
510   bError = SetNamedPipeHandleState(hPipe,
511                                    &dwPipeMode,
512                                    NULL,
513                                    NULL);
514   if (!bError)
515     {
516       CloseHandle(hPipe);
517       return(FALSE);
518     }
519
520   bError = TransactNamedPipe(hPipe,
521                              lpInBuffer,
522                              nInBufferSize,
523                              lpOutBuffer,
524                              nOutBufferSize,
525                              lpBytesRead,
526                              NULL);
527   CloseHandle(hPipe);
528
529   return(bError);
530 }
531
532
533 BOOL STDCALL
534 DisconnectNamedPipe(HANDLE hNamedPipe)
535 {
536   IO_STATUS_BLOCK Iosb;
537   NTSTATUS Status;
538
539   Status = NtFsControlFile(hNamedPipe,
540                            NULL,
541                            NULL,
542                            NULL,
543                            &Iosb,
544                            FSCTL_PIPE_DISCONNECT,
545                            NULL,
546                            0,
547                            NULL,
548                            0);
549   if (Status == STATUS_PENDING)
550     {
551       Status = NtWaitForSingleObject(hNamedPipe,
552                                      FALSE,
553                                      NULL);
554       if (!NT_SUCCESS(Status))
555         {
556           SetLastErrorByStatus(Status);
557           return(FALSE);
558         }
559     }
560
561   if (!NT_SUCCESS(Status))
562     {
563       SetLastErrorByStatus(Status);
564       return(FALSE);
565     }
566   return(TRUE);
567 }
568
569
570 WINBOOL STDCALL
571 GetNamedPipeHandleStateW(HANDLE hNamedPipe,
572                          LPDWORD lpState,
573                          LPDWORD lpCurInstances,
574                          LPDWORD lpMaxCollectionCount,
575                          LPDWORD lpCollectDataTimeout,
576                          LPWSTR lpUserName,
577                          DWORD nMaxUserNameSize)
578 {
579   FILE_PIPE_LOCAL_INFORMATION LocalInfo;
580   FILE_PIPE_INFORMATION PipeInfo;
581   IO_STATUS_BLOCK StatusBlock;
582   NTSTATUS Status;
583
584   if (lpState != NULL)
585     {
586       Status = NtQueryInformationFile(hNamedPipe,
587                                       &StatusBlock,
588                                       &PipeInfo,
589                                       sizeof(FILE_PIPE_INFORMATION),
590                                       FilePipeInformation);
591       if (!NT_SUCCESS(Status))
592         {
593           SetLastErrorByStatus(Status);
594           return(FALSE);
595         }
596       *lpState = 0; /* FIXME */
597     }
598
599   if (lpCurInstances != NULL)
600     {
601       Status = NtQueryInformationFile(hNamedPipe,
602                                       &StatusBlock,
603                                       &LocalInfo,
604                                       sizeof(FILE_PIPE_LOCAL_INFORMATION),
605                                       FilePipeLocalInformation);
606       if (!NT_SUCCESS(Status))
607         {
608           SetLastErrorByStatus(Status);
609           return(FALSE);
610         }
611       *lpCurInstances = min(LocalInfo.CurrentInstances, 255);
612     }
613
614
615   /* FIXME: retrieve remaining information */
616
617
618   return(TRUE);
619 }
620
621
622 WINBOOL STDCALL
623 GetNamedPipeHandleStateA(HANDLE hNamedPipe,
624                          LPDWORD lpState,
625                          LPDWORD lpCurInstances,
626                          LPDWORD lpMaxCollectionCount,
627                          LPDWORD lpCollectDataTimeout,
628                          LPSTR lpUserName,
629                          DWORD nMaxUserNameSize)
630 {
631         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
632         return FALSE;
633 }
634
635
636 WINBOOL STDCALL
637 GetNamedPipeInfo(HANDLE hNamedPipe,
638                  LPDWORD lpFlags,
639                  LPDWORD lpOutBufferSize,
640                  LPDWORD lpInBufferSize,
641                  LPDWORD lpMaxInstances)
642 {
643   FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation;
644   IO_STATUS_BLOCK StatusBlock;
645   NTSTATUS Status;
646   
647   Status = NtQueryInformationFile(hNamedPipe,
648                                   &StatusBlock,
649                                   &PipeLocalInformation,
650                                   sizeof(FILE_PIPE_LOCAL_INFORMATION),
651                                   FilePipeLocalInformation);
652   if (!NT_SUCCESS(Status))
653     {
654       SetLastErrorByStatus(Status);
655       return(FALSE);
656     }
657   
658   if (lpFlags != NULL)
659     {
660       *lpFlags = (PipeLocalInformation.NamedPipeEnd == FILE_PIPE_SERVER_END) ? PIPE_SERVER_END : PIPE_CLIENT_END;
661       *lpFlags |= (PipeLocalInformation.NamedPipeType == 1) ? PIPE_TYPE_MESSAGE : PIPE_TYPE_BYTE;
662     }
663   
664   if (lpOutBufferSize != NULL)
665     *lpOutBufferSize = PipeLocalInformation.OutboundQuota;
666   
667   if (lpInBufferSize != NULL)
668     *lpInBufferSize = PipeLocalInformation.InboundQuota;
669   
670   if (lpMaxInstances != NULL)
671     {
672       if (PipeLocalInformation.MaximumInstances >= 255)
673         *lpMaxInstances = PIPE_UNLIMITED_INSTANCES;
674       else
675         *lpMaxInstances = PipeLocalInformation.MaximumInstances;
676     }
677   
678   return(TRUE);
679 }
680
681
682 BOOL STDCALL
683 PeekNamedPipe(HANDLE hNamedPipe,
684               LPVOID lpBuffer,
685               DWORD nBufferSize,
686               LPDWORD lpBytesRead,
687               LPDWORD lpTotalBytesAvail,
688               LPDWORD lpBytesLeftThisMessage)
689 {
690   PFILE_PIPE_PEEK_BUFFER Buffer;
691   IO_STATUS_BLOCK Iosb;
692   ULONG BufferSize;
693   NTSTATUS Status;
694
695   BufferSize = nBufferSize + sizeof(FILE_PIPE_PEEK_BUFFER);
696   Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
697                            0,
698                            BufferSize);
699
700   Status = NtFsControlFile(hNamedPipe,
701                            NULL,
702                            NULL,
703                            NULL,
704                            &Iosb,
705                            FSCTL_PIPE_PEEK,
706                            NULL,
707                            0,
708                            Buffer,
709                            BufferSize);
710   if (Status == STATUS_PENDING)
711     {
712       Status = NtWaitForSingleObject(hNamedPipe,
713                                      FALSE,
714                                      NULL);
715       if (NT_SUCCESS(Status))
716         Status = Iosb.Status;
717     }
718
719   if (Status == STATUS_BUFFER_OVERFLOW)
720     {
721       Status = STATUS_SUCCESS;
722     }
723
724   if (!NT_SUCCESS(Status))
725     {
726       RtlFreeHeap(RtlGetProcessHeap(),
727                   0,
728                   Buffer);
729       SetLastErrorByStatus(Status);
730       return(FALSE);
731     }
732
733   if (lpTotalBytesAvail != NULL)
734     {
735       *lpTotalBytesAvail = Buffer->ReadDataAvailable;
736     }
737
738   if (lpBytesRead != NULL)
739     {
740       *lpBytesRead = Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER);
741     }
742
743   if (lpBytesLeftThisMessage != NULL)
744     {
745       *lpBytesLeftThisMessage = Buffer->MessageLength -
746         (Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER));
747     }
748
749   if (lpBuffer != NULL)
750     {
751       memcpy(lpBuffer, Buffer->Data,
752              min(nBufferSize, Iosb.Information - sizeof(FILE_PIPE_PEEK_BUFFER)));
753     }
754
755   RtlFreeHeap(RtlGetProcessHeap(),
756               0,
757               Buffer);
758
759   return(TRUE);
760 }
761
762
763 BOOL STDCALL
764 TransactNamedPipe(HANDLE hNamedPipe,
765                   LPVOID lpInBuffer,
766                   DWORD nInBufferSize,
767                   LPVOID lpOutBuffer,
768                   DWORD nOutBufferSize,
769                   LPDWORD lpBytesRead,
770                   LPOVERLAPPED lpOverlapped)
771 {
772   IO_STATUS_BLOCK IoStatusBlock;
773   NTSTATUS Status;
774
775   if (lpOverlapped == NULL)
776     {
777       Status = NtFsControlFile(hNamedPipe,
778                                NULL,
779                                NULL,
780                                NULL,
781                                &IoStatusBlock,
782                                FSCTL_PIPE_TRANSCEIVE,
783                                lpInBuffer,
784                                nInBufferSize,
785                                lpOutBuffer,
786                                nOutBufferSize);
787       if (Status == STATUS_PENDING)
788         {
789           NtWaitForSingleObject(hNamedPipe,
790                                 0,
791                                 FALSE);
792           Status = IoStatusBlock.Status;
793         }
794       if (NT_SUCCESS(Status))
795         {
796           *lpBytesRead = IoStatusBlock.Information;
797         }
798     }
799   else
800     {
801       lpOverlapped->Internal = STATUS_PENDING;
802
803       Status = NtFsControlFile(hNamedPipe,
804                                lpOverlapped->hEvent,
805                                NULL,
806                                NULL,
807                                (PIO_STATUS_BLOCK)lpOverlapped,
808                                FSCTL_PIPE_TRANSCEIVE,
809                                lpInBuffer,
810                                nInBufferSize,
811                                lpOutBuffer,
812                                nOutBufferSize);
813     }
814
815   if (!NT_SUCCESS(Status))
816     {
817       SetLastErrorByStatus(Status);
818       return(FALSE);
819     }
820
821   return(TRUE);
822 }
823
824 /* EOF */