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 *****************************************************************/
15 //#define USING_PROPER_NPFS_WAIT_SEMANTICS
18 /* FUNCTIONS ****************************************************************/
25 CreateNamedPipeA(LPCSTR lpName
,
31 DWORD nDefaultTimeOut
,
32 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
34 PUNICODE_STRING NameU
= &NtCurrentTeb()->StaticUnicodeString
;
37 /* Initialize the string as ANSI_STRING and convert to Unicode */
38 RtlInitAnsiString(&NameA
, (LPSTR
)lpName
);
39 RtlAnsiStringToUnicodeString(NameU
, &NameA
, FALSE
);
41 /* Call the Unicode API */
42 return CreateNamedPipeW(NameU
->Buffer
,
49 lpSecurityAttributes
);
58 CreateNamedPipeW(LPCWSTR lpName
,
64 DWORD nDefaultTimeOut
,
65 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
67 UNICODE_STRING NamedPipeName
;
70 OBJECT_ATTRIBUTES ObjectAttributes
;
72 ACCESS_MASK DesiredAccess
;
73 ULONG CreateOptions
= 0;
74 ULONG WriteModeMessage
;
75 ULONG ReadModeMessage
;
78 ULONG ShareAccess
= 0, Attributes
;
79 LARGE_INTEGER DefaultTimeOut
;
80 PSECURITY_DESCRIPTOR SecurityDescriptor
= NULL
;
82 /* Check for valid instances */
83 if (nMaxInstances
== 0 || nMaxInstances
> PIPE_UNLIMITED_INSTANCES
)
86 SetLastError(ERROR_INVALID_PARAMETER
);
87 return INVALID_HANDLE_VALUE
;
90 /* Convert to NT syntax */
91 if (nMaxInstances
== PIPE_UNLIMITED_INSTANCES
)
94 /* Convert the name */
95 Result
= RtlDosPathNameToNtPathName_U(lpName
,
101 /* Conversion failed */
102 SetLastError(ERROR_PATH_NOT_FOUND
);
103 return INVALID_HANDLE_VALUE
;
106 DPRINT("Pipe name: %wZ\n", &NamedPipeName
);
107 DPRINT("Pipe name: %S\n", NamedPipeName
.Buffer
);
109 /* Always case insensitive, check if we got extra attributes */
110 Attributes
= OBJ_CASE_INSENSITIVE
;
111 if(lpSecurityAttributes
)
113 /* We did; get the security descriptor */
114 SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
116 /* And check if this is pipe's handle will beinheritable */
117 if (lpSecurityAttributes
->bInheritHandle
)
118 Attributes
|= OBJ_INHERIT
;
121 /* Now we can initialize the object attributes */
122 InitializeObjectAttributes(&ObjectAttributes
,
128 /* Setup the default Desired Access */
129 DesiredAccess
= SYNCHRONIZE
| (dwOpenMode
& (WRITE_DAC
|
131 ACCESS_SYSTEM_SECURITY
));
133 /* Convert to NT Create Flags */
134 if (dwOpenMode
& FILE_FLAG_WRITE_THROUGH
)
136 CreateOptions
|= FILE_WRITE_THROUGH
;
139 if (!(dwOpenMode
& FILE_FLAG_OVERLAPPED
))
141 CreateOptions
|= FILE_SYNCHRONOUS_IO_NONALERT
;
144 /* Handle all open modes */
145 if (dwOpenMode
& PIPE_ACCESS_OUTBOUND
)
147 ShareAccess
|= FILE_SHARE_READ
;
148 DesiredAccess
|= GENERIC_WRITE
;
151 if (dwOpenMode
& PIPE_ACCESS_INBOUND
)
153 ShareAccess
|= FILE_SHARE_WRITE
;
154 DesiredAccess
|= GENERIC_READ
;
157 /* Handle the type flags */
158 if (dwPipeMode
& PIPE_TYPE_MESSAGE
)
160 WriteModeMessage
= FILE_PIPE_MESSAGE_TYPE
;
164 WriteModeMessage
= FILE_PIPE_BYTE_STREAM_TYPE
;
167 /* Handle the mode flags */
168 if (dwPipeMode
& PIPE_READMODE_MESSAGE
)
170 ReadModeMessage
= FILE_PIPE_MESSAGE_MODE
;
174 ReadModeMessage
= FILE_PIPE_BYTE_STREAM_MODE
;
177 /* Handle the blocking mode */
178 if (dwPipeMode
& PIPE_NOWAIT
)
180 NonBlocking
= FILE_PIPE_COMPLETE_OPERATION
;
184 NonBlocking
= FILE_PIPE_QUEUE_OPERATION
;
187 /* Check if we have a timeout */
190 /* Convert the time to NT format */
191 DefaultTimeOut
.QuadPart
= UInt32x32To64(nDefaultTimeOut
, -10000);
195 /* Use default timeout of 50 ms */
196 DefaultTimeOut
.QuadPart
= -500000;
199 /* Now create the pipe */
200 Status
= NtCreateNamedPipeFile(&PipeHandle
,
215 /* Normalize special error codes */
216 if ((Status
== STATUS_INVALID_DEVICE_REQUEST
) ||
217 (Status
== STATUS_NOT_SUPPORTED
))
219 Status
= STATUS_OBJECT_NAME_INVALID
;
223 RtlFreeHeap(RtlGetProcessHeap(),
225 NamedPipeName
.Buffer
);
228 if (!NT_SUCCESS(Status
))
230 /* Failed to create it */
231 DPRINT1("NtCreateNamedPipe failed (Status %x)!\n", Status
);
232 SetLastErrorByStatus (Status
);
233 return INVALID_HANDLE_VALUE
;
236 /* Return the handle */
246 WaitNamedPipeA(LPCSTR lpNamedPipeName
,
250 UNICODE_STRING NameU
;
252 /* Convert the name to Unicode */
253 Basep8BitStringToLiveUnicodeString(&NameU
, lpNamedPipeName
);
255 /* Call the Unicode API */
256 r
= WaitNamedPipeW(NameU
.Buffer
, nTimeOut
);
258 /* Free the Unicode string */
259 RtlFreeUnicodeString(&NameU
);
267 * When NPFS will work properly, use this code instead. It is compatible with
268 * Microsoft's NPFS.SYS. The main difference is that:
269 * - This code actually respects the timeout instead of ignoring it!
270 * - This code validates and creates the proper names for both UNC and local pipes
271 * - On NT, you open the *root* pipe directory (either \DosDevices\Pipe or
272 * \DosDevices\Unc\Server\Pipe) and then send the pipe to wait on in the
273 * FILE_PIPE_WAIT_FOR_BUFFER structure.
275 #ifdef USING_PROPER_NPFS_WAIT_SEMANTICS
281 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
284 UNICODE_STRING NamedPipeName
, NewName
, DevicePath
, PipePrefix
;
289 OBJECT_ATTRIBUTES ObjectAttributes
;
292 IO_STATUS_BLOCK IoStatusBlock
;
293 ULONG WaitPipeInfoSize
;
294 PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo
;
296 /* Start by making a unicode string of the name */
297 DPRINT("Sent path: %S\n", lpNamedPipeName
);
298 RtlCreateUnicodeString(&NamedPipeName
, lpNamedPipeName
);
299 NameLength
= NamedPipeName
.Length
/ sizeof(WCHAR
);
301 /* All slashes must become backslashes */
302 for (i
= 0; i
< NameLength
; i
++)
304 /* Check and convert */
305 if (NamedPipeName
.Buffer
[i
] == L
'/') NamedPipeName
.Buffer
[i
] = L
'\\';
308 /* Find the path type of the name we were given */
309 NewName
= NamedPipeName
;
310 Type
= RtlDetermineDosPathNameType_U(lpNamedPipeName
);
312 /* Check if this was a device path, ie : "\\.\pipe\name" */
313 if (Type
== RtlPathTypeLocalDevice
)
315 /* Make sure it's a valid prefix */
316 RtlInitUnicodeString(&PipePrefix
, L
"\\\\.\\pipe\\");
317 RtlPrefixString((PANSI_STRING
)&PipePrefix
, (PANSI_STRING
)&NewName
, TRUE
);
321 NewName
.Length
-= 9 * sizeof(WCHAR
);
323 /* Initialize the Dos Devices name */
324 DPRINT("NewName: %wZ\n", &NewName
);
325 RtlInitUnicodeString(&DevicePath
, L
"\\DosDevices\\pipe\\");
327 else if (Type
== RtlPathTypeRootLocalDevice
)
329 /* The path is \\server\\pipe\name; find the pipename itself */
330 p
= &NewName
.Buffer
[2];
332 /* First loop to get past the server name */
335 /* Check if this is a backslash */
336 if (*p
== L
'\\') break;
342 /* Now make sure the full name contains "pipe\" */
343 if ((*p
) && !(_wcsnicmp(p
+ 1, L
"pipe\\", sizeof("pipe\\"))))
345 /* Get to the pipe name itself now */
346 p
+= sizeof("pipe\\") - 1;
350 /* The name is invalid */
351 DPRINT1("Invalid name!\n");
352 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD
);
356 /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
360 DPRINT1("Invalid path type\n");
361 SetLastErrorByStatus(STATUS_OBJECT_PATH_SYNTAX_BAD
);
365 /* Now calculate the total length of the structure and allocate it */
366 WaitPipeInfoSize
= FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER
, Name
[0]) +
368 WaitPipeInfo
= RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize
);
369 if (WaitPipeInfo
== NULL
)
371 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
375 /* Initialize the object attributes */
376 DPRINT("Opening: %wZ\n", &DevicePath
);
377 InitializeObjectAttributes(&ObjectAttributes
,
379 OBJ_CASE_INSENSITIVE
,
384 Status
= NtOpenFile(&FileHandle
,
385 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
388 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
389 FILE_SYNCHRONOUS_IO_NONALERT
);
390 if (!NT_SUCCESS(Status
))
392 /* Fail; couldn't open */
393 DPRINT1("Status: %lx\n", Status
);
394 SetLastErrorByStatus(Status
);
395 RtlFreeUnicodeString(&NamedPipeName
);
396 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
400 /* Check what timeout we got */
401 if (nTimeOut
== NMPWAIT_USE_DEFAULT_WAIT
)
403 /* Don't use a timeout */
404 WaitPipeInfo
->TimeoutSpecified
= FALSE
;
408 /* Check if we should wait forever */
409 if (nTimeOut
== NMPWAIT_WAIT_FOREVER
)
412 WaitPipeInfo
->Timeout
.LowPart
= 0;
413 WaitPipeInfo
->Timeout
.HighPart
= 0x80000000;
417 /* Convert to NT format */
418 WaitPipeInfo
->Timeout
.QuadPart
= UInt32x32To64(-10000, nTimeOut
);
421 /* In both cases, we do have a timeout */
422 WaitPipeInfo
->TimeoutSpecified
= FALSE
;
425 /* Set the length and copy the name */
426 WaitPipeInfo
->NameLength
= NewName
.Length
;
427 RtlCopyMemory(WaitPipeInfo
->Name
, NewName
.Buffer
, NewName
.Length
);
429 /* Get rid of the full name */
430 RtlFreeUnicodeString(&NamedPipeName
);
432 /* Let NPFS know of our request */
433 Status
= NtFsControlFile(FileHandle
,
444 /* Free our pipe info data and close the handle */
445 RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo
);
448 /* Check the status */
449 if (!NT_SUCCESS(Status
))
451 /* Failure to wait on the pipe */
452 DPRINT1("Status: %lx\n", Status
);
453 SetLastErrorByStatus (Status
);
466 WaitNamedPipeW(LPCWSTR lpNamedPipeName
,
469 UNICODE_STRING NamedPipeName
;
471 OBJECT_ATTRIBUTES ObjectAttributes
;
472 FILE_PIPE_WAIT_FOR_BUFFER WaitPipe
;
474 IO_STATUS_BLOCK Iosb
;
476 if (RtlDosPathNameToNtPathName_U(lpNamedPipeName
,
484 InitializeObjectAttributes(&ObjectAttributes
,
486 OBJ_CASE_INSENSITIVE
,
489 Status
= NtOpenFile(&FileHandle
,
490 FILE_READ_ATTRIBUTES
| SYNCHRONIZE
,
493 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
494 FILE_SYNCHRONOUS_IO_NONALERT
);
495 if (!NT_SUCCESS(Status
))
497 SetLastErrorByStatus(Status
);
501 /* Check what timeout we got */
502 if (nTimeOut
== NMPWAIT_USE_DEFAULT_WAIT
)
504 /* Don't use a timeout */
505 WaitPipe
.TimeoutSpecified
= FALSE
;
509 /* Check if we should wait forever */
510 if (nTimeOut
== NMPWAIT_WAIT_FOREVER
)
513 WaitPipe
.Timeout
.LowPart
= 0;
514 WaitPipe
.Timeout
.HighPart
= 0x80000000;
518 /* Convert to NT format */
519 WaitPipe
.Timeout
.QuadPart
= UInt32x32To64(-10000, nTimeOut
);
522 /* In both cases, we do have a timeout */
523 WaitPipe
.TimeoutSpecified
= FALSE
;
526 Status
= NtFsControlFile(FileHandle
,
537 if (!NT_SUCCESS(Status
))
539 SetLastErrorByStatus(Status
);
553 ConnectNamedPipe(IN HANDLE hNamedPipe
,
554 IN LPOVERLAPPED lpOverlapped
)
558 if (lpOverlapped
!= NULL
)
562 lpOverlapped
->Internal
= STATUS_PENDING
;
563 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
565 Status
= NtFsControlFile(hNamedPipe
,
566 lpOverlapped
->hEvent
,
569 (PIO_STATUS_BLOCK
)lpOverlapped
,
576 /* return FALSE in case of failure and pending operations! */
577 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
579 SetLastErrorByStatus(Status
);
585 IO_STATUS_BLOCK Iosb
;
587 Status
= NtFsControlFile(hNamedPipe
,
598 /* wait in case operation is pending */
599 if (Status
== STATUS_PENDING
)
601 Status
= NtWaitForSingleObject(hNamedPipe
,
604 if (NT_SUCCESS(Status
))
606 Status
= Iosb
.Status
;
610 if (!NT_SUCCESS(Status
))
612 SetLastErrorByStatus(Status
);
626 SetNamedPipeHandleState(HANDLE hNamedPipe
,
628 LPDWORD lpMaxCollectionCount
,
629 LPDWORD lpCollectDataTimeout
)
631 IO_STATUS_BLOCK Iosb
;
634 /* Check if the Mode is being changed */
637 FILE_PIPE_INFORMATION Settings
;
639 /* Set the Completion Mode */
640 Settings
.CompletionMode
= (*lpMode
& PIPE_NOWAIT
) ?
641 FILE_PIPE_COMPLETE_OPERATION
: FILE_PIPE_QUEUE_OPERATION
;
643 /* Set the Read Mode */
644 Settings
.ReadMode
= (*lpMode
& PIPE_READMODE_MESSAGE
) ?
645 FILE_PIPE_MESSAGE_MODE
: FILE_PIPE_BYTE_STREAM_MODE
;
647 /* Send the changes to the Driver */
648 Status
= NtSetInformationFile(hNamedPipe
,
651 sizeof(FILE_PIPE_INFORMATION
),
652 FilePipeInformation
);
653 if (!NT_SUCCESS(Status
))
655 SetLastErrorByStatus(Status
);
660 /* Check if the Collection count or Timeout are being changed */
661 if (lpMaxCollectionCount
|| lpCollectDataTimeout
)
663 FILE_PIPE_REMOTE_INFORMATION RemoteSettings
;
665 /* Setting one without the other would delete it, so we read old one */
666 if (!lpMaxCollectionCount
|| !lpCollectDataTimeout
)
668 Status
= NtQueryInformationFile(hNamedPipe
,
671 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
672 FilePipeRemoteInformation
);
673 if (!NT_SUCCESS(Status
))
675 SetLastErrorByStatus(Status
);
680 /* Now set the new settings */
681 RemoteSettings
.MaximumCollectionCount
= (lpMaxCollectionCount
) ?
682 *lpMaxCollectionCount
:
683 RemoteSettings
.MaximumCollectionCount
;
684 if (lpCollectDataTimeout
)
686 /* Convert it to Quad */
687 RemoteSettings
.CollectDataTime
.QuadPart
=
688 -(LONGLONG
)UInt32x32To64(10000, *lpCollectDataTimeout
);
691 /* Tell the driver to change them */
692 Status
= NtSetInformationFile(hNamedPipe
,
695 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
696 FilePipeRemoteInformation
);
697 if (!NT_SUCCESS(Status
))
699 SetLastErrorByStatus(Status
);
713 CallNamedPipeA(LPCSTR lpNamedPipeName
,
717 DWORD nOutBufferSize
,
721 PUNICODE_STRING PipeName
= &NtCurrentTeb()->StaticUnicodeString
;
722 ANSI_STRING AnsiPipe
;
724 /* Initialize the string as ANSI_STRING and convert to Unicode */
725 RtlInitAnsiString(&AnsiPipe
, (LPSTR
)lpNamedPipeName
);
726 RtlAnsiStringToUnicodeString(PipeName
, &AnsiPipe
, FALSE
);
728 /* Call the Unicode function */
729 return CallNamedPipeW(PipeName
->Buffer
,
744 CallNamedPipeW(LPCWSTR lpNamedPipeName
,
748 DWORD nOutBufferSize
,
759 /* Try creating it */
760 hPipe
= CreateFileW(lpNamedPipeName
,
761 GENERIC_READ
| GENERIC_WRITE
,
762 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
765 FILE_ATTRIBUTE_NORMAL
,
768 /* Success, break out */
769 if (hPipe
!= INVALID_HANDLE_VALUE
)
772 /* Already tried twice, give up */
777 WaitNamedPipeW(lpNamedPipeName
, nTimeOut
);
779 /* Get ready to try again */
783 /* Set the pipe mode */
784 dwPipeMode
= PIPE_READMODE_MESSAGE
| PIPE_WAIT
;
785 bError
= SetNamedPipeHandleState(hPipe
, &dwPipeMode
, NULL
, NULL
);
788 /* Couldn't change state, fail */
793 /* Do the transact */
794 bError
= TransactNamedPipe(hPipe
,
802 /* Close the handle */
814 DisconnectNamedPipe(HANDLE hNamedPipe
)
816 IO_STATUS_BLOCK Iosb
;
819 /* Send the FSCTL to the driver */
820 Status
= NtFsControlFile(hNamedPipe
,
825 FSCTL_PIPE_DISCONNECT
,
830 if (Status
== STATUS_PENDING
)
832 /* Wait on NPFS to finish and get updated status */
833 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
834 if (NT_SUCCESS(Status
))
835 Status
= Iosb
.Status
;
838 /* Check for error */
839 if (!NT_SUCCESS(Status
))
842 SetLastErrorByStatus(Status
);
855 GetNamedPipeHandleStateW(HANDLE hNamedPipe
,
857 LPDWORD lpCurInstances
,
858 LPDWORD lpMaxCollectionCount
,
859 LPDWORD lpCollectDataTimeout
,
861 DWORD nMaxUserNameSize
)
863 IO_STATUS_BLOCK StatusBlock
;
868 FILE_PIPE_INFORMATION PipeInfo
;
870 Status
= NtQueryInformationFile(hNamedPipe
,
873 sizeof(FILE_PIPE_INFORMATION
),
874 FilePipeInformation
);
875 if (!NT_SUCCESS(Status
))
877 SetLastErrorByStatus(Status
);
881 *lpState
= ((PipeInfo
.CompletionMode
!= FILE_PIPE_QUEUE_OPERATION
) ? PIPE_NOWAIT
: PIPE_WAIT
);
882 *lpState
|= ((PipeInfo
.ReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
) ? PIPE_READMODE_MESSAGE
: PIPE_READMODE_BYTE
);
885 if(lpCurInstances
!= NULL
)
887 FILE_PIPE_LOCAL_INFORMATION LocalInfo
;
889 Status
= NtQueryInformationFile(hNamedPipe
,
892 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
893 FilePipeLocalInformation
);
894 if (!NT_SUCCESS(Status
))
896 SetLastErrorByStatus(Status
);
900 *lpCurInstances
= min(LocalInfo
.CurrentInstances
, PIPE_UNLIMITED_INSTANCES
);
903 if (lpMaxCollectionCount
!= NULL
|| lpCollectDataTimeout
!= NULL
)
905 FILE_PIPE_REMOTE_INFORMATION RemoteInfo
;
907 Status
= NtQueryInformationFile(hNamedPipe
,
910 sizeof(FILE_PIPE_REMOTE_INFORMATION
),
911 FilePipeRemoteInformation
);
912 if (!NT_SUCCESS(Status
))
914 SetLastErrorByStatus(Status
);
918 if (lpMaxCollectionCount
!= NULL
)
920 *lpMaxCollectionCount
= RemoteInfo
.MaximumCollectionCount
;
923 if(lpCollectDataTimeout
!= NULL
)
926 *lpCollectDataTimeout
= 0;
930 if (lpUserName
!= NULL
)
932 /* FIXME - open the thread token, call ImpersonateNamedPipeClient() and
933 retreive the user name with GetUserName(), revert the impersonation
934 and finally restore the thread token */
946 GetNamedPipeHandleStateA(HANDLE hNamedPipe
,
948 LPDWORD lpCurInstances
,
949 LPDWORD lpMaxCollectionCount
,
950 LPDWORD lpCollectDataTimeout
,
952 DWORD nMaxUserNameSize
)
954 UNICODE_STRING UserNameW
= {0};
955 ANSI_STRING UserNameA
;
958 if(lpUserName
!= NULL
)
960 UserNameW
.MaximumLength
= (USHORT
)nMaxUserNameSize
* sizeof(WCHAR
);
961 UserNameW
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, UserNameW
.MaximumLength
);
962 if (UserNameW
.Buffer
== NULL
)
964 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
968 UserNameA
.Buffer
= lpUserName
;
969 UserNameA
.Length
= 0;
970 UserNameA
.MaximumLength
= (USHORT
)nMaxUserNameSize
;
973 Ret
= GetNamedPipeHandleStateW(hNamedPipe
,
976 lpMaxCollectionCount
,
977 lpCollectDataTimeout
,
980 if (Ret
&& lpUserName
!= NULL
)
984 RtlInitUnicodeString(&UserNameW
, UserNameW
.Buffer
);
985 Status
= RtlUnicodeStringToAnsiString(&UserNameA
, &UserNameW
, FALSE
);
986 if (!NT_SUCCESS(Status
))
988 SetLastErrorByStatus(Status
);
993 if (UserNameW
.Buffer
!= NULL
)
995 RtlFreeHeap(RtlGetProcessHeap(), 0, UserNameW
.Buffer
);
1007 GetNamedPipeInfo(HANDLE hNamedPipe
,
1009 LPDWORD lpOutBufferSize
,
1010 LPDWORD lpInBufferSize
,
1011 LPDWORD lpMaxInstances
)
1013 FILE_PIPE_LOCAL_INFORMATION PipeLocalInformation
;
1014 IO_STATUS_BLOCK StatusBlock
;
1017 Status
= NtQueryInformationFile(hNamedPipe
,
1019 &PipeLocalInformation
,
1020 sizeof(FILE_PIPE_LOCAL_INFORMATION
),
1021 FilePipeLocalInformation
);
1022 if (!NT_SUCCESS(Status
))
1024 SetLastErrorByStatus(Status
);
1028 if (lpFlags
!= NULL
)
1030 *lpFlags
= (PipeLocalInformation
.NamedPipeEnd
== FILE_PIPE_SERVER_END
) ? PIPE_SERVER_END
: PIPE_CLIENT_END
;
1031 *lpFlags
|= (PipeLocalInformation
.NamedPipeType
== 1) ? PIPE_TYPE_MESSAGE
: PIPE_TYPE_BYTE
;
1034 if (lpOutBufferSize
!= NULL
)
1035 *lpOutBufferSize
= PipeLocalInformation
.OutboundQuota
;
1037 if (lpInBufferSize
!= NULL
)
1038 *lpInBufferSize
= PipeLocalInformation
.InboundQuota
;
1040 if (lpMaxInstances
!= NULL
)
1042 if (PipeLocalInformation
.MaximumInstances
>= 255)
1043 *lpMaxInstances
= PIPE_UNLIMITED_INSTANCES
;
1045 *lpMaxInstances
= PipeLocalInformation
.MaximumInstances
;
1057 PeekNamedPipe(HANDLE hNamedPipe
,
1060 LPDWORD lpBytesRead
,
1061 LPDWORD lpTotalBytesAvail
,
1062 LPDWORD lpBytesLeftThisMessage
)
1064 PFILE_PIPE_PEEK_BUFFER Buffer
;
1065 IO_STATUS_BLOCK Iosb
;
1070 /* Calculate the buffer space that we'll need and allocate it */
1071 BufferSize
= nBufferSize
+ FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]);
1072 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize
);
1075 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1079 /* Tell the driver to seek */
1080 Status
= NtFsControlFile(hNamedPipe
,
1090 if (Status
== STATUS_PENDING
)
1092 /* Wait for npfs to be done, and update the status */
1093 Status
= NtWaitForSingleObject(hNamedPipe
, FALSE
, NULL
);
1094 if (NT_SUCCESS(Status
))
1095 Status
= Iosb
.Status
;
1098 /* Overflow is success for us */
1099 if (Status
== STATUS_BUFFER_OVERFLOW
)
1100 Status
= STATUS_SUCCESS
;
1103 if (!NT_SUCCESS(Status
))
1105 /* Free the buffer and return failure */
1106 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1107 SetLastErrorByStatus(Status
);
1111 /* Check if caller requested bytes available */
1112 if (lpTotalBytesAvail
)
1113 *lpTotalBytesAvail
= Buffer
->ReadDataAvailable
;
1115 /* Calculate the bytes returned, minus our structure overhead */
1116 BytesRead
= (ULONG
)(Iosb
.Information
-
1117 FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
[0]));
1119 /* Check if caller requested bytes read */
1122 /* Return the bytes read */
1123 *lpBytesRead
= BytesRead
;
1126 /* Check if caller requested bytes left */
1127 if (lpBytesLeftThisMessage
)
1129 /* Calculate total minus what we returned and our structure overhead */
1130 *lpBytesLeftThisMessage
= Buffer
->MessageLength
- BytesRead
;
1133 /* Check if the caller wanted to see the actual data */
1136 /* Give him what he wants */
1137 RtlCopyMemory(lpBuffer
,
1142 /* Free the buffer */
1143 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
1154 TransactNamedPipe(IN HANDLE hNamedPipe
,
1155 IN LPVOID lpInBuffer
,
1156 IN DWORD nInBufferSize
,
1157 OUT LPVOID lpOutBuffer
,
1158 IN DWORD nOutBufferSize
,
1159 OUT LPDWORD lpBytesRead OPTIONAL
,
1160 IN LPOVERLAPPED lpOverlapped OPTIONAL
)
1164 if (lpBytesRead
!= NULL
)
1169 if (lpOverlapped
!= NULL
)
1173 ApcContext
= (((ULONG_PTR
)lpOverlapped
->hEvent
& 0x1) ? NULL
: lpOverlapped
);
1174 lpOverlapped
->Internal
= STATUS_PENDING
;
1176 Status
= NtFsControlFile(hNamedPipe
,
1177 lpOverlapped
->hEvent
,
1180 (PIO_STATUS_BLOCK
)lpOverlapped
,
1181 FSCTL_PIPE_TRANSCEIVE
,
1186 if (!NT_SUCCESS(Status
) || Status
== STATUS_PENDING
)
1188 SetLastErrorByStatus(Status
);
1192 if (lpBytesRead
!= NULL
)
1194 *lpBytesRead
= lpOverlapped
->InternalHigh
;
1199 #if 0 /* We don't implement FSCTL_PIPE_TRANSCEIVE yet */
1200 IO_STATUS_BLOCK Iosb
;
1202 Status
= NtFsControlFile(hNamedPipe
,
1207 FSCTL_PIPE_TRANSCEIVE
,
1212 if (Status
== STATUS_PENDING
)
1214 Status
= NtWaitForSingleObject(hNamedPipe
,
1217 if (NT_SUCCESS(Status
))
1218 Status
= Iosb
.Status
;
1221 if (NT_SUCCESS(Status
))
1223 /* lpNumberOfBytesRead must not be NULL here, in fact Win doesn't
1224 check that case either and crashes (only after the operation
1226 *lpBytesRead
= Iosb
.Information
;
1230 SetLastErrorByStatus(Status
);
1233 #else /* Workaround while FSCTL_PIPE_TRANSCEIVE not available */
1236 while (0 != nInBufferSize
&&
1237 WriteFile(hNamedPipe
, lpInBuffer
, nInBufferSize
, &nActualBytes
,
1240 lpInBuffer
= (LPVOID
)((char *) lpInBuffer
+ nActualBytes
);
1241 nInBufferSize
-= nActualBytes
;
1244 if (0 != nInBufferSize
)
1246 /* Must have dropped out of the while 'cause WriteFile failed */
1250 if (!ReadFile(hNamedPipe
, lpOutBuffer
, nOutBufferSize
, &nActualBytes
,
1256 if (NULL
!= lpBytesRead
)
1258 *lpBytesRead
= nActualBytes
;