win32u: Move NtUserGetMessage implementation from user32.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2022-03-31 15:37:04 +02:00 committed by Alexandre Julliard
parent 58c4488626
commit dda4b573ea
7 changed files with 112 additions and 529 deletions

View File

@ -913,212 +913,6 @@ static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lpara
}
/***********************************************************************
* unpack_message
*
* Unpack a message received from another process.
*/
static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
void **buffer, size_t size )
{
size_t minsize = 0;
union packed_structs *ps = *buffer;
switch(message)
{
case WM_WINE_SETWINDOWPOS:
{
WINDOWPOS wp;
if (size < sizeof(ps->wp)) return FALSE;
wp.hwnd = wine_server_ptr_handle( ps->wp.hwnd );
wp.hwndInsertAfter = wine_server_ptr_handle( ps->wp.hwndInsertAfter );
wp.x = ps->wp.x;
wp.y = ps->wp.y;
wp.cx = ps->wp.cx;
wp.cy = ps->wp.cy;
wp.flags = ps->wp.flags;
memcpy( &ps->wp, &wp, sizeof(wp) );
break;
}
case WM_WINE_KEYBOARD_LL_HOOK:
case WM_WINE_MOUSE_LL_HOOK:
{
struct hook_extra_info h_extra;
minsize = sizeof(ps->hook) +
(message == WM_WINE_KEYBOARD_LL_HOOK ? sizeof(KBDLLHOOKSTRUCT)
: sizeof(MSLLHOOKSTRUCT));
if (size < minsize) return FALSE;
h_extra.handle = wine_server_ptr_handle( ps->hook.handle );
h_extra.lparam = (LPARAM)(&ps->hook + 1);
memcpy( &ps->hook, &h_extra, sizeof(h_extra) );
break;
}
default:
return TRUE; /* message doesn't need any unpacking */
}
/* default exit for most messages: check minsize and store buffer in lparam */
if (size < minsize) return FALSE;
*lparam = (LPARAM)*buffer;
return TRUE;
}
/***********************************************************************
* pack_reply
*
* Pack a reply to a message for sending to another process.
*/
static void pack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
LRESULT res, struct packed_message *data )
{
data->count = 0;
switch(message)
{
case WM_NCCREATE:
case WM_CREATE:
{
CREATESTRUCTW *cs = (CREATESTRUCTW *)lparam;
data->ps.cs.lpCreateParams = (ULONG_PTR)cs->lpCreateParams;
data->ps.cs.hInstance = (ULONG_PTR)cs->hInstance;
data->ps.cs.hMenu = wine_server_user_handle( cs->hMenu );
data->ps.cs.hwndParent = wine_server_user_handle( cs->hwndParent );
data->ps.cs.cy = cs->cy;
data->ps.cs.cx = cs->cx;
data->ps.cs.y = cs->y;
data->ps.cs.x = cs->x;
data->ps.cs.style = cs->style;
data->ps.cs.dwExStyle = cs->dwExStyle;
data->ps.cs.lpszName = (ULONG_PTR)cs->lpszName;
data->ps.cs.lpszClass = (ULONG_PTR)cs->lpszClass;
push_data( data, &data->ps.cs, sizeof(data->ps.cs) );
break;
}
case WM_GETTEXT:
case CB_GETLBTEXT:
case LB_GETTEXT:
push_data( data, (WCHAR *)lparam, (res + 1) * sizeof(WCHAR) );
break;
case WM_GETMINMAXINFO:
push_data( data, (MINMAXINFO *)lparam, sizeof(MINMAXINFO) );
break;
case WM_MEASUREITEM:
{
MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lparam;
data->ps.mis.CtlType = mis->CtlType;
data->ps.mis.CtlID = mis->CtlID;
data->ps.mis.itemID = mis->itemID;
data->ps.mis.itemWidth = mis->itemWidth;
data->ps.mis.itemHeight = mis->itemHeight;
data->ps.mis.itemData = mis->itemData;
push_data( data, &data->ps.mis, sizeof(data->ps.mis) );
break;
}
case WM_WINDOWPOSCHANGING:
case WM_WINDOWPOSCHANGED:
{
WINDOWPOS *wp = (WINDOWPOS *)lparam;
data->ps.wp.hwnd = wine_server_user_handle( wp->hwnd );
data->ps.wp.hwndInsertAfter = wine_server_user_handle( wp->hwndInsertAfter );
data->ps.wp.x = wp->x;
data->ps.wp.y = wp->y;
data->ps.wp.cx = wp->cx;
data->ps.wp.cy = wp->cy;
data->ps.wp.flags = wp->flags;
push_data( data, &data->ps.wp, sizeof(data->ps.wp) );
break;
}
case WM_GETDLGCODE:
if (lparam)
{
MSG *msg = (MSG *)lparam;
data->ps.msg.hwnd = wine_server_user_handle( msg->hwnd );
data->ps.msg.message = msg->message;
data->ps.msg.wParam = msg->wParam;
data->ps.msg.lParam = msg->lParam;
data->ps.msg.time = msg->time;
data->ps.msg.pt = msg->pt;
push_data( data, &data->ps.msg, sizeof(data->ps.msg) );
}
break;
case SBM_GETSCROLLINFO:
push_data( data, (SCROLLINFO *)lparam, sizeof(SCROLLINFO) );
break;
case EM_GETRECT:
case LB_GETITEMRECT:
case CB_GETDROPPEDCONTROLRECT:
case WM_SIZING:
case WM_MOVING:
push_data( data, (RECT *)lparam, sizeof(RECT) );
break;
case EM_GETLINE:
{
WORD *ptr = (WORD *)lparam;
push_data( data, ptr, ptr[-1] * sizeof(WCHAR) );
break;
}
case LB_GETSELITEMS:
push_data( data, (UINT *)lparam, wparam * sizeof(UINT) );
break;
case WM_MDIGETACTIVE:
if (lparam) push_data( data, (BOOL *)lparam, sizeof(BOOL) );
break;
case WM_NCCALCSIZE:
if (!wparam)
push_data( data, (RECT *)lparam, sizeof(RECT) );
else
{
NCCALCSIZE_PARAMS *ncp = (NCCALCSIZE_PARAMS *)lparam;
data->ps.ncp.rgrc[0] = ncp->rgrc[0];
data->ps.ncp.rgrc[1] = ncp->rgrc[1];
data->ps.ncp.rgrc[2] = ncp->rgrc[2];
data->ps.ncp.hwnd = wine_server_user_handle( ncp->lppos->hwnd );
data->ps.ncp.hwndInsertAfter = wine_server_user_handle( ncp->lppos->hwndInsertAfter );
data->ps.ncp.x = ncp->lppos->x;
data->ps.ncp.y = ncp->lppos->y;
data->ps.ncp.cx = ncp->lppos->cx;
data->ps.ncp.cy = ncp->lppos->cy;
data->ps.ncp.flags = ncp->lppos->flags;
push_data( data, &data->ps.ncp, sizeof(data->ps.ncp) );
}
break;
case EM_GETSEL:
case SBM_GETRANGE:
case CB_GETEDITSEL:
if (wparam) push_data( data, (DWORD *)wparam, sizeof(DWORD) );
if (lparam) push_data( data, (DWORD *)lparam, sizeof(DWORD) );
break;
case WM_NEXTMENU:
{
MDINEXTMENU *mnm = (MDINEXTMENU *)lparam;
data->ps.mnm.hmenuIn = wine_server_user_handle( mnm->hmenuIn );
data->ps.mnm.hmenuNext = wine_server_user_handle( mnm->hmenuNext );
data->ps.mnm.hwndNext = wine_server_user_handle( mnm->hwndNext );
push_data( data, &data->ps.mnm, sizeof(data->ps.mnm) );
break;
}
case WM_MDICREATE:
{
MDICREATESTRUCTW *mcs = (MDICREATESTRUCTW *)lparam;
data->ps.mcs.szClass = pack_ptr( mcs->szClass );
data->ps.mcs.szTitle = pack_ptr( mcs->szTitle );
data->ps.mcs.hOwner = pack_ptr( mcs->hOwner );
data->ps.mcs.x = mcs->x;
data->ps.mcs.y = mcs->y;
data->ps.mcs.cx = mcs->cx;
data->ps.mcs.cy = mcs->cy;
data->ps.mcs.style = mcs->style;
data->ps.mcs.lParam = mcs->lParam;
push_data( data, &data->ps.mcs, sizeof(data->ps.mcs) );
break;
}
case WM_ASKCBFORMATNAME:
push_data( data, (WCHAR *)lparam, (lstrlenW((WCHAR *)lparam) + 1) * sizeof(WCHAR) );
break;
}
}
/***********************************************************************
* unpack_reply
*
@ -1281,40 +1075,6 @@ static void unpack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam,
}
/***********************************************************************
* reply_message
*
* Send a reply to a sent message.
*/
static void reply_message( struct received_message_info *info, LRESULT result, MSG *msg )
{
struct packed_message data;
int i, replied = info->flags & ISMEX_REPLIED;
BOOL remove = msg != NULL;
if (info->flags & ISMEX_NOTIFY) return; /* notify messages don't get replies */
if (!remove && replied) return; /* replied already */
memset( &data, 0, sizeof(data) );
info->flags |= ISMEX_REPLIED;
if (info->type == MSG_OTHER_PROCESS && !replied)
{
if (!msg) msg = &info->msg;
pack_reply( msg->hwnd, msg->message, msg->wParam, msg->lParam, result, &data );
}
SERVER_START_REQ( reply_message )
{
req->result = result;
req->remove = remove;
for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
wine_server_call( req );
}
SERVER_END_REQ;
}
/***********************************************************************
* handle_internal_message
*
@ -2127,249 +1887,6 @@ static inline void call_sendmsg_callback( SENDASYNCPROC callback, HWND hwnd, UIN
}
/***********************************************************************
* peek_message
*
* Peek for a message matching the given parameters. Return 0 if none are
* available; -1 on error.
* All pending sent messages are processed before returning.
*/
static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, UINT changed_mask )
{
LRESULT result;
struct user_thread_info *thread_info = get_user_thread_info();
INPUT_MESSAGE_SOURCE prev_source = thread_info->msg_source;
struct received_message_info info;
unsigned int hw_id = 0; /* id of previous hardware message */
void *buffer;
size_t buffer_size = 1024;
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size ))) return -1;
if (!first && !last) last = ~0;
if (hwnd == HWND_BROADCAST) hwnd = HWND_TOPMOST;
for (;;)
{
NTSTATUS res;
size_t size = 0;
const message_data_t *msg_data = buffer;
BOOL needs_unpack = FALSE;
thread_info->msg_source = prev_source;
SERVER_START_REQ( get_message )
{
req->flags = flags;
req->get_win = wine_server_user_handle( hwnd );
req->get_first = first;
req->get_last = last;
req->hw_id = hw_id;
req->wake_mask = changed_mask & (QS_SENDMESSAGE | QS_SMRESULT);
req->changed_mask = changed_mask;
wine_server_set_reply( req, buffer, buffer_size );
if (!(res = wine_server_call( req )))
{
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;
hw_id = 0;
thread_info->active_hooks = reply->active_hooks;
}
else buffer_size = reply->total;
}
SERVER_END_REQ;
if (res)
{
HeapFree( GetProcessHeap(), 0, buffer );
if (res == STATUS_PENDING)
{
thread_info->wake_mask = changed_mask & (QS_SENDMESSAGE | QS_SMRESULT);
thread_info->changed_mask = changed_mask;
return 0;
}
if (res != STATUS_BUFFER_OVERFLOW)
{
SetLastError( RtlNtStatusToDosError(res) );
return -1;
}
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size ))) return -1;
continue;
}
TRACE( "got type %d msg %x (%s) hwnd %p wp %lx lp %lx\n",
info.type, info.msg.message,
(info.type == MSG_WINEVENT) ? "MSG_WINEVENT" : SPY_GetMsgName(info.msg.message, info.msg.hwnd),
info.msg.hwnd, info.msg.wParam, info.msg.lParam );
switch(info.type)
{
case MSG_ASCII:
case MSG_UNICODE:
info.flags = ISMEX_SEND;
break;
case MSG_NOTIFY:
info.flags = ISMEX_NOTIFY;
if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
&info.msg.lParam, &buffer, size ))
continue;
needs_unpack = TRUE;
break;
case MSG_CALLBACK:
info.flags = ISMEX_CALLBACK;
break;
case MSG_CALLBACK_RESULT:
if (size >= sizeof(msg_data->callback))
call_sendmsg_callback( wine_server_get_ptr(msg_data->callback.callback),
info.msg.hwnd, info.msg.message,
msg_data->callback.data, msg_data->callback.result );
continue;
case MSG_WINEVENT:
if (size >= sizeof(msg_data->winevent))
{
struct win_event_hook_params params;
params.proc = wine_server_get_ptr( msg_data->winevent.hook_proc );
size -= sizeof(msg_data->winevent);
if (size)
{
size = min( size, sizeof(params.module) - sizeof(WCHAR) );
memcpy( params.module, &msg_data->winevent + 1, size );
}
params.module[size / sizeof(WCHAR)] = 0;
size = FIELD_OFFSET( struct win_hook_params, module[size / sizeof(WCHAR) + 1] );
params.handle = wine_server_ptr_handle( msg_data->winevent.hook );
params.event = info.msg.message;
params.hwnd = info.msg.hwnd;
params.object_id = info.msg.wParam;
params.child_id = info.msg.lParam;
params.tid = msg_data->winevent.tid;
params.time = info.msg.time;
User32CallWinEventHook( &params, size );
}
continue;
case MSG_HOOK_LL:
info.flags = ISMEX_SEND;
result = 0;
if (info.msg.message == WH_KEYBOARD_LL && size >= sizeof(msg_data->hardware))
{
KBDLLHOOKSTRUCT hook;
hook.vkCode = LOWORD( info.msg.lParam );
hook.scanCode = HIWORD( info.msg.lParam );
hook.flags = msg_data->hardware.flags;
hook.time = info.msg.time;
hook.dwExtraInfo = msg_data->hardware.info;
TRACE( "calling keyboard LL hook vk %x scan %x flags %x time %u info %lx\n",
hook.vkCode, hook.scanCode, hook.flags, hook.time, hook.dwExtraInfo );
result = HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, info.msg.wParam, (LPARAM)&hook, TRUE );
}
else if (info.msg.message == WH_MOUSE_LL && size >= sizeof(msg_data->hardware))
{
MSLLHOOKSTRUCT hook;
hook.pt = info.msg.pt;
hook.mouseData = info.msg.lParam;
hook.flags = msg_data->hardware.flags;
hook.time = info.msg.time;
hook.dwExtraInfo = msg_data->hardware.info;
TRACE( "calling mouse LL hook pos %d,%d data %x flags %x time %u info %lx\n",
hook.pt.x, hook.pt.y, hook.mouseData, hook.flags, hook.time, hook.dwExtraInfo );
result = HOOK_CallHooks( WH_MOUSE_LL, HC_ACTION, info.msg.wParam, (LPARAM)&hook, TRUE );
}
reply_message( &info, result, &info.msg );
continue;
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, &info.msg );
continue;
}
needs_unpack = TRUE;
break;
case MSG_HARDWARE:
if (size >= sizeof(msg_data->hardware))
{
hw_id = msg_data->hardware.hw_id;
if (!process_hardware_message( &info.msg, hw_id, &msg_data->hardware,
hwnd, first, last, flags & PM_REMOVE ))
{
TRACE("dropping msg %x\n", info.msg.message );
continue; /* ignore it */
}
*msg = info.msg;
thread_info->GetMessagePosVal = MAKELONG( info.msg.pt.x, info.msg.pt.y );
thread_info->GetMessageTimeVal = info.msg.time;
thread_info->GetMessageExtraInfoVal = msg_data->hardware.info;
HeapFree( GetProcessHeap(), 0, buffer );
HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg, TRUE );
return 1;
}
continue;
case MSG_POSTED:
if (info.msg.message & 0x80000000) /* internal message */
{
if (flags & PM_REMOVE)
{
handle_internal_message( info.msg.hwnd, info.msg.message,
info.msg.wParam, info.msg.lParam );
/* if this is a nested call return right away */
if (first == info.msg.message && last == info.msg.message)
{
HeapFree( GetProcessHeap(), 0, buffer );
return 0;
}
}
else
peek_message( msg, info.msg.hwnd, info.msg.message,
info.msg.message, flags | PM_REMOVE, changed_mask );
continue;
}
if (info.msg.message >= WM_DDE_FIRST && info.msg.message <= WM_DDE_LAST)
{
if (!unpack_dde_message( info.msg.hwnd, info.msg.message, &info.msg.wParam,
&info.msg.lParam, &buffer, size ))
continue; /* ignore it */
}
*msg = info.msg;
msg->pt = point_phys_to_win_dpi( info.msg.hwnd, info.msg.pt );
thread_info->GetMessagePosVal = MAKELONG( msg->pt.x, msg->pt.y );
thread_info->GetMessageTimeVal = info.msg.time;
thread_info->GetMessageExtraInfoVal = 0;
thread_info->msg_source = msg_source_unavailable;
HeapFree( GetProcessHeap(), 0, buffer );
HOOK_CallHooks( WH_GETMESSAGE, HC_ACTION, flags & PM_REMOVE, (LPARAM)msg, TRUE );
return 1;
}
/* if we get here, we have a sent message; call the window procedure */
info.prev = thread_info->receive_info;
thread_info->receive_info = &info;
thread_info->msg_source = msg_source_unavailable;
result = call_window_proc( info.msg.hwnd, info.msg.message, info.msg.wParam,
info.msg.lParam, (info.type != MSG_ASCII), FALSE,
WMCHAR_MAP_RECVMESSAGE, needs_unpack, buffer, size );
if (thread_info->receive_info == &info )
NtUserCallTwoParam( result, (UINT_PTR)&info.msg, NtUserReplyMessage );
/* if some PM_QS* flags were specified, only handle sent messages from now on */
if (HIWORD(flags) && !changed_mask) flags = PM_QS_SENDMESSAGE | LOWORD(flags);
}
}
/***********************************************************************
* process_sent_messages
*
@ -3187,22 +2704,6 @@ void WINAPI PostQuitMessage( INT exit_code )
SERVER_END_REQ;
}
/* check for driver events if we detect that the app is not properly consuming messages */
static inline void check_for_driver_events( UINT msg )
{
if (get_user_thread_info()->message_count > 200)
{
flush_window_surfaces( FALSE );
USER_Driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_ALLINPUT, 0 );
}
else if (msg == WM_TIMER || msg == WM_SYSTIMER)
{
/* driver events should have priority over timers, so make sure we'll check for them soon */
get_user_thread_info()->message_count += 100;
}
else get_user_thread_info()->message_count++;
}
/***********************************************************************
* PeekMessageW (USER32.@)
*/
@ -3229,33 +2730,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 */
int ret;
USER_CheckNotLock();
check_for_driver_events( 0 );
if (first || last)
{
if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
}
else mask = QS_ALLINPUT;
while (!(ret = peek_message( msg, hwnd, first, last, PM_REMOVE | (mask << 16), mask )))
{
wait_objects( 1, &server_queue, INFINITE, mask & (QS_SENDMESSAGE | QS_SMRESULT), mask, 0 );
}
if (ret < 0) return -1;
check_for_driver_events( msg->message );
return (msg->message != WM_QUIT);
return NtUserGetMessage( msg, hwnd, first, last );
}

