From: Rose Hellsing <rose@pinkro.se> Implement server-side LPC message receiving and replying: - NtReplyPort: Send a reply to a previous request message - NtReplyWaitReceivePort: Wrapper around NtReplyWaitReceivePortEx - NtReplyWaitReceivePortEx: Optionally reply to a previous message and wait for the next incoming message with optional timeout --- dlls/ntdll/tests/port.c | 5 +-- dlls/ntdll/unix/sync.c | 90 ++++++++++++++++++++++++++++++++++++----- dlls/wow64/sync.c | 6 +-- 3 files changed, 84 insertions(+), 17 deletions(-) diff --git a/dlls/ntdll/tests/port.c b/dlls/ntdll/tests/port.c index 0b7cd92d739..302e766da4e 100644 --- a/dlls/ntdll/tests/port.c +++ b/dlls/ntdll/tests/port.c @@ -322,10 +322,7 @@ static void test_ports_server( HANDLE PortHandle ) while (TRUE) { status = pNtReplyWaitReceivePort(PortHandle, NULL, NULL, &LpcMessage->msg); - todo_wine - { - ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld(%lx)\n", status, status); - } + ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %ld(%lx)\n", status, status); /* STATUS_INVALID_HANDLE: win2k without admin rights will perform an * endless loop here */ diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index d3f82e2cc49..c81552a7b3a 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -3454,31 +3454,103 @@ NTSTATUS WINAPI NtRequestPort( HANDLE handle, LPC_MESSAGE *msg ) /*********************************************************************** * NtReplyPort (NTDLL.@) */ -NTSTATUS WINAPI NtReplyPort( HANDLE handle, LPC_MESSAGE *reply ) +NTSTATUS WINAPI NtReplyPort( HANDLE handle, LPC_MESSAGE *reply_msg ) { - FIXME("(%p,%p),stub!\n", handle, reply ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + + TRACE( "(%p,%p)\n", handle, reply_msg ); + + if (!reply_msg) + return STATUS_INVALID_PARAMETER; + + SERVER_START_REQ( reply_wait_receive_lpc ) + { + req->handle = wine_server_obj_handle( handle ); + req->reply_msg_id = reply_msg->MessageId; + req->reply_size = reply_msg->DataSize; + req->timeout = 0; /* Don't wait for a new message */ + wine_server_add_data( req, reply_msg->Data, reply_msg->DataSize ); + ret = wine_server_call( req ); + /* STATUS_PENDING just means no new message, which is fine for NtReplyPort */ + if (ret == STATUS_PENDING) + ret = STATUS_SUCCESS; + } + SERVER_END_REQ; + return ret; } /*********************************************************************** * NtReplyWaitReceivePort (NTDLL.@) */ -NTSTATUS WINAPI NtReplyWaitReceivePort( HANDLE handle, ULONG *id, LPC_MESSAGE *reply, LPC_MESSAGE *msg ) +NTSTATUS WINAPI NtReplyWaitReceivePort( HANDLE handle, ULONG *id, LPC_MESSAGE *reply_msg, LPC_MESSAGE *msg ) { - FIXME("(%p,%p,%p,%p),stub!\n", handle, id, reply, msg ); - return STATUS_NOT_IMPLEMENTED; + return NtReplyWaitReceivePortEx( handle, id, reply_msg, msg, NULL ); } /*********************************************************************** * NtReplyWaitReceivePortEx (NTDLL.@) */ -NTSTATUS WINAPI NtReplyWaitReceivePortEx( HANDLE handle, ULONG *id, LPC_MESSAGE *reply, LPC_MESSAGE *msg, +NTSTATUS WINAPI NtReplyWaitReceivePortEx( HANDLE handle, ULONG *id, LPC_MESSAGE *reply_msg, LPC_MESSAGE *msg, LARGE_INTEGER *timeout ) { - FIXME("(%p,%p,%p,%p,%p),stub!\n", handle, id, reply, msg, timeout ); - return STATUS_NOT_IMPLEMENTED; + unsigned int ret; + timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; + unsigned int reply_msg_id = 0; + USHORT reply_size = 0; + + TRACE( "(%p,%p,%p,%p,%p)\n", handle, id, reply_msg, msg, timeout ); + + if (reply_msg) + { + reply_msg_id = reply_msg->MessageId; + reply_size = reply_msg->DataSize; + } + + for (;;) + { + SERVER_START_REQ( reply_wait_receive_lpc ) + { + req->handle = wine_server_obj_handle( handle ); + req->reply_msg_id = reply_msg_id; + req->reply_size = reply_size; + req->timeout = abs_timeout; + if (reply_msg && reply_size) + wine_server_add_data( req, reply_msg->Data, reply_size ); + if (msg) + { + /* Use a reasonable max size for LPC message data. + * sizeof(msg->Data) is just 1 due to ANYSIZE_ARRAY. */ + wine_server_set_reply( req, msg->Data, 0x1000 ); + } + ret = wine_server_call( req ); + if (!ret && msg) + { + msg->DataSize = reply->data_size; + msg->MessageSize = sizeof(*msg) + reply->data_size; + msg->MessageType = reply->msg_type; + msg->VirtualRangesOffset = 0; + msg->ClientId.UniqueProcess = ULongToHandle( reply->client_pid ); + msg->ClientId.UniqueThread = ULongToHandle( reply->client_tid ); + msg->MessageId = reply->msg_id; + msg->SectionSize = 0; + if (id) *id = (ULONG)(ULONG_PTR)reply->context; + } + } + SERVER_END_REQ; + + /* After first iteration, don't send reply again */ + reply_msg_id = 0; + reply_size = 0; + + if (ret != STATUS_PENDING) break; + + /* Wait on port for message availability */ + ret = NtWaitForSingleObject( handle, FALSE, timeout ); + if (ret) break; + } + return ret; } diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index 3b89e633ab1..c4ba357979b 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -1327,8 +1327,7 @@ NTSTATUS WINAPI wow64_NtReplyPort( UINT *args ) HANDLE handle = get_handle( &args ); LPC_MESSAGE *reply = get_ptr( &args ); - FIXME( "%p %p: stub\n", handle, reply ); - return STATUS_NOT_IMPLEMENTED; + return NtReplyPort( handle, reply ); } @@ -1342,8 +1341,7 @@ NTSTATUS WINAPI wow64_NtReplyWaitReceivePort( UINT *args ) LPC_MESSAGE *reply = get_ptr( &args ); LPC_MESSAGE *msg = get_ptr( &args ); - FIXME( "%p %p %p %p: stub\n", handle, id, reply, msg ); - return STATUS_NOT_IMPLEMENTED; + return NtReplyWaitReceivePort( handle, id, reply, msg ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10611