- fixed TransactNamedPipe to properly wait on completion for synchronous operations 
- prevent completion port notification by not passing an APC context to the kernel when the low-order bit of the event handle is set (for asynchronous operations)
Modified: trunk/reactos/lib/kernel32/file/npipe.c

Modified: trunk/reactos/lib/kernel32/file/npipe.c
--- trunk/reactos/lib/kernel32/file/npipe.c	2005-05-06 16:23:24 UTC (rev 15050)
+++ trunk/reactos/lib/kernel32/file/npipe.c	2005-05-06 16:47:09 UTC (rev 15051)
@@ -892,64 +892,93 @@
  * @implemented
  */
 BOOL STDCALL
-TransactNamedPipe(HANDLE hNamedPipe,
-		  LPVOID lpInBuffer,
-		  DWORD nInBufferSize,
-		  LPVOID lpOutBuffer,
-		  DWORD nOutBufferSize,
-		  LPDWORD lpBytesRead,
-		  LPOVERLAPPED lpOverlapped)
+TransactNamedPipe(IN HANDLE hNamedPipe,
+                  IN LPVOID lpInBuffer,
+                  IN DWORD nInBufferSize,
+                  OUT LPVOID lpOutBuffer,
+                  IN DWORD nOutBufferSize,
+                  OUT LPDWORD lpBytesRead  OPTIONAL,
+                  IN LPOVERLAPPED lpOverlapped  OPTIONAL)
 {
-  IO_STATUS_BLOCK IoStatusBlock;
-  NTSTATUS Status;
+   NTSTATUS Status;
+   
+   if (lpBytesRead != NULL)
+     {
+        *lpBytesRead = 0;
+     }
 
-  if (lpOverlapped == NULL)
-    {
-      Status = NtFsControlFile(hNamedPipe,
-			       NULL,
-			       NULL,
-			       NULL,
-			       &IoStatusBlock,
-			       FSCTL_PIPE_TRANSCEIVE,
-			       lpInBuffer,
-			       nInBufferSize,
-			       lpOutBuffer,
-			       nOutBufferSize);
-      if (Status == STATUS_PENDING)
-	{
-	  NtWaitForSingleObject(hNamedPipe,
-				0,
-				FALSE);
-	  Status = IoStatusBlock.Status;
-	}
-      if (NT_SUCCESS(Status))
-	{
-	  *lpBytesRead = IoStatusBlock.Information;
-	}
-    }
-  else
-    {
-      lpOverlapped->Internal = STATUS_PENDING;
+   if (lpOverlapped != NULL)
+     {
+        PVOID ApcContext;
 
-      Status = NtFsControlFile(hNamedPipe,
-			       lpOverlapped->hEvent,
-			       NULL,
-			       NULL,
-			       (PIO_STATUS_BLOCK)lpOverlapped,
-			       FSCTL_PIPE_TRANSCEIVE,
-			       lpInBuffer,
-			       nInBufferSize,
-			       lpOutBuffer,
-			       nOutBufferSize);
-    }
+        ApcContext = (((ULONG_PTR)lpOverlapped->hEvent & 0x1) ? NULL : lpOverlapped);
+        lpOverlapped->Internal = STATUS_PENDING;
 
-  if (!NT_SUCCESS(Status))
-    {
-      SetLastErrorByStatus(Status);
-      return(FALSE);
-    }
+        Status = NtFsControlFile(hNamedPipe,
+                                 lpOverlapped->hEvent,
+                                 NULL,
+                                 ApcContext,
+                                 (PIO_STATUS_BLOCK)lpOverlapped,
+                                 FSCTL_PIPE_TRANSCEIVE,
+                                 lpInBuffer,
+                                 nInBufferSize,
+                                 lpOutBuffer,
+                                 nOutBufferSize);
 
-  return(TRUE);
+        /* return FALSE in case of failure and pending operations! */
+        if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
+          {
+             SetLastErrorByStatus(Status);
+             return FALSE;
+          }
+
+        if (lpBytesRead != NULL)
+          {
+             *lpBytesRead = lpOverlapped->InternalHigh;
+          }
+     }
+   else
+     {
+        IO_STATUS_BLOCK Iosb;
+        
+        Status = NtFsControlFile(hNamedPipe,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 &Iosb,
+                                 FSCTL_PIPE_TRANSCEIVE,
+                                 lpInBuffer,
+                                 nInBufferSize,
+                                 lpOutBuffer,
+                                 nOutBufferSize);
+
+        /* wait in case operation is pending */
+        if (Status == STATUS_PENDING)
+          {
+             Status = NtWaitForSingleObject(hNamedPipe,
+                                            FALSE,
+                                            NULL);
+             if (NT_SUCCESS(Status))
+               {
+                  Status = Iosb.Status;
+               }
+          }
+
+        if (NT_SUCCESS(Status))
+          {
+             /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
+                check that case either and crashes (only after the operation
+                completed) */
+             *lpBytesRead = Iosb.Information;
+          }
+        else
+          {
+             SetLastErrorByStatus(Status);
+             return FALSE;
+          }
+     }
+
+   return TRUE;
 }
 
 /* EOF */