[PATCH] user32: Fix handling of internal messages.
Zebediah Figura
z.figura12 at gmail.com
Wed Mar 15 11:42:51 CDT 2017
I'm submitting this to wine-devel because the code is probably messy and
I'm not sure if this is the right approach to solving the problem.
This patch adds a new flag and a server reply, allowing GetQueueStatus
to ignore internal messages, and MsgWaitForMultipleObjects to process
internal messages until a real sent message is found.
Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
dlls/user32/message.c | 129
+++++++++++++++++++++++++++++++++++++++--
dlls/user32/tests/msg.c | 8 +--
include/wine/server_protocol.h | 4 +-
include/winuser.h | 3 +
server/protocol.def | 1 +
server/queue.c | 14 ++++-
server/request.h | 3 +-
server/trace.c | 1 +
8 files changed, 150 insertions(+), 13 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c
index 9bfb453..92caf64 100644
--- a/dlls/user32/message.c
+++ b/dlls/user32/message.c
@@ -2964,6 +2964,98 @@ static BOOL peek_message( MSG *msg, HWND hwnd,
UINT first, UINT last, UINT flags
/***********************************************************************
+ * receive_internal_message
+ *
+ * Retrieves and processes a single sent internal message.
+ */
+static DWORD receive_internal_message(size_t buffer_size)
+{
+ LRESULT result;
+ struct user_thread_info *thread_info = get_user_thread_info();
+ struct received_message_info info, *old_info;
+ void *buffer;
+ size_t size = 0;
+
+ buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size);
+
+ SERVER_START_REQ( get_message )
+ {
+ NTSTATUS res;
+
+ req->flags = PM_REMOVE | PM_QS_SENDMESSAGE;
+ req->get_win = 0;
+ req->get_first = 0;
+ req->get_last = 0;
+ req->hw_id = 0;
+ req->wake_mask = 0;
+ req->changed_mask = 0;
+ wine_server_set_reply( req, buffer, buffer_size );
+
+ if ((res = wine_server_call( req )) != STATUS_SUCCESS)
+ {
+ HeapFree(GetProcessHeap(), 0, buffer);
+ if (res == STATUS_BUFFER_OVERFLOW)
+ return receive_internal_message(reply->total);
+
+ return RtlNtStatusToDosError(res);
+ }
+
+ size = wine_server_reply_size( reply );
+ info.type = reply->type;
+ info.msg.hwnd = wine_server_ptr_handle( reply->win );
+ info.msg.message = reply->msg;
+ info.msg.wParam = reply->wparam;
+ info.msg.lParam = reply->lparam;
+ info.msg.time = reply->time;
+ info.msg.pt.x = reply->x;
+ info.msg.pt.y = reply->y;
+ thread_info->active_hooks = reply->active_hooks;
+ }
+ SERVER_END_REQ;
+
+ switch(info.type)
+ {
+ case MSG_ASCII:
+ case MSG_UNICODE:
+ info.flags = ISMEX_SEND;
+ break;
+ case MSG_NOTIFY:
+ info.flags = ISMEX_NOTIFY;
+ break;
+ case MSG_CALLBACK:
+ info.flags = ISMEX_CALLBACK;
+ break;
+ case MSG_HOOK_LL:
+ info.flags = ISMEX_SEND;
+ reply_message(&info, 0, TRUE);
+ return STATUS_SUCCESS;
+ case MSG_OTHER_PROCESS:
+ info.flags = ISMEX_SEND;
+ if (!unpack_message(info.msg.hwnd, info.msg.message,
&info.msg.wParam,
+ &info.msg.lParam, &buffer, size))
+ {
+ /* ignore it */
+ reply_message(&info, 0, TRUE);
+ return ERROR_SUCCESS;
+ }
+ break;
+ default:
+ ERR("unexpected type %d for internal message %08x\n",
info.type, info.msg.message);
+ }
+
+ old_info = thread_info->receive_info;
+ thread_info->receive_info = &info;
+ result = handle_internal_message(info.msg.hwnd, info.msg.message,
+ info.msg.wParam, info.msg.lParam);
+ reply_message( &info, result, TRUE );
+ thread_info->receive_info = old_info;
+
+ HeapFree(GetProcessHeap(), 0, buffer);
+ return ERROR_SUCCESS;
+}
+
+
+/***********************************************************************
* process_sent_messages
*
* Process all pending sent messages.
@@ -3811,7 +3903,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH PeekMessageA( MSG
*msg, HWND hwnd, UINT first, UIN
BOOL WINAPI DECLSPEC_HOTPATCH GetMessageW( MSG *msg, HWND hwnd, UINT
first, UINT last )
{
HANDLE server_queue = get_server_queue_handle();
- unsigned int mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always
selected */
+ unsigned int mask = QS_POSTMESSAGE | QS_SENDMESSAGE |
QS_WINE_SENDMESSAGE; /* Always selected */
USER_CheckNotLock();
check_for_driver_events( 0 );
@@ -3825,7 +3917,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetMessageW( MSG
*msg, HWND hwnd, UINT first, UINT
if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |=
QS_TIMER;
if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
}
- else mask = QS_ALLINPUT;
+ else mask |= QS_ALLINPUT;
while (!peek_message( msg, hwnd, first, last, PM_REMOVE | (mask <<
16), mask ))
{
@@ -4142,7 +4234,7 @@ DWORD WINAPI MsgWaitForMultipleObjectsEx( DWORD
count, const HANDLE *pHandles,
DWORD timeout, DWORD mask,
DWORD flags )
{
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
- DWORD i;
+ DWORD i, res;
if (count > MAXIMUM_WAIT_OBJECTS-1)
{
@@ -4154,8 +4246,37 @@ DWORD WINAPI MsgWaitForMultipleObjectsEx( DWORD
count, const HANDLE *pHandles,
for (i = 0; i < count; i++) handles[i] = pHandles[i];
handles[count] = get_server_queue_handle();
- return wait_objects( count+1, handles, timeout,
+ mask |= QS_WINE_SENDMESSAGE;
+
+ for (;;)
+ {
+ res = wait_objects( count+1, handles, timeout,
(flags & MWMO_INPUTAVAILABLE) ? mask : 0,
mask, flags );
+ if (res == WAIT_OBJECT_0+count)
+ {
+ NTSTATUS server_res;
+ UINT msg;
+ SERVER_START_REQ( get_queue_status )
+ {
+ req->clear_bits = 0;
+ if ((server_res = wine_server_call( req )) !=
STATUS_SUCCESS)
+ {
+ SetLastError(RtlNtStatusToDosError(server_res));
+ return WAIT_FAILED;
+ }
+ msg = reply->first_sent_msg;
+ }
+ SERVER_END_REQ;
+
+ if (msg & 0x80000000)
+ {
+ /* If it's a WINE internal message, process it and keep
waiting */
+ receive_internal_message(256);
+ continue;
+ }
+ }
+ return res;
+ }
}
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 19a1f31..a682b70 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -16332,7 +16332,7 @@ static void test_SendMessage_other_thread(int
thread_n)
GetMessageA(&msg, 0, 0, 0);
ok(msg.message == WM_USER, "expected WM_USER, got %04x\n",
msg.message);
DispatchMessageA(&msg);
- ok_sequence(send_message_1, "SendMessage from other thread 1",
thread_n == 2);
+ ok_sequence(send_message_1, "SendMessage from other thread 1", FALSE);
/* intentionally yield */
MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
@@ -16347,7 +16347,7 @@ static void test_SendMessage_other_thread(int
thread_n)
trace("main: call PeekMessage\n");
ok(PeekMessageA(&msg, 0, 0, 0, PM_NOREMOVE), "PeekMessage should
not fail\n");
ok(msg.message == WM_USER+1, "expected WM_USER+1, got %04x\n",
msg.message);
- ok_sequence(send_message_3, "SendMessage from other thread 3",
thread_n == 2);
+ ok_sequence(send_message_3, "SendMessage from other thread 3", FALSE);
trace("main: call PeekMessage\n");
ok(PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should not
fail\n");
@@ -16359,13 +16359,11 @@ static void test_SendMessage_other_thread(int
thread_n)
MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input);
ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
- /* FIXME: remove once Wine is fixed */
-todo_wine_if (thread_n == 2)
ok(ret == 0, "wrong status %08x\n", ret);
trace("main: call PeekMessage\n");
ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should
fail\n");
- ok_sequence(WmEmptySeq, "SendMessage from other thread 5", thread_n
== 2);
+ ok_sequence(WmEmptySeq, "SendMessage from other thread 5", FALSE);
ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE);
ok(ret == 0, "wrong status %08x\n", ret);
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index ee9fdd1..4417cb6 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2941,6 +2941,8 @@ struct get_queue_status_reply
struct reply_header __header;
unsigned int wake_bits;
unsigned int changed_bits;
+ unsigned int first_sent_msg;
+ char __pad_20[4];
};
@@ -6412,6 +6414,6 @@ union generic_reply
struct terminate_job_reply terminate_job_reply;
};
-#define SERVER_PROTOCOL_VERSION 524
+#define SERVER_PROTOCOL_VERSION 525
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/winuser.h b/include/winuser.h
index 2b8331c..d10caba 100644
--- a/include/winuser.h
+++ b/include/winuser.h
@@ -2898,6 +2898,9 @@ typedef struct tagTRACKMOUSEEVENT {
/* Extra (undocumented) queue wake bits - see "Undoc. Windows" */
#define QS_SMRESULT 0x8000
+/* Internal WINE message */
+#define QS_WINE_SENDMESSAGE 0x80000000
+
/* InSendMessageEx flags */
#define ISMEX_NOSEND 0x00000000
#define ISMEX_SEND 0x00000001
diff --git a/server/protocol.def b/server/protocol.def
index 60865a6..7b797af 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2162,6 +2162,7 @@ enum char_info_mode
@REPLY
unsigned int wake_bits; /* wake bits */
unsigned int changed_bits; /* changed bits since last time */
+ unsigned int first_sent_msg; /* first message in the sent message
queue */
@END
diff --git a/server/queue.c b/server/queue.c
index c479b38..ea6d5e6 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -744,7 +744,8 @@ static void receive_message( struct msg_queue
*queue, struct message *msg,
queue->recv_result = result;
}
free( msg );
- if (list_empty( &queue->msg_list[SEND_MESSAGE] )) clear_queue_bits(
queue, QS_SENDMESSAGE );
+ if (list_empty( &queue->msg_list[SEND_MESSAGE] ))
+ clear_queue_bits( queue, QS_SENDMESSAGE | QS_WINE_SENDMESSAGE );
}
/* set the result of the current received message */
@@ -2272,11 +2273,17 @@ DECL_HANDLER(set_queue_mask)
DECL_HANDLER(get_queue_status)
{
struct msg_queue *queue = current->queue;
+ struct list *ptr;
if (queue)
{
reply->wake_bits = queue->wake_bits;
reply->changed_bits = queue->changed_bits;
queue->changed_bits &= ~req->clear_bits;
+
+ if ((ptr = list_head( &queue->msg_list[SEND_MESSAGE] )))
+ reply->first_sent_msg = LIST_ENTRY( ptr, struct message, entry )->msg;
+ else
+ reply->first_sent_msg = 0;
}
else reply->wake_bits = reply->changed_bits = 0;
}
@@ -2339,7 +2346,10 @@ DECL_HANDLER(send_message)
/* fall through */
case MSG_NOTIFY:
list_add_tail( &recv_queue->msg_list[SEND_MESSAGE],
&msg->entry );
- set_queue_bits( recv_queue, QS_SENDMESSAGE );
+ if (msg->msg & 0x80000000) /* Wine internal message */
+ set_queue_bits( recv_queue, QS_WINE_SENDMESSAGE );
+ else
+ set_queue_bits( recv_queue, QS_SENDMESSAGE );
break;
case MSG_POSTED:
list_add_tail( &recv_queue->msg_list[POST_MESSAGE],
&msg->entry );
diff --git a/server/request.h b/server/request.h
index cd396ee..374150d 100644
--- a/server/request.h
+++ b/server/request.h
@@ -1480,7 +1480,8 @@ C_ASSERT( FIELD_OFFSET(struct
get_queue_status_request, clear_bits) == 12 );
C_ASSERT( sizeof(struct get_queue_status_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_queue_status_reply, wake_bits) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_queue_status_reply, changed_bits) ==
12 );
-C_ASSERT( sizeof(struct get_queue_status_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_queue_status_reply, first_sent_msg)
== 16 );
+C_ASSERT( sizeof(struct get_queue_status_reply) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_process_idle_event_request, handle)
== 12 );
C_ASSERT( sizeof(struct get_process_idle_event_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_process_idle_event_reply, event) == 8 );
diff --git a/server/trace.c b/server/trace.c
index e0ce45a..5ba65da 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2698,6 +2698,7 @@ static void dump_get_queue_status_reply( const
struct get_queue_status_reply *re
{
fprintf( stderr, " wake_bits=%08x", req->wake_bits );
fprintf( stderr, ", changed_bits=%08x", req->changed_bits );
+ fprintf( stderr, ", first_sent_msg=%08x", req->first_sent_msg );
}
static void dump_get_process_idle_event_request( const struct
get_process_idle_event_request *req )
--
2.7.4
More information about the wine-devel
mailing list