2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32 Kernel Library
4 * FILE: lib/kernel32/file/npipe.c
5 * PURPOSE: Named Pipe Functions
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
7 * Ariadne ( ariadne@xs4all.nl)
10 /* INCLUDES *****************************************************************/
13 #include <wine/debug.h>
15 WINE_DEFAULT_DEBUG_CHANNEL(kernel32file
);
17 //#define USING_PROPER_NPFS_WAIT_SEMANTICS
19 /* FUNCTIONS ****************************************************************/
26 CreateNamedPipeA(LPCSTR lpName
,
32 DWORD nDefaultTimeOut
,
33 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
35 PUNICODE_STRING NameU
= &NtCurrentTeb()->StaticUnicodeString
;
38 /* Initialize the string as ANSI_STRING and convert to Unicode */
39 RtlInitAnsiString(&NameA
, (LPSTR
)lpName
);
40 RtlAnsiStringToUnicodeString(NameU
, &NameA
, FALSE
);
42 /* Call the Unicode API */
43 return CreateNamedPipeW(NameU
->Buffer
,
50 lpSecurityAttributes
);
59 CreateNamedPipeW(LPCWSTR lpName
,
65 DWORD nDefaultTimeOut
,
66 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
68 UNICODE_STRING NamedPipeName
;
71 OBJECT_ATTRIBUTES ObjectAttributes
;
73 ACCESS_MASK DesiredAccess
;
74 ULONG CreateOptions
= 0;
75 ULONG WriteModeMessage
;
76 ULONG ReadModeMessage
;
79 ULONG ShareAccess
= 0, Attributes
;
80 LARGE_INTEGER DefaultTimeOut
;
81 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
83 /* Check for valid instances */
84 if (nMaxInstances
== 0 || nMaxInstances
> PIPE_UNLIMITED_INSTANCES
)
87 SetLastError(ERROR_INVALID_PARAMETER
);
88 return INVALID_HANDLE_VALUE
;
91 /* Convert to NT syntax */
92 if (nMaxInstances
== PIPE_UNLIMITED_INSTANCES
)
95 /* Convert the name */
96 Result
= RtlDosPathNameToNtPathName_U(lpName
,
102 /* Conversion failed */
103 SetLastError(ERROR_PATH_NOT_FOUND
);
104 return INVALID_HANDLE_VALUE
;
107 TRACE("Pipe name: %wZ\n", &NamedPipeName
);
108 TRACE("Pipe name: %S\n", NamedPipeName
.Buffer
);
110 /* Always case insensitive, check if we got extra attributes */
111 Attributes
= OBJ_CASE_INSENSITIVE
;
112 if(lpSecurityAttributes
)
114 /* We did; get the security descriptor */
115 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
117 /* And check if this is pipe's handle will beinheritable */
118 if (lpSecurityAttributes
->bInheritHandle
)
119 Attributes
|= OBJ_INHERIT
;
122 /* Now we can initialize the object attributes */
123 InitializeObjectAttributes(&ObjectAttributes
,
129 /* Setup the default Desired Access */
130 DesiredAccess
= SYNCHRONIZE
| (dwOpenMode
& (WRITE_DAC
|
132 ACCESS_SYSTEM_SECURITY
));
134 /* Convert to NT Create Flags */
135 if (dwOpenMode
& FILE_FLAG_WRITE_THROUGH
)
137 CreateOptions
|= FILE_WRITE_THROUGH
;
140 if (!(dwOpenMode
& FILE_FLAG_OVERLAPPED
))
142 CreateOptions
|= FILE_SYNCHRONOUS_IO_NONALERT
;
145 /* Handle all open modes */
146 if (dwOpenMode
& PIPE_ACCESS_OUTBOUND
)
148 ShareAccess
|= FILE_SHARE_READ
;
149 DesiredAccess
|= GENERIC_WRITE
;
152 if (dwOpenMode
& PIPE_ACCESS_INBOUND
)
154 ShareAccess
|= FILE_SHARE_WRITE
;
155 DesiredAccess
|= GENERIC_READ
;
158 /* Handle the type flags */
159 if (dwPipeMode
& PIPE_TYPE_MESSAGE
)
161 WriteModeMessage
= FILE_PIPE_MESSAGE_TYPE
;
165 WriteModeMessage
= FILE_PIPE_BYTE_STREAM_TYPE
;
168 /* Handle the mode flags */
169 if (dwPipeMode
& PIPE_READMODE_MESSAGE
)
171 ReadModeMessage
= FILE_PIPE_MESSAGE_MODE
;
175 ReadModeMessage
= FILE_PIPE_BYTE_STREAM_MODE
;
178 /* Handle the blocking mode */
179 if (dwPipeMode
& PIPE_NOWAIT
)
181 NonBlocking
= FILE_PIPE_COMPLETE_OPERATION
;
185 NonBlocking
= FILE_PIPE_QUEUE_OPERATION
;
188 /* Check if we have a timeout */
191 /* Convert the time to NT format */
192 DefaultTimeOut
.QuadPart
= UInt32x32To64(nDefaultTimeOut
, -10000);
196 /* Use default timeout of 50 ms */
197 DefaultTimeOut
.QuadPart
= -500000;
200 /* Now create the pipe */
201 Status
= NtCreateNamedPipeFile(&PipeHandle
,
216 /* Normalize special error codes */
217 if ((Status
== STATUS_INVALID_DEVICE_REQUEST
) ||
218 (Status
== STATUS_NOT_SUPPORTED
))
220 Status
= STATUS_OBJECT_NAME_INVALID
;
224 RtlFreeHeap(RtlGetProcessHeap(),
226 NamedPipeName
.Buffer
);
229 if (!NT_SUCCESS(Status
))
231 /* Failed to create it */
232 WARN("NtCreateNamedPipe failed (Status %x)!\n", Status
);
233 SetLastErrorByStatus (Status
);
234 return INVALID_HANDLE_VALUE
;
237 /* Return the handle */
247 WaitNamedPipeA(LPCSTR lpNamedPipeName
,
251 UNICODE_STRING NameU
;
253 /* Convert the name to Unicode */
254 Basep8BitStringToHeapUnicodeString(&NameU
, lpNamedPipeName
);
256 /* Call the Unicode API */
257 r
= WaitNamedPipeW(NameU
.Buffer
, nTimeOut
);
259 /* Free the Unicode string */
260 RtlFreeUnicodeString(&NameU
);
268 * When NPFS will work properly, use this code instead. It is compatible with
269 * Microsoft's NPFS.SYS. The main difference is that:
270 * - This code actually respects the timeout instead of ignoring it!
271 * - This code validates and creates the proper names for both UNC and local pipes
272 * - On NT, you open the *root* pipe directory (either \DosDevices\Pipe or
273 * \DosDevices\Unc\Server\Pipe) and then send the pipe to wait on in the
274 * FILE_PIPE_WAIT_FOR_BUFFER structure.
276 #ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
282 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
285 UNICODE_STRING NamedPipeName
, NewName
, DevicePath
, PipePrefix
;
290 OBJECT_ATTRIBUTES ObjectAttributes
;
293 IO_STATUS_BLOCK IoStatusBlock
;
294 ULONG WaitPipeInfoSize
;
295 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo
;
297 /* Start by making a unicode string of the name */
298 TRACE("Sent path: %S\n", lpNamedPipeName
);
299 RtlCreateUnicodeString(&NamedPipeName
, lpNamedPipeName
);
300 NameLength
= NamedPipeName
.Length
/ sizeof(WCHAR
);
302 /* All slashes must become backslashes */
303 for (i
= 0; i
< NameLength
; i
++)
305 /* Check and convert */
306 if (NamedPipeName
.Buffer
[i
] == L
'/') NamedPipeName
.Buffer
[i
] = L
'\\';
309 /* Find the path type of the name we were given */
310 NewName
= NamedPipeName
;
311 Type
= RtlDetermineDosPathNameType_U(lpNamedPipeName
);
313 /* Check if this was a device path, ie : "\\.\pipe\name" */
314 if (Type
== RtlPathTypeLocalDevice
)
316 /* Make sure it's a valid prefix */
317 RtlInitUnicodeString(&PipePrefix
, L
"\\\\.\\pipe\\");
318 RtlPrefixString((PANSI_STRING
)&PipePrefix
, (PANSI_STRING
)&NewName
, TRUE
);
322 NewName
.Length
-= 9 * sizeof(WCHAR
);
324 /* Initialize the Dos Devices name */
325 TRACE("NewName: %wZ\n", &NewName
);
326 RtlInitUnicodeString(&DevicePath
, L
"\\DosDevices\\pipe\\");
328 else if (Type
== RtlPathTypeRootLocalDevice
)
330 /* The path is \\server\\pipe\name; find the pipename itself */
331 p
= &NewName
.Buffer
[2];
333 /* First loop to get past the server name */
336 /* Check if this is a backslash */
337 if (*p
== L
'\\') break;
343 /* Now make sure the full name contains "pipe\" */
344 if ((*p
) && !(_wcsnicmp(p
+ 1, L
"pipe\\", sizeof("pipe\\"))))
346 /* Get to the pipe name itself now */
347 p
+= sizeof("pipe\\") - 1;
351 /* The name is invalid */
352 WARN("Invalid name!\n");
353 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD
);
357 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
361 WARN("Invalid path type\n");
362 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD
);
366 /* Now calculate the total length of the structure and allocate it */
367 WaitPipeInfoSize
= FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER
, Name
[0]) +
369 WaitPipeInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize
);
370 if (WaitPipeInfo
== NULL
)
372 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
376 /* Initialize the object attributes */
377 TRACE("Opening: %wZ\n", &DevicePath
);
378 InitializeObjectAttributes(&ObjectAttributes
,
380 OBJ_CASE_INSENSITIVE
,
385 Status
= NtOpenFile(&FileHandle
,
386 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
389 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
390 FILE_SYNCHRONOUS_IO_NONALERT
);
391 if (!NT_SUCCESS(Status
))
393 /* Fail; couldn't open */
394 WARN("Status: %lx\n", Status
);
395 SetLastErrorByStatus(Status
);
396 RtlFreeUnicodeString(&NamedPipeName
);
397 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
401 /* Check what timeout we got */
402 if (nTimeOut
== NMPWAIT_USE_DEFAULT_WAIT
)
404 /* Don't use a timeout */
405 WaitPipeInfo
->TimeoutSpecified
= FALSE
;
409 /* Check if we should wait forever */
410 if (nTimeOut
== NMPWAIT_WAIT_FOREVER
)
413 WaitPipeInfo
->Timeout
.LowPart
= 0;
414 WaitPipeInfo
->Timeout
.HighPart
= 0x80000000;
418 /* Convert to NT format */
419 WaitPipeInfo
->Timeout
.QuadPart
= UInt32x32To64(-10000, nTimeOut
);
422 /* In both cases, we do have a timeout */
423 WaitPipeInfo
->TimeoutSpecified
= TRUE
;
426 /* Set the length and copy the name */
427 WaitPipeInfo
->NameLength
= NewName
.Length
;
428 RtlCopyMemory(WaitPipeInfo
->Name
, NewName
.Buffer
, NewName
.Length
);
430 /* Get rid of the full name */
431 RtlFreeUnicodeString(&NamedPipeName
);
433 /* Let NPFS know of our request */
434 Status
= NtFsControlFile(FileHandle
,
445 /* Free our pipe info data and close the handle */
446 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
449 /* Check the status */
450 if (!NT_SUCCESS(Status
))
452 /* Failure to wait on the pipe */
453 WARN("Status: %lx\n", Status
);
454 SetLastErrorByStatus (Status
);
467 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
470 UNICODE_STRING NamedPipeName
;
472 OBJECT_ATTRIBUTES ObjectAttributes
;
473 FILE_PIPE_WAIT_FOR_BUFFER WaitPipe
;
475 IO_STATUS_BLOCK Iosb
;
477 if (RtlDosPathNameToNtPathName_U(lpNamedPipeName
,
485 InitializeObjectAttributes(&ObjectAttributes
,
487 OBJ_CASE_INSENSITIVE
,
490 Status
= NtOpenFile(&FileHandle
,
491 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
494 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
495 FILE_SYNCHRONOUS_IO_NONALERT
);
496 if (!NT_SUCCESS(Status
))
498 SetLastErrorByStatus(Status
);
499 RtlFreeUnicodeString(&NamedPipeName
);
503 /* Check what timeout we got */
504 if (nTimeOut
== NMPWAIT_USE_DEFAULT_WAIT
)
506 /* Don't use a timeout */
507 WaitPipe
.TimeoutSpecified
= FALSE
;
511 /* Check if we should wait forever */
512 if (nTimeOut
== NMPWAIT_WAIT_FOREVER
)
515 WaitPipe
.Timeout
.LowPart
= 0;
516 WaitPipe
.Timeout
.HighPart
= 0x80000000;
520 /* Convert to NT format */
521 WaitPipe
.Timeout
.QuadPart
= UInt32x32To64(-10000, nTimeOut
);
524 /* In both cases, we do have a timeout */
525 WaitPipe
.TimeoutSpecified
= TRUE
;
528 Status
= NtFsControlFile(FileHandle
,
539 if (!NT_SUCCESS(Status
))
541 SetLastErrorByStatus(Status
);
542 RtlFreeUnicodeString(&NamedPipeName
);
546 RtlFreeUnicodeString(&NamedPipeName
);
557 ConnectNamedPipe(IN HANDLE hNamedPipe
,
558 IN LPOVERLAPPED lpOverlapped
)
562 if (lpOverlapped
!= NULL
)
566 lpOverlapped
->Internal
= STATUS_PENDING
;
567 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
569 Status
= NtFsControlFile(hNamedPipe
,
570 lpOverlapped
->hEvent
,
573 (PIO_STATUS_BLOCK
)lpOverlapped
,
580 /* return FALSE in case of failure and pending operations! */
581 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
583 SetLastErrorByStatus(Status
);
589 IO_STATUS_BLOCK Iosb
;
591 Status
= NtFsControlFile(hNamedPipe
,
602 /* wait in case operation is pending */
603 if (Status
== STATUS_PENDING
)
605 Status
= NtWaitForSingleObject(hNamedPipe
,
608 if (NT_SUCCESS(Status
))
610 Status
= Iosb
.Status
;
614 if (!NT_SUCCESS(Status
))
616 SetLastErrorByStatus(Status
);
630 SetNamedPipeHandleState(HANDLE hNamedPipe
,
632 LPDWORD lpMaxCollectionCount
,
633 LPDWORD lpCollectDataTimeout
)
635 IO_STATUS_BLOCK Iosb
;
638 /* Check if the Mode is being changed */
641 FILE_PIPE_INFORMATION Settings
;
643 /* Set the Completion Mode */
644 Settings
.CompletionMode
= (*lpMode
& PIPE_NOWAIT
) ?
645 FILE_PIPE_COMPLETE_OPERATION
: FILE_PIPE_QUEUE_OPERATION
;
647 /* Set the Read Mode */
648 Settings
.ReadMode
= (*lpMode
& PIPE_READMODE_MESSAGE
) ?
649 FILE_PIPE_MESSAGE_MODE
: FILE_PIPE_BYTE_STREAM_MODE
;
651 /* Send the changes to the Driver */
652 Status
= NtSetInformationFile(hNamedPipe
,
655 sizeof(FILE_PIPE_INFORMATION
),
656 FilePipeInformation
);
657 if (!NT_SUCCESS(Status
))
659 SetLastErrorByStatus(Status
);
664 /* Check if the Collection count or Timeout are being changed */
665 if (lpMaxCollectionCount
|| lpCollectDataTimeout
)
667 FILE_PIPE_REMOTE_INFORMATION RemoteSettings
;
669 /* Setting one without the other would delete it, so we read old one */
670 if (!lpMaxCollectionCount
|| !lpCollectDataTimeout
)
672 Status
= NtQueryInformationFile(hNamedPipe
,
675 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
676 FilePipeRemoteInformation
);
677 if (!NT_SUCCESS(Status
))
679 SetLastErrorByStatus(Status
);
684 /* Now set the new settings */
685 RemoteSettings
.MaximumCollectionCount
= (lpMaxCollectionCount
) ?
686 *lpMaxCollectionCount
:
687 RemoteSettings
.MaximumCollectionCount
;
688 if (lpCollectDataTimeout
)
690 /* Convert it to Quad */
691 RemoteSettings
.CollectDataTime
.QuadPart
=
692 -(LONGLONG
)UInt32x32To64(10000, *lpCollectDataTimeout
);
695 /* Tell the driver to change them */
696 Status
= NtSetInformationFile(hNamedPipe
,
699 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
700 FilePipeRemoteInformation
);
701 if (!NT_SUCCESS(Status
))
703 SetLastErrorByStatus(Status
);
717 CallNamedPipeA(LPCSTR lpNamedPipeName
,
721 DWORD nOutBufferSize
,
725 PUNICODE_STRING PipeName
= &NtCurrentTeb()->StaticUnicodeString
;
726 ANSI_STRING AnsiPipe
;
728 /* Initialize the string as ANSI_STRING and convert to Unicode */
729 RtlInitAnsiString(&AnsiPipe
, (LPSTR
)lpNamedPipeName
);
730 RtlAnsiStringToUnicodeString(PipeName
, &AnsiPipe
, FALSE
);
732 /* Call the Unicode function */
733 return CallNamedPipeW(PipeName
->Buffer
,
748 CallNamedPipeW(LPCWSTR lpNamedPipeName
,
752 DWORD nOutBufferSize
,
763 /* Try creating it */
764 hPipe
= CreateFileW(lpNamedPipeName
,
765 GENERIC_READ
| GENERIC_WRITE
,
766 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
769 FILE_ATTRIBUTE_NORMAL
,
772 /* Success, break out */
773 if (hPipe
!= INVALID_HANDLE_VALUE
)
776 /* Already tried twice, give up */
781 WaitNamedPipeW(lpNamedPipeName
, nTimeOut
);
783 /* Get ready to try again */
787 /* Set the pipe mode */
788 dwPipeMode
= PIPE_READMODE_MESSAGE
| PIPE_WAIT
;
789 bError
= SetNamedPipeHandleState(hPipe
, &dwPipeMode
, NULL
, NULL
);
792 /* Couldn't change state, fail */
797 /* Do the transact */
798 bError
= TransactNamedPipe(hPipe
,
806 /* Close the handle */
818 DisconnectNamedPipe(HANDLE hNamedPipe
)
820 IO_STATUS_BLOCK Iosb
;
823 /* Send the FSCTL to the driver */
824 Status
= NtFsControlFile(hNamedPipe
,
829 FSCTL_PIPE_DISCONNECT
,
834 if (Status
== STATUS_PENDING
)
836 /* Wait on NPFS to finish and get updated status */
837 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
838 if (NT_SUCCESS(Status
))
839 Status
= Iosb
.Status
;
842 /* Check for error */
843 if (!NT_SUCCESS(Status
))
846 SetLastErrorByStatus(Status
);
859 GetNamedPipeHandleStateW(HANDLE hNamedPipe
,
861 LPDWORD lpCurInstances
,
862 LPDWORD lpMaxCollectionCount
,
863 LPDWORD lpCollectDataTimeout
,
865 DWORD nMaxUserNameSize
)
867 IO_STATUS_BLOCK StatusBlock
;
872 FILE_PIPE_INFORMATION PipeInfo
;
874 Status
= NtQueryInformationFile(hNamedPipe
,
877 sizeof(FILE_PIPE_INFORMATION
),
878 FilePipeInformation
);
879 if (!NT_SUCCESS(Status
))
881 SetLastErrorByStatus(Status
);
885 *lpState
= ((PipeInfo
.CompletionMode
!= FILE_PIPE_QUEUE_OPERATION
) ? PIPE_NOWAIT
: PIPE_WAIT
);
886 *lpState
|= ((PipeInfo
.ReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
) ? PIPE_READMODE_MESSAGE
: PIPE_READMODE_BYTE
);
889 if(lpCurInstances
!= NULL
)
891 FILE_PIPE_LOCAL_INFORMATION LocalInfo
;
893 Status
= NtQueryInformationFile(hNamedPipe
,
896 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
897 FilePipeLocalInformation
);
898 if (!NT_SUCCESS(Status
))
900 SetLastErrorByStatus(Status
);
904 *lpCurInstances
= min(LocalInfo
.CurrentInstances
, PIPE_UNLIMITED_INSTANCES
);
907 if (lpMaxCollectionCount
!= NULL
|| lpCollectDataTimeout
!= NULL
)
909 FILE_PIPE_REMOTE_INFORMATION RemoteInfo
;
911 Status
= NtQueryInformationFile(hNamedPipe
,
914 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
915 FilePipeRemoteInformation
);
916 if (!NT_SUCCESS(Status
))
918 SetLastErrorByStatus(Status
);
922 if (lpMaxCollectionCount
!= NULL
)
924 *lpMaxCollectionCount
= RemoteInfo
.MaximumCollectionCount
;
927 if(lpCollectDataTimeout
!= NULL
)
930 *lpCollectDataTimeout
= 0;
934 if (lpUserName
!= NULL
)
936 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
937 retreive the user name with GetUserName(), revert the impersonation
938 and finally restore the thread token */
950 GetNamedPipeHandleStateA(HANDLE hNamedPipe
,
952 LPDWORD lpCurInstances
,
953 LPDWORD lpMaxCollectionCount
,
954 LPDWORD lpCollectDataTimeout
,
956 DWORD nMaxUserNameSize
)
958 UNICODE_STRING UserNameW
= { 0, 0, NULL
};
959 ANSI_STRING UserNameA
;
962 if(lpUserName
!= NULL
)
964 UserNameW
.MaximumLength
= (USHORT
)nMaxUserNameSize
* sizeof(WCHAR
);
965 UserNameW
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW
.MaximumLength
);
966 if (UserNameW
.Buffer
== NULL
)
968 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
972 UserNameA
.Buffer
= lpUserName
;
973 UserNameA
.Length
= 0;
974 UserNameA
.MaximumLength
= (USHORT
)nMaxUserNameSize
;
977 Ret
= GetNamedPipeHandleStateW(hNamedPipe
,
980 lpMaxCollectionCount
,
981 lpCollectDataTimeout
,
984 if (Ret
&& lpUserName
!= NULL
)
988 RtlInitUnicodeString(&UserNameW
, UserNameW
.Buffer
);
989 Status
= RtlUnicodeStringToAnsiString(&UserNameA
, &UserNameW
, FALSE
);
990 if (!NT_SUCCESS(Status
))
992 SetLastErrorByStatus(Status
);
997 if (UserNameW
.Buffer
!= NULL
)
999 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW
.Buffer
);
1011 GetNamedPipeInfo(HANDLE hNamedPipe
,
1013 LPDWORD lpOutBufferSize
,
1014 LPDWORD lpInBufferSize
,
1015 LPDWORD lpMaxInstances
)
1017 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation
;
1018 IO_STATUS_BLOCK StatusBlock
;
1021 Status
= NtQueryInformationFile(hNamedPipe
,
1023 &PipeLocalInformation
,
1024 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
1025 FilePipeLocalInformation
);
1026 if (!NT_SUCCESS(Status
))
1028 SetLastErrorByStatus(Status
);
1032 if (lpFlags
!= NULL
)
1034 *lpFlags
= (PipeLocalInformation
.NamedPipeEnd
== FILE_PIPE_SERVER_END
) ? PIPE_SERVER_END
: PIPE_CLIENT_END
;
1035 *lpFlags
|= (PipeLocalInformation
.NamedPipeType
== 1) ? PIPE_TYPE_MESSAGE
: PIPE_TYPE_BYTE
;
1038 if (lpOutBufferSize
!= NULL
)
1039 *lpOutBufferSize
= PipeLocalInformation
.OutboundQuota
;
1041 if (lpInBufferSize
!= NULL
)
1042 *lpInBufferSize
= PipeLocalInformation
.InboundQuota
;
1044 if (lpMaxInstances
!= NULL
)
1046 if (PipeLocalInformation
.MaximumInstances
>= 255)
1047 *lpMaxInstances
= PIPE_UNLIMITED_INSTANCES
;
1049 *lpMaxInstances
= PipeLocalInformation
.MaximumInstances
;
1061 PeekNamedPipe(HANDLE hNamedPipe
,
1064 LPDWORD lpBytesRead
,
1065 LPDWORD lpTotalBytesAvail
,
1066 LPDWORD lpBytesLeftThisMessage
)
1068 PFILE_PIPE_PEEK_BUFFER Buffer
;
1069 IO_STATUS_BLOCK Iosb
;
1074 /* Calculate the buffer space that we'll need and allocate it */
1075 BufferSize
= nBufferSize
+ sizeof(FILE_PIPE_PEEK_BUFFER
);
1076 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize
);
1079 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1083 /* Tell the driver to seek */
1084 Status
= NtFsControlFile(hNamedPipe
,
1094 if (Status
== STATUS_PENDING
)
1096 /* Wait for npfs to be done, and update the status */
1097 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
1098 if (NT_SUCCESS(Status
))
1099 Status
= Iosb
.Status
;
1102 /* Overflow is success for us */
1103 if (Status
== STATUS_BUFFER_OVERFLOW
)
1104 Status
= STATUS_SUCCESS
;
1107 if (!NT_SUCCESS(Status
))
1109 /* Free the buffer and return failure */
1110 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1111 SetLastErrorByStatus(Status
);
1115 /* Check if caller requested bytes available */
1116 if (lpTotalBytesAvail
)
1117 *lpTotalBytesAvail
= Buffer
->ReadDataAvailable
;
1119 /* Calculate the bytes returned, minus our structure overhead */
1120 BytesRead
= (ULONG
)(Iosb
.Information
-
1121 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]));
1123 /* Check if caller requested bytes read */
1126 /* Return the bytes read */
1127 *lpBytesRead
= BytesRead
;
1130 /* Check if caller requested bytes left */
1131 if (lpBytesLeftThisMessage
)
1133 /* Calculate total minus what we returned and our structure overhead */
1134 *lpBytesLeftThisMessage
= Buffer
->MessageLength
- BytesRead
;
1137 /* Check if the caller wanted to see the actual data */
1140 /* Give him what he wants */
1141 RtlCopyMemory(lpBuffer
,
1146 /* Free the buffer */
1147 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1158 TransactNamedPipe(IN HANDLE hNamedPipe
,
1159 IN LPVOID lpInBuffer
,
1160 IN DWORD nInBufferSize
,
1161 OUT LPVOID lpOutBuffer
,
1162 IN DWORD nOutBufferSize
,
1163 OUT LPDWORD lpBytesRead OPTIONAL
,
1164 IN LPOVERLAPPED lpOverlapped OPTIONAL
)
1168 if (lpBytesRead
!= NULL
)
1173 if (lpOverlapped
!= NULL
)
1177 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
1178 lpOverlapped
->Internal
= STATUS_PENDING
;
1180 Status
= NtFsControlFile(hNamedPipe
,
1181 lpOverlapped
->hEvent
,
1184 (PIO_STATUS_BLOCK
)lpOverlapped
,
1185 FSCTL_PIPE_TRANSCEIVE
,
1190 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
1192 SetLastErrorByStatus(Status
);
1196 if (lpBytesRead
!= NULL
)
1198 *lpBytesRead
= lpOverlapped
->InternalHigh
;
1203 #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */
1204 IO_STATUS_BLOCK Iosb
;
1206 Status
= NtFsControlFile(hNamedPipe
,
1211 FSCTL_PIPE_TRANSCEIVE
,
1216 if (Status
== STATUS_PENDING
)
1218 Status
= NtWaitForSingleObject(hNamedPipe
,
1221 if (NT_SUCCESS(Status
))
1222 Status
= Iosb
.Status
;
1225 if (NT_SUCCESS(Status
))
1227 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1228 check that case either and crashes (only after the operation
1230 *lpBytesRead
= Iosb
.Information
;
1234 SetLastErrorByStatus(Status
);
1237 #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */
1240 while (0 != nInBufferSize
&&
1241 WriteFile(hNamedPipe
, lpInBuffer
, nInBufferSize
, &nActualBytes
,
1244 lpInBuffer
= (LPVOID
)((char *) lpInBuffer
+ nActualBytes
);
1245 nInBufferSize
-= nActualBytes
;
1248 if (0 != nInBufferSize
)
1250 /* Must have dropped out of the while 'cause WriteFile failed */
1254 if (!ReadFile(hNamedPipe
, lpOutBuffer
, nOutBufferSize
, &nActualBytes
,
1260 if (NULL
!= lpBytesRead
)
1262 *lpBytesRead
= nActualBytes
;