View File

@ -1181,6 +1181,7 @@ static struct unix_funcs unix_funcs =
NtUserGetIconInfo,
NtUserGetKeyNameText,
NtUserGetKeyboardLayoutList,
NtUserGetMessage,
NtUserGetPriorityClipboardFormat,
NtUserGetQueueStatus,
NtUserGetUpdateRect,

View File

@ -24,6 +24,7 @@
#pragma makedep unix
#endif
#include <assert.h>
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "win32u_private.h"
@ -37,6 +38,9 @@ WINE_DECLARE_DEBUG_CHANNEL(relay);
#define MAX_WINPROC_RECURSION 64
#define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
#define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
#define MAX_PACK_COUNT 4
struct packed_hook_extra_info
@ -384,22 +388,24 @@ static void reply_message( struct received_message_info *info, LRESULT result, M
{
struct packed_message data;
int i, replied = info->flags & ISMEX_REPLIED;
BOOL remove = msg != NULL;
if (info->flags & ISMEX_NOTIFY) return; /* notify messages don't get replies */
if (!msg && replied) return; /* replied already */
if (!remove && replied) return; /* replied already */
memset( &data, 0, sizeof(data) );
info->flags |= ISMEX_REPLIED;
if (info->type == MSG_OTHER_PROCESS && !replied)
{
if (!msg) msg = &info->msg;
pack_reply( msg->hwnd, msg->message, msg->wParam, msg->lParam, result, &data );
}
SERVER_START_REQ( reply_message )
{
req->result = result;
req->remove = msg != NULL;
req->remove = remove;
for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
wine_server_call( req );
}
@ -856,6 +862,30 @@ void process_sent_messages(void)
peek_message( &msg, 0, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE, 0 );
}
/***********************************************************************
* get_server_queue_handle
*
* Get a handle to the server message queue for the current thread.
*/
static HANDLE get_server_queue_handle(void)
{
struct user_thread_info *thread_info = get_user_thread_info();
HANDLE ret;
if (!(ret = thread_info->server_queue))
{
SERVER_START_REQ( get_msg_queue )
{
wine_server_call( req );
ret = wine_server_ptr_handle( reply->handle );
}
SERVER_END_REQ;
thread_info->server_queue = ret;
if (!ret) ERR( "Cannot get server thread queue\n" );
}
return ret;
}
/* check for driver events if we detect that the app is not properly consuming messages */
static inline void check_for_driver_events( UINT msg )
{
@ -892,6 +922,41 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW
return ret;
}
/***********************************************************************
* wait_objects
*
* Wait for multiple objects including the server queue, with specific queue masks.
*/
static DWORD wait_objects( DWORD count, const HANDLE *handles, DWORD timeout,
DWORD wake_mask, DWORD changed_mask, DWORD flags )
{
struct user_thread_info *thread_info = get_user_thread_info();
DWORD ret;
assert( count ); /* we must have at least the server queue */
flush_window_surfaces( TRUE );
if (thread_info->wake_mask != wake_mask || thread_info->changed_mask != changed_mask)
{
SERVER_START_REQ( set_queue_mask )
{
req->wake_mask = wake_mask;
req->changed_mask = changed_mask;
req->skip_wait = 0;
wine_server_call( req );
}
SERVER_END_REQ;
thread_info->wake_mask = wake_mask;
thread_info->changed_mask = changed_mask;
}
ret = wait_message( count, handles, timeout, changed_mask, flags );
if (ret != WAIT_TIMEOUT) thread_info->wake_mask = thread_info->changed_mask = 0;
return ret;
}
/***********************************************************************
* NtUserPeekMessage (win32u.@)
*/
@ -929,6 +994,40 @@ BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, U
return TRUE;
}
/***********************************************************************
* NtUserGetMessage (win32u.@)
*/
BOOL WINAPI NtUserGetMessage( MSG *msg, HWND hwnd, UINT first, UINT last )
{
HANDLE server_queue = get_server_queue_handle();
unsigned int mask = QS_POSTMESSAGE | QS_SENDMESSAGE; /* Always selected */
int ret;
user_check_not_lock();
check_for_driver_events( 0 );
if (first || last)
{
if ((first <= WM_KEYLAST) && (last >= WM_KEYFIRST)) mask |= QS_KEY;
if ( ((first <= WM_MOUSELAST) && (last >= WM_MOUSEFIRST)) ||
((first <= WM_NCMOUSELAST) && (last >= WM_NCMOUSEFIRST)) ) mask |= QS_MOUSE;
if ((first <= WM_TIMER) && (last >= WM_TIMER)) mask |= QS_TIMER;
if ((first <= WM_SYSTIMER) && (last >= WM_SYSTIMER)) mask |= QS_TIMER;
if ((first <= WM_PAINT) && (last >= WM_PAINT)) mask |= QS_PAINT;
}
else mask = QS_ALLINPUT;
while (!(ret = peek_message( msg, hwnd, first, last, PM_REMOVE | (mask << 16), mask )))
{
wait_objects( 1, &server_queue, INFINITE, mask & (QS_SENDMESSAGE | QS_SMRESULT), mask, 0 );
}
if (ret < 0) return -1;
check_for_driver_events( msg->message );
return msg->message != WM_QUIT;
}
/**********************************************************************
* dispatch_message
*/

