* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/lpc/reply.c
* PURPOSE: Local Procedure Call: Receive (Replies)
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
VOID
NTAPI
LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
IN ULONG MessageId,
IN ULONG CallbackId,
IN CLIENT_ID ClientId)
{
PLPCP_MESSAGE Message;
PLIST_ENTRY ListHead, NextEntry;
if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
{
Port = Port->ConnectionPort;
if (!Port) return;
}
ListHead = &Port->LpcDataInfoChainHead;
NextEntry = ListHead->Flink;
while (ListHead != NextEntry)
{
Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
if ((Message->Request.MessageId == MessageId) &&
(Message->Request.ClientId.UniqueThread == ClientId.UniqueThread) &&
(Message->Request.ClientId.UniqueProcess == ClientId.UniqueProcess))
{
RemoveEntryList(&Message->Entry);
InitializeListHead(&Message->Entry);
LpcpFreeToPortZone(Message, LPCP_LOCK_HELD);
break;
}
NextEntry = NextEntry->Flink;
}
}
VOID
NTAPI
LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
IN PLPCP_MESSAGE Message,
IN ULONG LockFlags)
{
BOOLEAN LockHeld = (LockFlags & LPCP_LOCK_HELD);
PAGED_CODE();
if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
{
Port = Port->ConnectionPort;
if (!Port)
{
if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);
return;
}
}
InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry);
if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);
}
PLPCP_MESSAGE
NTAPI
LpcpFindDataInfoMessage(
IN PLPCP_PORT_OBJECT Port,
IN ULONG MessageId,
IN LPC_CLIENT_ID ClientId)
{
PLPCP_MESSAGE Message;
PLIST_ENTRY ListEntry;
PAGED_CODE();
if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
{
Port = Port->ConnectionPort;
if (!Port)
{
return NULL;
}
}
for (ListEntry = Port->LpcDataInfoChainHead.Flink;
ListEntry != &Port->LpcDataInfoChainHead;
ListEntry = ListEntry->Flink)
{
Message = CONTAINING_RECORD(ListEntry, LPCP_MESSAGE, Entry);
if ((Message->Request.MessageId == MessageId) &&
(Message->Request.ClientId.UniqueProcess == ClientId.UniqueProcess) &&
(Message->Request.ClientId.UniqueThread == ClientId.UniqueThread))
{
return Message;
}
}
return NULL;
}
VOID
NTAPI
LpcpMoveMessage(IN PPORT_MESSAGE Destination,
IN PPORT_MESSAGE Origin,
IN PVOID Data,
IN ULONG MessageType,
IN PCLIENT_ID ClientId)
{
LPCTRACE((LPC_REPLY_DEBUG | LPC_SEND_DEBUG),
"Destination/Origin: %p/%p. Data: %p. Length: %lx\n",
Destination,
Origin,
Data,
Origin->u1.Length);
Destination->u1.Length = Origin->u1.Length;
Destination->u2.s2.Type = !MessageType ?
Origin->u2.s2.Type : MessageType & 0xFFFF;
if (ClientId)
{
Destination->ClientId.UniqueProcess = ClientId->UniqueProcess;
Destination->ClientId.UniqueThread = ClientId->UniqueThread;
}
else
{
Destination->ClientId.UniqueProcess = Origin->ClientId.UniqueProcess;
Destination->ClientId.UniqueThread = Origin->ClientId.UniqueThread;
}
Destination->MessageId = Origin->MessageId;
Destination->ClientViewSize = Origin->ClientViewSize;
RtlCopyMemory(Destination + 1,
Data,
ALIGN_UP_BY(Destination->u1.s1.DataLength, sizeof(ULONG)));
}
* @implemented
*/
NTSTATUS
NTAPI
NtReplyPort(IN HANDLE PortHandle,
IN PPORT_MESSAGE ReplyMessage)
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PORT_MESSAGE CapturedReplyMessage;
PLPCP_PORT_OBJECT Port;
PLPCP_MESSAGE Message;
PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
PAGED_CODE();
LPCTRACE(LPC_REPLY_DEBUG,
"Handle: %p. Message: %p.\n",
PortHandle,
ReplyMessage);
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
CapturedReplyMessage = *ReplyMessage;
}
if (((ULONG)CapturedReplyMessage.u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
(ULONG)CapturedReplyMessage.u1.s1.TotalLength)
{
return STATUS_INVALID_PARAMETER;
}
if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER;
Status = ObReferenceObjectByHandle(PortHandle,
0,
LpcPortObjectType,
PreviousMode,
(PVOID*)&Port,
NULL);
if (!NT_SUCCESS(Status)) return Status;
if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) ||
((ULONG)CapturedReplyMessage.u1.s1.TotalLength <=
(ULONG)CapturedReplyMessage.u1.s1.DataLength))
{
ObDereferenceObject(Port);
return STATUS_PORT_MESSAGE_TOO_LONG;
}
Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId,
NULL,
&WakeupThread);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Port);
return Status;
}
Message = LpcpAllocateFromPortZone();
if (!Message)
{
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
return STATUS_NO_MEMORY;
}
KeAcquireGuardedMutex(&LpcpLock);
if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) ||
((LpcpGetMessageFromThread(WakeupThread)) &&
(LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)-> Request)
!= LPC_REQUEST)))
{
LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
return STATUS_REPLY_MESSAGE_MISMATCH;
}
_SEH2_TRY
{
LpcpMoveMessage(&Message->Request,
&CapturedReplyMessage,
ReplyMessage + 1,
LPC_REPLY,
NULL);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
ObReferenceObject(WakeupThread);
Message->RepliedToThread = WakeupThread;
WakeupThread->LpcReplyMessageId = 0;
WakeupThread->LpcReplyMessage = (PVOID)Message;
if (!(WakeupThread->LpcExitThreadCalled) &&
!(IsListEmpty(&WakeupThread->LpcReplyChain)))
{
RemoveEntryList(&WakeupThread->LpcReplyChain);
InitializeListHead(&WakeupThread->LpcReplyChain);
}
if ((Thread->LpcReceivedMsgIdValid) &&
(Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId))
{
Thread->LpcReceivedMessageId = 0;
Thread->LpcReceivedMsgIdValid = FALSE;
}
LpcpFreeDataInfoMessage(Port,
CapturedReplyMessage.MessageId,
CapturedReplyMessage.CallbackId,
CapturedReplyMessage.ClientId);
KeReleaseGuardedMutex(&LpcpLock);
LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
return Status;
}
* @implemented
*/
NTSTATUS
NTAPI
NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
OUT PVOID *PortContext OPTIONAL,
IN PPORT_MESSAGE ReplyMessage OPTIONAL,
OUT PPORT_MESSAGE ReceiveMessage,
IN PLARGE_INTEGER Timeout OPTIONAL)
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode;
PORT_MESSAGE CapturedReplyMessage;
LARGE_INTEGER CapturedTimeout;
PLPCP_PORT_OBJECT Port, ReceivePort, ConnectionPort = NULL;
PLPCP_MESSAGE Message;
PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
PLPCP_CONNECTION_MESSAGE ConnectMessage;
ULONG ConnectionInfoLength;
PAGED_CODE();
LPCTRACE(LPC_REPLY_DEBUG,
"Handle: %p. Messages: %p/%p. Context: %p\n",
PortHandle,
ReplyMessage,
ReceiveMessage,
PortContext);
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
if (PortContext != NULL)
ProbeForWritePointer(PortContext);
if (ReplyMessage != NULL)
{
ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
}
if (Timeout != NULL)
{
ProbeForReadLargeInteger(Timeout);
CapturedTimeout = *(volatile LARGE_INTEGER*)Timeout;
Timeout = &CapturedTimeout;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
if (Thread->SystemThread) WaitMode = UserMode;
if (ReplyMessage != NULL)
CapturedReplyMessage = *ReplyMessage;
}
if (ReplyMessage)
{
if (((ULONG)CapturedReplyMessage.u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
(ULONG)CapturedReplyMessage.u1.s1.TotalLength)
{
return STATUS_INVALID_PARAMETER;
}
if (!CapturedReplyMessage.MessageId) return STATUS_INVALID_PARAMETER;
}
Status = ObReferenceObjectByHandle(PortHandle,
0,
LpcPortObjectType,
PreviousMode,
(PVOID*)&Port,
NULL);
if (!NT_SUCCESS(Status)) return Status;
if (ReplyMessage)
{
if (((ULONG)CapturedReplyMessage.u1.s1.TotalLength > Port->MaxMessageLength) ||
((ULONG)CapturedReplyMessage.u1.s1.TotalLength <=
(ULONG)CapturedReplyMessage.u1.s1.DataLength))
{
ObDereferenceObject(Port);
return STATUS_PORT_MESSAGE_TOO_LONG;
}
}
if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CLIENT_PORT)
{
if (Port->ConnectionPort == Port)
{
ConnectionPort = ReceivePort = Port;
ObReferenceObject(ConnectionPort);
}
else
{
KeAcquireGuardedMutex(&LpcpLock);
ConnectionPort = ReceivePort = Port->ConnectionPort;
if (!ConnectionPort)
{
KeReleaseGuardedMutex(&LpcpLock);
ObDereferenceObject(Port);
return STATUS_PORT_DISCONNECTED;
}
ObReferenceObject(ConnectionPort);
KeReleaseGuardedMutex(&LpcpLock);
}
}
else
{
ReceivePort = Port;
}
if (ReplyMessage)
{
Status = PsLookupProcessThreadByCid(&CapturedReplyMessage.ClientId,
NULL,
&WakeupThread);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Port);
if (ConnectionPort) ObDereferenceObject(ConnectionPort);
return Status;
}
Message = LpcpAllocateFromPortZone();
if (!Message)
{
if (ConnectionPort) ObDereferenceObject(ConnectionPort);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
return STATUS_NO_MEMORY;
}
KeAcquireGuardedMutex(&LpcpLock);
if ((WakeupThread->LpcReplyMessageId != CapturedReplyMessage.MessageId) ||
((LpcpGetMessageFromThread(WakeupThread)) &&
(LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->Request)
!= LPC_REQUEST)))
{
LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
if (ConnectionPort) ObDereferenceObject(ConnectionPort);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
return STATUS_REPLY_MESSAGE_MISMATCH;
}
_SEH2_TRY
{
LpcpMoveMessage(&Message->Request,
&CapturedReplyMessage,
ReplyMessage + 1,
LPC_REPLY,
NULL);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
if (ConnectionPort) ObDereferenceObject(ConnectionPort);
ObDereferenceObject(WakeupThread);
ObDereferenceObject(Port);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
ObReferenceObject(WakeupThread);
Message->RepliedToThread = WakeupThread;
WakeupThread->LpcReplyMessageId = 0;
WakeupThread->LpcReplyMessage = (PVOID)Message;
if (!(WakeupThread->LpcExitThreadCalled) &&
!(IsListEmpty(&WakeupThread->LpcReplyChain)))
{
RemoveEntryList(&WakeupThread->LpcReplyChain);
InitializeListHead(&WakeupThread->LpcReplyChain);
}
if ((Thread->LpcReceivedMsgIdValid) &&
(Thread->LpcReceivedMessageId == CapturedReplyMessage.MessageId))
{
Thread->LpcReceivedMessageId = 0;
Thread->LpcReceivedMsgIdValid = FALSE;
}
LpcpFreeDataInfoMessage(Port,
CapturedReplyMessage.MessageId,
CapturedReplyMessage.CallbackId,
CapturedReplyMessage.ClientId);
KeReleaseGuardedMutex(&LpcpLock);
LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
ObDereferenceObject(WakeupThread);
}
LpcpReceiveWait(ReceivePort->MsgQueue.Semaphore, WaitMode);
if (Status != STATUS_SUCCESS) goto Cleanup;
KeAcquireGuardedMutex(&LpcpLock);
if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
{
if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
{
KeClearEvent(&ReceivePort->WaitEvent);
}
KeReleaseGuardedMutex(&LpcpLock);
if (ConnectionPort) ObDereferenceObject(ConnectionPort);
ObDereferenceObject(Port);
return STATUS_UNSUCCESSFUL;
}
Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->MsgQueue.ReceiveHead),
LPCP_MESSAGE,
Entry);
if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
{
if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
{
KeClearEvent(&ReceivePort->WaitEvent);
}
}
InitializeListHead(&Message->Entry);
Thread->LpcReceivedMessageId = Message->Request.MessageId;
Thread->LpcReceivedMsgIdValid = TRUE;
_SEH2_TRY
{
if (LpcpGetMessageType(&Message->Request) == LPC_CONNECTION_REQUEST)
{
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
LPCTRACE(LPC_REPLY_DEBUG,
"Request Messages: %p/%p\n",
Message,
ConnectMessage);
ConnectionInfoLength = Message->Request.u1.s1.DataLength -
sizeof(LPCP_CONNECTION_MESSAGE);
*ReceiveMessage = Message->Request;
Message = NULL;
ReceiveMessage->u1.s1.TotalLength = (CSHORT)(sizeof(PORT_MESSAGE) +
ConnectionInfoLength);
ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength;
RtlCopyMemory(ReceiveMessage + 1,
ConnectMessage + 1,
ConnectionInfoLength);
if (PortContext) *PortContext = NULL;
}
else if (LpcpGetMessageType(&Message->Request) != LPC_REPLY)
{
LPCTRACE(LPC_REPLY_DEBUG,
"Non-Reply Messages: %p/%p\n",
&Message->Request,
(&Message->Request) + 1);
LpcpMoveMessage(ReceiveMessage,
&Message->Request,
(&Message->Request) + 1,
0,
NULL);
if (PortContext) *PortContext = Message->PortContext;
if (Message->Request.u2.s2.DataInfoOffset)
{
LpcpSaveDataInfoMessage(Port, Message, LPCP_LOCK_HELD);
Message = NULL;
}
}
else
{
ASSERT(FALSE);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
if (Message)
{
LpcpFreeToPortZone(Message, LPCP_LOCK_HELD | LPCP_LOCK_RELEASE);
}
else
{
KeReleaseGuardedMutex(&LpcpLock);
}
Cleanup:
LPCTRACE(LPC_REPLY_DEBUG,
"Port: %p. Status: %d\n",
Port,
Status);
if (ConnectionPort) ObDereferenceObject(ConnectionPort);
ObDereferenceObject(Port);
return Status;
}
* @implemented
*/
NTSTATUS
NTAPI
NtReplyWaitReceivePort(IN HANDLE PortHandle,
OUT PVOID *PortContext OPTIONAL,
IN PPORT_MESSAGE ReplyMessage OPTIONAL,
OUT PPORT_MESSAGE ReceiveMessage)
{
return NtReplyWaitReceivePortEx(PortHandle,
PortContext,
ReplyMessage,
ReceiveMessage,
NULL);
}
* @unimplemented
*/
NTSTATUS
NTAPI
NtReplyWaitReplyPort(IN HANDLE PortHandle,
IN PPORT_MESSAGE ReplyMessage)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
NTAPI
LpcpCopyRequestData(
IN BOOLEAN Write,
IN HANDLE PortHandle,
IN PPORT_MESSAGE Message,
IN ULONG Index,
IN PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnLength)
{
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PORT_MESSAGE CapturedMessage;
PLPCP_PORT_OBJECT Port = NULL;
PETHREAD ClientThread = NULL;
SIZE_T LocalReturnLength;
PLPCP_MESSAGE InfoMessage;
PLPCP_DATA_INFO DataInfo;
PVOID DataInfoBaseAddress;
PAGED_CODE();
if (PreviousMode != KernelMode)
{
_SEH2_TRY
{
ProbeForRead(Message, sizeof(*Message), sizeof(PVOID));
CapturedMessage = *(volatile PORT_MESSAGE*)Message;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return _SEH2_GetExceptionCode());
}
_SEH2_END;
}
else
{
CapturedMessage = *Message;
}
if (CapturedMessage.u2.s2.DataInfoOffset == 0)
{
return STATUS_INVALID_PARAMETER;
}
Status = ObReferenceObjectByHandle(PortHandle,
PORT_ALL_ACCESS,
LpcPortObjectType,
PreviousMode,
(PVOID*)&Port,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to reference port handle: 0x%ls\n", Status);
return Status;
}
Status = PsLookupProcessThreadByCid(&CapturedMessage.ClientId,
NULL,
&ClientThread);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to lookup client thread for [0x%lx:0x%lx]: 0x%ls\n",
CapturedMessage.ClientId.UniqueProcess,
CapturedMessage.ClientId.UniqueThread, Status);
goto Cleanup;
}
KeAcquireGuardedMutex(&LpcpLock);
if ((ClientThread->LpcReplyMessageId != CapturedMessage.MessageId) ||
(CapturedMessage.MessageId == 0))
{
DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n",
ClientThread->LpcReplyMessageId, CapturedMessage.MessageId);
Status = STATUS_REPLY_MESSAGE_MISMATCH;
goto CleanupWithLock;
}
if (!LpcpValidateClientPort(ClientThread, Port))
{
DPRINT1("LpcpValidateClientPort failed\n");
Status = STATUS_REPLY_MESSAGE_MISMATCH;
goto CleanupWithLock;
}
InfoMessage = LpcpFindDataInfoMessage(Port,
CapturedMessage.MessageId,
CapturedMessage.ClientId);
if (InfoMessage == NULL)
{
DPRINT1("LpcpFindDataInfoMessage failed\n");
Status = STATUS_INVALID_PARAMETER;
goto CleanupWithLock;
}
DataInfo = LpcpGetDataInfoFromMessage(&InfoMessage->Request);
if (Index >= DataInfo->NumberOfEntries)
{
DPRINT1("Message data index %lu out of bounds (%lu in msg)\n",
Index, DataInfo->NumberOfEntries);
Status = STATUS_INVALID_PARAMETER;
goto CleanupWithLock;
}
if (BufferLength > DataInfo->Entries[Index].DataLength)
{
DPRINT1("Trying to read more data (%lu) than available (%lu)\n",
BufferLength, DataInfo->Entries[Index].DataLength);
Status = STATUS_INVALID_PARAMETER;
goto CleanupWithLock;
}
DataInfoBaseAddress = DataInfo->Entries[Index].BaseAddress;
KeReleaseGuardedMutex(&LpcpLock);
if (Write)
{
Status = MmCopyVirtualMemory(PsGetCurrentProcess(),
Buffer,
ClientThread->ThreadsProcess,
DataInfoBaseAddress,
BufferLength,
PreviousMode,
&LocalReturnLength);
}
else
{
Status = MmCopyVirtualMemory(ClientThread->ThreadsProcess,
DataInfoBaseAddress,
PsGetCurrentProcess(),
Buffer,
BufferLength,
PreviousMode,
&LocalReturnLength);
}
if (!NT_SUCCESS(Status))
{
DPRINT1("MmCopyVirtualMemory failed: 0x%ls\n", Status);
goto Cleanup;
}
if (ReturnLength != NULL)
{
_SEH2_TRY
{
*ReturnLength = LocalReturnLength;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
DPRINT1("Exception writing ReturnLength, ignoring\n");
}
_SEH2_END;
}
Cleanup:
if (ClientThread != NULL)
ObDereferenceObject(ClientThread);
ObDereferenceObject(Port);
return Status;
CleanupWithLock:
KeReleaseGuardedMutex(&LpcpLock);
goto Cleanup;
}
* @implemented
*/
NTSTATUS
NTAPI
NtReadRequestData(IN HANDLE PortHandle,
IN PPORT_MESSAGE Message,
IN ULONG Index,
IN PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnLength)
{
return LpcpCopyRequestData(FALSE,
PortHandle,
Message,
Index,
Buffer,
BufferLength,
ReturnLength);
}
* @implemented
*/
NTSTATUS
NTAPI
NtWriteRequestData(IN HANDLE PortHandle,
IN PPORT_MESSAGE Message,
IN ULONG Index,
IN PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnLength)
{
return LpcpCopyRequestData(TRUE,
PortHandle,
Message,
Index,
Buffer,
BufferLength,
ReturnLength);
}