View File

@ -955,7 +955,7 @@
@ stub NtUserGetMenuBarInfo
@ stub NtUserGetMenuIndex
@ stub NtUserGetMenuItemRect
@ stub NtUserGetMessage
@ stdcall NtUserGetMessage(ptr long long long)
@ stdcall -syscall NtUserGetMouseMovePointsEx(long ptr ptr long long)
@ stdcall -syscall NtUserGetObjectInformation(long long long long ptr)
@ stub NtUserGetOemBitmapSize

View File

@ -228,6 +228,7 @@ struct unix_funcs
UNICODE_STRING *res_name, DWORD *bpp, LONG unk );
INT (WINAPI *pNtUserGetKeyNameText)( LONG lparam, WCHAR *buffer, INT size );
UINT (WINAPI *pNtUserGetKeyboardLayoutList)( INT size, HKL *layouts );
BOOL (WINAPI *pNtUserGetMessage)( MSG *msg, HWND hwnd, UINT first, UINT last );
INT (WINAPI *pNtUserGetPriorityClipboardFormat)( UINT *list, INT count );
DWORD (WINAPI *pNtUserGetQueueStatus)( UINT flags );
BOOL (WINAPI *pNtUserGetUpdateRect)( HWND hwnd, RECT *rect, BOOL erase );

View File

@ -903,6 +903,12 @@ INT WINAPI NtUserGetKeyNameText( LONG lparam, WCHAR *buffer, INT size )
return unix_funcs->pNtUserGetKeyNameText( lparam, buffer, size );
}
BOOL WINAPI NtUserGetMessage( MSG *msg, HWND hwnd, UINT first, UINT last )
{
if (!unix_funcs) return FALSE;
return unix_funcs->pNtUserGetMessage( msg, hwnd, first, last );
}
BOOL WINAPI NtUserGetUpdateRect( HWND hwnd, RECT *rect, BOOL erase )
{
if (!unix_funcs) return FALSE;

View File

@ -559,6 +559,7 @@ UINT WINAPI NtUserGetKeyboardLayoutList( INT size, HKL *layouts );
BOOL WINAPI NtUserGetKeyboardLayoutName( WCHAR *name );
BOOL WINAPI NtUserGetKeyboardState( BYTE *state );
BOOL WINAPI NtUserGetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags );
BOOL WINAPI NtUserGetMessage( MSG *msg, HWND hwnd, UINT first, UINT last );
int WINAPI NtUserGetMouseMovePointsEx( UINT size, MOUSEMOVEPOINT *ptin, MOUSEMOVEPOINT *ptout,
int count, DWORD resolution );
BOOL WINAPI NtUserGetObjectInformation( HANDLE handle, INT index, void *info,