From 51ab43bd130b2fee7a07dfd8e6e4ad64ce7bc7c7 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Fri, 18 May 2001 22:51:56 +0000 Subject: [PATCH] Moved the major part of message queue and window timer handling into the server. Implemented MsgWaitForMultipleObjectsEx. --- dlls/user/user32.spec | 2 +- dlls/user/user_main.c | 2 +- dlls/x11drv/x11drv.spec | 2 +- include/message.h | 2 - include/queue.h | 72 +--- include/server.h | 150 +++++++- include/user.h | 2 +- include/winuser.h | 38 +- server/queue.c | 701 +++++++++++++++++++++++++++++++++- server/request.h | 24 +- server/thread.c | 14 +- server/trace.c | 149 +++++++- windows/clipboard.c | 5 + windows/message.c | 640 +++++++++++++------------------ windows/queue.c | 824 +++++++++------------------------------- windows/timer.c | 141 ++----- windows/win.c | 25 +- windows/x11drv/event.c | 12 +- 18 files changed, 1529 insertions(+), 1276 deletions(-) diff --git a/dlls/user/user32.spec b/dlls/user/user32.spec index b4ad906513c..2df366fd84d 100644 --- a/dlls/user/user32.spec +++ b/dlls/user/user32.spec @@ -414,7 +414,7 @@ debug_channels (accel caret class clipboard combo cursor dc ddeml dialog driver @ stdcall ModifyMenuW(long long long long ptr) ModifyMenuW @ stdcall MoveWindow(long long long long long long) MoveWindow @ stdcall MsgWaitForMultipleObjects(long ptr long long long) MsgWaitForMultipleObjects -@ stub MsgWaitForMultipleObjectsEx +@ stdcall MsgWaitForMultipleObjectsEx(long ptr long long long) MsgWaitForMultipleObjectsEx @ stdcall OemKeyScan(long) OemKeyScan @ stdcall OemToCharA(ptr ptr) OemToCharA @ stdcall OemToCharBuffA(ptr ptr long) OemToCharBuffA diff --git a/dlls/user/user_main.c b/dlls/user/user_main.c index 341c5f45ff2..63dbfb9afef 100644 --- a/dlls/user/user_main.c +++ b/dlls/user/user_main.c @@ -88,7 +88,7 @@ static BOOL load_driver(void) GET_USER_FUNC(DestroyWindow); GET_USER_FUNC(GetDC); GET_USER_FUNC(EnableWindow); - GET_USER_FUNC(MsgWaitForMultipleObjects); + GET_USER_FUNC(MsgWaitForMultipleObjectsEx); GET_USER_FUNC(ScrollWindowEx); GET_USER_FUNC(SetFocus); GET_USER_FUNC(SetParent); diff --git a/dlls/x11drv/x11drv.spec b/dlls/x11drv/x11drv.spec index ac91214d474..118e318f283 100644 --- a/dlls/x11drv/x11drv.spec +++ b/dlls/x11drv/x11drv.spec @@ -31,7 +31,7 @@ debug_channels (bitblt bitmap clipboard cursor dinput event font gdi graphics @ cdecl DestroyWindow(long) X11DRV_DestroyWindow @ cdecl GetDC(long long long long) X11DRV_GetDC @ cdecl EnableWindow(long long) X11DRV_EnableWindow -@ cdecl MsgWaitForMultipleObjects(long ptr long long) X11DRV_MsgWaitForMultipleObjects +@ cdecl MsgWaitForMultipleObjectsEx(long ptr long long long) X11DRV_MsgWaitForMultipleObjectsEx @ cdecl ScrollWindowEx(long long long ptr ptr long ptr long) X11DRV_ScrollWindowEx @ cdecl SetFocus(long) X11DRV_SetFocus @ cdecl SetParent(long long) X11DRV_SetParent diff --git a/include/message.h b/include/message.h index 5db85092eb4..1d9968bf36c 100644 --- a/include/message.h +++ b/include/message.h @@ -21,8 +21,6 @@ extern BOOL MSG_InternalGetMessage( struct tagMSG *msg, HWND hwnd, HWND hwndOwne /* timer.c */ extern void TIMER_RemoveWindowTimers( HWND hwnd ); extern void TIMER_RemoveQueueTimers( HQUEUE16 hqueue ); -extern BOOL TIMER_GetTimerMsg( struct tagMSG *msg, HWND hwnd, - HQUEUE16 hQueue, BOOL remove ); extern BOOL TIMER_IsTimerValid( HWND hwnd, UINT id, HWINDOWPROC hProc ); /* input.c */ diff --git a/include/queue.h b/include/queue.h index cd3a61ab94d..20c14cac4bd 100644 --- a/include/queue.h +++ b/include/queue.h @@ -31,43 +31,6 @@ typedef struct tagQMSG #define QMSG_HARDWARE 3 -typedef struct tagSMSG -{ - struct tagSMSG *nextProcessing; /* next SMSG in the processing list */ - struct tagSMSG *nextPending; /* next SMSG in the pending list */ - struct tagSMSG *nextWaiting; /* next SMSG in the waiting list */ - - HQUEUE16 hSrcQueue; /* sending Queue, (NULL if it didn't wait) */ - HQUEUE16 hDstQueue; /* destination Queue */ - - HWND hWnd; /* destination window */ - UINT msg; /* message sent */ - WPARAM wParam; /* wParam of the sent message */ - LPARAM lParam; /* lParam of the sent message */ - - LRESULT lResult; /* result of SendMessage */ - WORD flags; /* see below SMSG_XXXX */ -} SMSG; - - -/* SMSG -> flags values */ -/* set when lResult contains a good value */ -#define SMSG_HAVE_RESULT 0x0001 -/* protection for multiple call to ReplyMessage16() */ -#define SMSG_ALREADY_REPLIED 0x0002 -/* use with EARLY_REPLY for forcing the receiver to clean SMSG */ -#define SMSG_RECEIVER_CLEANS 0x0010 -/* used with EARLY_REPLY to indicate to sender, receiver is done with SMSG */ -#define SMSG_RECEIVED 0x0020 -/* set in ReceiveMessage() to indicate it's not an early reply */ -#define SMSG_SENDING_REPLY 0x0040 -/* set when ReplyMessage16() is called by the application */ -#define SMSG_EARLY_REPLY 0x0080 -/* set when sender is Win32 thread */ -#define SMSG_WIN32 0x1000 -/* set when sender is a unicode thread */ -#define SMSG_UNICODE 0x2000 - /* Per-queue data for the message queue * Note that we currently only store the current values for * Active, Capture and Focus windows currently. @@ -87,7 +50,6 @@ typedef struct tagPERQUEUEDATA /* Message queue */ typedef struct tagMESSAGEQUEUE { - HQUEUE16 next; /* Next queue */ HQUEUE16 self; /* Handle to self (was: reserved) */ TEB* teb; /* Thread owning queue */ HANDLE server_queue; /* Handle to server-side queue */ @@ -96,27 +58,17 @@ typedef struct tagMESSAGEQUEUE DWORD magic; /* magic number should be QUEUE_MAGIC */ DWORD lockCount; /* reference counter */ - WORD msgCount; /* Number of waiting messages */ QMSG* firstMsg; /* First message in linked list */ QMSG* lastMsg; /* Last message in linked list */ WORD wPostQMsg; /* PostQuitMessage flag */ WORD wExitCode; /* PostQuitMessage exit code */ WORD wPaintCount; /* Number of WM_PAINT needed */ - WORD wTimerCount; /* Number of timers for this task */ - - WORD changeBits; /* Changed wake-up bits */ - WORD wakeBits; /* Queue wake-up bits */ - WORD wakeMask; /* Queue wake-up mask */ DWORD GetMessageTimeVal; /* Value for GetMessageTime */ DWORD GetMessagePosVal; /* Value for GetMessagePos */ DWORD GetMessageExtraInfoVal; /* Value for GetMessageExtraInfo */ - - SMSG* smWaiting; /* SendMessage waiting for reply */ - SMSG* smProcessing; /* SendMessage currently being processed */ - SMSG* smPending; /* SendMessage waiting to be received */ - + HANDLE16 hCurHook; /* Current hook */ HANDLE16 hooks[WH_NB_HOOKS]; /* Task hooks list */ @@ -125,14 +77,6 @@ typedef struct tagMESSAGEQUEUE } MESSAGEQUEUE; -/* Extra (undocumented) queue wake bits - see "Undoc. Windows" */ -#define QS_SMRESULT 0x8000 /* Queue has a SendMessage() result */ - -/* Types of SMSG stack */ -#define SM_PROCESSING_LIST 1 /* list of SM currently being processed */ -#define SM_PENDING_LIST 2 /* list of SM wating to be received */ -#define SM_WAITING_LIST 3 /* list of SM waiting for reply */ - #define QUEUE_MAGIC 0xD46E80AF /* Per queue data management methods */ @@ -152,28 +96,22 @@ INT16 PERQDATA_SetCaptureInfo( PERQUEUEDATA *pQData, INT16 nCaptureHT ); extern MESSAGEQUEUE *QUEUE_Lock( HQUEUE16 hQueue ); extern void QUEUE_Unlock( MESSAGEQUEUE *queue ); extern void QUEUE_DumpQueue( HQUEUE16 hQueue ); -extern void QUEUE_WalkQueues(void); extern BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue ); extern void QUEUE_SetExitingQueue( HQUEUE16 hQueue ); extern MESSAGEQUEUE *QUEUE_GetSysQueue(void); -extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit ); +extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear ); extern void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit ); extern WORD QUEUE_TestWakeBit( MESSAGEQUEUE *queue, WORD bit ); -extern BOOL QUEUE_ReceiveMessage( MESSAGEQUEUE *queue ); extern int QUEUE_WaitBits( WORD bits, DWORD timeout ); extern void QUEUE_IncPaintCount( HQUEUE16 hQueue ); extern void QUEUE_DecPaintCount( HQUEUE16 hQueue ); -extern void QUEUE_IncTimerCount( HQUEUE16 hQueue ); -extern void QUEUE_DecTimerCount( HQUEUE16 hQueue ); extern BOOL QUEUE_CreateSysMsgQueue( int size ); extern BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ); extern HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue ); -extern BOOL QUEUE_AddMsg( HQUEUE16 hQueue, int type, MSG * msg, DWORD extraInfo ); -extern QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, - int first, int last ); +extern BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove, + BOOL sent_only, QMSG *msg ); extern void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg ); -extern SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg ); -extern BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg ); +extern void QUEUE_CleanupWindow( HWND hwnd ); extern void hardware_event( UINT message, WPARAM wParam, LPARAM lParam, int xPos, int yPos, DWORD time, DWORD extraInfo ); diff --git a/include/server.h b/include/server.h index 2f48af91c5c..ef02a771cf9 100644 --- a/include/server.h +++ b/include/server.h @@ -1296,14 +1296,41 @@ struct get_msg_queue_request OUT handle_t handle; /* handle to the queue */ }; -/* Wake up a message queue */ -struct wake_queue_request + +/* Set the message queue wake bits */ +struct set_queue_bits_request { REQUEST_HEADER; /* request header */ IN handle_t handle; /* handle to the queue */ - IN unsigned int bits; /* wake bits */ + IN unsigned int set; /* wake bits to set */ + IN unsigned int clear; /* wake bits to clear */ + IN unsigned int mask_cond; /* mask for conditional bit setting */ + OUT unsigned int changed_mask; /* changed bits wake mask */ }; + +/* Set the current message queue wakeup mask */ +struct set_queue_mask_request +{ + REQUEST_HEADER; /* request header */ + IN unsigned int wake_mask; /* wakeup bits mask */ + IN unsigned int changed_mask; /* changed bits mask */ + IN int skip_wait; /* will we skip waiting if signaled? */ + OUT unsigned int wake_bits; /* current wake bits */ + OUT unsigned int changed_bits; /* current changed bits */ +}; + + +/* Get the current message queue status */ +struct get_queue_status_request +{ + REQUEST_HEADER; /* request header */ + IN int clear; /* should we clear the change bits? */ + OUT unsigned int wake_bits; /* wake bits */ + OUT unsigned int changed_bits; /* changed bits since last time */ +}; + + /* Wait for a process to start waiting on input */ struct wait_input_idle_request { @@ -1313,6 +1340,97 @@ struct wait_input_idle_request OUT handle_t event; /* handle to idle event */ }; + +/* Send a message to a thread queue */ +struct send_message_request +{ + REQUEST_HEADER; /* request header */ + IN int posted; /* posted instead of sent message? */ + IN void* id; /* thread id */ + IN int type; /* message type */ + IN handle_t win; /* window handle */ + IN unsigned int msg; /* message code */ + IN unsigned int wparam; /* parameters */ + IN unsigned int lparam; /* parameters */ + IN unsigned int info; /* extra info */ +}; + + +/* Get a message from the current queue */ +struct get_message_request +{ + REQUEST_HEADER; /* request header */ + IN int remove; /* remove it? */ + IN int posted; /* check posted messages too? */ + IN handle_t get_win; /* window handle to get */ + IN unsigned int get_first; /* first message code to get */ + IN unsigned int get_last; /* last message code to get */ + OUT int sent; /* it is a sent message */ + OUT int type; /* message type */ + OUT handle_t win; /* window handle */ + OUT unsigned int msg; /* message code */ + OUT unsigned int wparam; /* parameters */ + OUT unsigned int lparam; /* parameters */ + OUT unsigned int info; /* extra info */ +}; + + +/* Reply to a sent message */ +struct reply_message_request +{ + REQUEST_HEADER; /* request header */ + IN unsigned int result; /* message result */ + IN int remove; /* should we remove the message? */ +}; + + +/* Retrieve the reply for the last message sent */ +struct get_message_reply_request +{ + REQUEST_HEADER; /* request header */ + IN int cancel; /* cancel message if not ready? */ + OUT unsigned int result; /* message result */ +}; + + +/* Check if we are processing a sent message */ +struct in_send_message_request +{ + REQUEST_HEADER; /* request header */ + OUT int flags; /* ISMEX_* flags */ +}; + + +/* Cleanup a queue when a window is deleted */ +struct cleanup_window_queue_request +{ + REQUEST_HEADER; /* request header */ + IN handle_t win; /* window handle */ +}; + + +/* Set a window timer */ +struct set_win_timer_request +{ + REQUEST_HEADER; /* request header */ + IN handle_t win; /* window handle */ + IN unsigned int msg; /* message to post */ + IN unsigned int id; /* timer id */ + IN unsigned int rate; /* timer rate in ms */ + IN unsigned int lparam; /* message lparam (callback proc) */ +}; + + +/* Kill a window timer */ +struct kill_win_timer_request +{ + REQUEST_HEADER; /* request header */ + IN handle_t win; /* window handle */ + IN unsigned int msg; /* message to post */ + IN unsigned int id; /* timer id */ +}; + + struct create_serial_request { REQUEST_HEADER; /* request header */ @@ -1473,8 +1591,18 @@ enum request REQ_get_atom_name, REQ_init_atom_table, REQ_get_msg_queue, - REQ_wake_queue, + REQ_set_queue_bits, + REQ_set_queue_mask, + REQ_get_queue_status, REQ_wait_input_idle, + REQ_send_message, + REQ_get_message, + REQ_reply_message, + REQ_get_message_reply, + REQ_in_send_message, + REQ_cleanup_window_queue, + REQ_set_win_timer, + REQ_kill_win_timer, REQ_create_serial, REQ_get_serial_info, REQ_set_serial_info, @@ -1588,15 +1716,25 @@ union generic_request struct get_atom_name_request get_atom_name; struct init_atom_table_request init_atom_table; struct get_msg_queue_request get_msg_queue; - struct wake_queue_request wake_queue; + struct set_queue_bits_request set_queue_bits; + struct set_queue_mask_request set_queue_mask; + struct get_queue_status_request get_queue_status; struct wait_input_idle_request wait_input_idle; + struct send_message_request send_message; + struct get_message_request get_message; + struct reply_message_request reply_message; + struct get_message_reply_request get_message_reply; + struct in_send_message_request in_send_message; + struct cleanup_window_queue_request cleanup_window_queue; + struct set_win_timer_request set_win_timer; + struct kill_win_timer_request kill_win_timer; struct create_serial_request create_serial; struct get_serial_info_request get_serial_info; struct set_serial_info_request set_serial_info; struct create_async_request create_async; }; -#define SERVER_PROTOCOL_VERSION 44 +#define SERVER_PROTOCOL_VERSION 45 /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */ diff --git a/include/user.h b/include/user.h index 8e1b92e8523..a69feb0e539 100644 --- a/include/user.h +++ b/include/user.h @@ -73,7 +73,7 @@ typedef struct tagUSER_DRIVER { BOOL (*pDestroyWindow)(HWND); BOOL (*pGetDC)(HWND,HDC,HRGN,DWORD); BOOL (*pEnableWindow)(HWND,BOOL); - DWORD (*pMsgWaitForMultipleObjects)(DWORD,HANDLE*,BOOL,DWORD); + DWORD (*pMsgWaitForMultipleObjectsEx)(DWORD,const HANDLE*,DWORD,DWORD,DWORD); INT (*pScrollWindowEx)(HWND,INT,INT,const RECT*,const RECT*,HRGN,LPRECT,UINT); void (*pSetFocus)(HWND); HWND (*pSetParent)(HWND,HWND); diff --git a/include/winuser.h b/include/winuser.h index e39ddffe2e8..56c45073eab 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -902,6 +902,10 @@ typedef struct #define WM_APP 0x8000 +/* MsgWaitForMultipleObjectsEx flags */ +#define MWMO_WAITALL 0x0001 +#define MWMO_ALERTABLE 0x0002 +#define MWMO_INPUTAVAILABLE 0x0004 #define DLGC_WANTARROWS 0x0001 #define DLGC_WANTTAB 0x0002 @@ -3026,6 +3030,16 @@ typedef struct #define QS_ALLEVENTS (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY) #define QS_ALLINPUT (QS_ALLEVENTS | QS_SENDMESSAGE) +/* Extra (undocumented) queue wake bits - see "Undoc. Windows" */ +#define QS_SMRESULT 0x8000 + +/* InSendMessageEx flags */ +#define ISMEX_NOSEND 0x00000000 +#define ISMEX_SEND 0x00000001 +#define ISMEX_NOTIFY 0x00000002 +#define ISMEX_CALLBACK 0x00000004 +#define ISMEX_REPLIED 0x00000008 + #define DDL_READWRITE 0x0000 #define DDL_READONLY 0x0001 #define DDL_HIDDEN 0x0002 @@ -3184,10 +3198,11 @@ INT WINAPI MessageBoxExW(HWND,LPCWSTR,LPCWSTR,UINT,WORD); HMONITOR WINAPI MonitorFromPoint(POINT,DWORD); HMONITOR WINAPI MonitorFromRect(LPRECT,DWORD); HMONITOR WINAPI MonitorFromWindow(HWND,DWORD); -DWORD WINAPI MsgWaitForMultipleObjects(DWORD,HANDLE*,BOOL,DWORD,DWORD); -BOOL WINAPI PaintDesktop(HDC); -BOOL WINAPI PostThreadMessageA(DWORD, UINT, WPARAM, LPARAM); -BOOL WINAPI PostThreadMessageW(DWORD, UINT, WPARAM, LPARAM); +DWORD WINAPI MsgWaitForMultipleObjects(DWORD,CONST HANDLE*,BOOL,DWORD,DWORD); +DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD); +BOOL WINAPI PaintDesktop(HDC); +BOOL WINAPI PostThreadMessageA(DWORD,UINT,WPARAM,LPARAM); +BOOL WINAPI PostThreadMessageW(DWORD,UINT,WPARAM,LPARAM); #define PostThreadMessage WINELIB_NAME_AW(PostThreadMessage) BOOL WINAPI RegisterHotKey(HWND,INT,UINT,UINT); HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE,LPVOID,DWORD); @@ -3229,7 +3244,6 @@ LONG WINAPI GetMessageTime(void); DWORD WINAPI OemKeyScan(WORD); BOOL WINAPI ReleaseCapture(void); BOOL WINAPI SetKeyboardState(LPBYTE); -VOID WINAPI WaitMessage(void); /* Declarations for functions that change between Win16 and Win32 */ @@ -3589,12 +3603,13 @@ BOOL WINAPI GrayStringA(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM, BOOL WINAPI GrayStringW(HDC,HBRUSH,GRAYSTRINGPROC,LPARAM, INT,INT,INT,INT,INT); #define GrayString WINELIB_NAME_AW(GrayString) -BOOL WINAPI HideCaret(HWND); -BOOL WINAPI HiliteMenuItem(HWND,HMENU,UINT,UINT); -BOOL WINAPI InflateRect(LPRECT,INT,INT); -BOOL WINAPI InSendMessage(void); -BOOL WINAPI InsertMenuA(HMENU,UINT,UINT,UINT,LPCSTR); -BOOL WINAPI InsertMenuW(HMENU,UINT,UINT,UINT,LPCWSTR); +BOOL WINAPI HideCaret(HWND); +BOOL WINAPI HiliteMenuItem(HWND,HMENU,UINT,UINT); +BOOL WINAPI InflateRect(LPRECT,INT,INT); +BOOL WINAPI InSendMessage(void); +DWORD WINAPI InSendMessageEx(LPVOID); +BOOL WINAPI InsertMenuA(HMENU,UINT,UINT,UINT,LPCSTR); +BOOL WINAPI InsertMenuW(HMENU,UINT,UINT,UINT,LPCWSTR); #define InsertMenu WINELIB_NAME_AW(InsertMenu) BOOL WINAPI InsertMenuItemA(HMENU,UINT,BOOL,const MENUITEMINFOA*); BOOL WINAPI InsertMenuItemW(HMENU,UINT,BOOL,const MENUITEMINFOW*); @@ -3837,6 +3852,7 @@ WORD WINAPI VkKeyScanW(WCHAR); WORD WINAPI VkKeyScanExA(CHAR, HKL); WORD WINAPI VkKeyScanExW(WCHAR, HKL); #define VkKeyScanEx WINELIB_NAME_AW(VkKeyScanEx) +BOOL WINAPI WaitMessage(void); HWND WINAPI WindowFromDC(HDC); HWND WINAPI WindowFromPoint(POINT); BOOL WINAPI WinHelpA(HWND,LPCSTR,UINT,DWORD); diff --git a/server/queue.c b/server/queue.c index 3067c0c620b..ef99ac2671f 100644 --- a/server/queue.c +++ b/server/queue.c @@ -8,16 +8,72 @@ #include #include +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" + #include "handle.h" #include "thread.h" #include "process.h" #include "request.h" +struct message_result +{ + struct message_result *send_next; /* next in sender list */ + struct message_result *recv_next; /* next in receiver list */ + struct msg_queue *sender; /* sender queue */ + struct msg_queue *receiver; /* receiver queue */ + int replied; /* has it been replied to? */ + unsigned int result; /* reply result */ + unsigned int error; /* error code to pass back to sender */ +}; + +struct message +{ + struct message *next; /* next message in list */ + struct message *prev; /* prev message in list */ + int type; /* message type (FIXME) */ + handle_t win; /* window handle */ + unsigned int msg; /* message code */ + unsigned int wparam; /* parameters */ + unsigned int lparam; /* parameters */ + unsigned int info; /* extra info */ + struct message_result *result; /* result in sender queue */ +}; + +struct message_list +{ + struct message *first; /* head of list */ + struct message *last; /* tail of list */ +}; + +struct timer +{ + struct timer *next; /* next timer in list */ + struct timer *prev; /* prev timer in list */ + struct timeval when; /* next expiration */ + unsigned int rate; /* timer rate in ms */ + handle_t win; /* window handle */ + unsigned int msg; /* message to post */ + unsigned int id; /* timer id */ + unsigned int lparam; /* lparam for message */ +}; + struct msg_queue { - struct object obj; /* object header */ - struct thread *thread; /* thread owning this queue */ - int signaled; /* queue has been signaled */ + struct object obj; /* object header */ + unsigned int wake_bits; /* wakeup bits */ + unsigned int wake_mask; /* wakeup mask */ + unsigned int changed_bits; /* changed wakeup bits */ + unsigned int changed_mask; /* changed wakeup mask */ + struct message_list send_list; /* list of sent messages */ + struct message_list post_list; /* list of posted messages */ + struct message_result *send_result; /* stack of sent messages waiting for result */ + struct message_result *recv_result; /* stack of received messages waiting for result */ + struct timer *first_timer; /* head of timer list */ + struct timer *last_timer; /* tail of timer list */ + struct timer *next_timer; /* next timer to expire */ + struct timeout_user *timeout; /* timeout for next timer to expire */ }; static void msg_queue_dump( struct object *obj, int verbose ); @@ -25,6 +81,8 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry ); static int msg_queue_signaled( struct object *obj, struct thread *thread ); static int msg_queue_satisfied( struct object *obj, struct thread *thread ); +static void msg_queue_destroy( struct object *obj ); +static void timer_callback( void *private ); static const struct object_ops msg_queue_ops = { @@ -39,7 +97,7 @@ static const struct object_ops msg_queue_ops = no_get_fd, /* get_fd */ no_flush, /* flush */ no_get_file_info, /* get_file_info */ - no_destroy /* destroy */ + msg_queue_destroy /* destroy */ }; @@ -49,8 +107,20 @@ static struct msg_queue *create_msg_queue( struct thread *thread ) if ((queue = alloc_object( &msg_queue_ops, -1 ))) { - queue->signaled = 0; - queue->thread = thread; + queue->wake_bits = 0; + queue->wake_mask = 0; + queue->changed_bits = 0; + queue->changed_mask = 0; + queue->send_list.first = NULL; + queue->send_list.last = NULL; + queue->post_list.first = NULL; + queue->post_list.last = NULL; + queue->send_result = NULL; + queue->recv_result = NULL; + queue->first_timer = NULL; + queue->last_timer = NULL; + queue->next_timer = NULL; + queue->timeout = NULL; thread->queue = queue; if (!thread->process->queue) thread->process->queue = (struct msg_queue *)grab_object( queue ); @@ -58,13 +128,211 @@ static struct msg_queue *create_msg_queue( struct thread *thread ) return queue; } +/* check the queue status */ +inline static int is_signaled( struct msg_queue *queue ) +{ + return ((queue->wake_bits & queue->wake_mask) || (queue->changed_bits & queue->changed_mask)); +} + +/* set/clear some queue bits */ +inline static void change_queue_bits( struct msg_queue *queue, unsigned int set, unsigned int clear ) +{ + queue->wake_bits = (queue->wake_bits | set) & ~clear; + queue->changed_bits = (queue->changed_bits | set) & ~clear; + if (is_signaled( queue )) wake_up( &queue->obj, 0 ); +} + +/* get the current thread queue, creating it if needed */ +inline struct msg_queue *get_current_queue(void) +{ + struct msg_queue *queue = current->queue; + if (!queue) queue = create_msg_queue( current ); + return queue; +} + +/* append a message to the end of a list */ +inline static void append_message( struct message_list *list, struct message *msg ) +{ + msg->next = NULL; + if ((msg->prev = list->last)) msg->prev->next = msg; + else list->first = msg; + list->last = msg; +} + +/* unlink a message from a list it */ +inline static void unlink_message( struct message_list *list, struct message *msg ) +{ + if (msg->next) msg->next->prev = msg->prev; + else list->last = msg->prev; + if (msg->prev) msg->prev->next = msg->next; + else list->first = msg->next; +} + +/* free a message when deleting a queue or window */ +static void free_message( struct message *msg ) +{ + struct message_result *result = msg->result; + if (result) + { + if (result->sender) + { + result->result = 0; + result->error = STATUS_ACCESS_DENIED; /* FIXME */ + result->replied = 1; + result->receiver = NULL; + /* wake sender queue if waiting on this result */ + if (result->sender->send_result == result) + change_queue_bits( result->sender, QS_SMRESULT, 0 ); + } + else free( result ); + } + free( msg ); +} + +/* remove (and free) a message from the sent messages list */ +static void remove_sent_message( struct msg_queue *queue, struct message *msg ) +{ + unlink_message( &queue->send_list, msg ); + free_message( msg ); + if (!queue->send_list.first) change_queue_bits( queue, 0, QS_SENDMESSAGE ); +} + +/* remove (and free) a message from the posted messages list */ +static void remove_posted_message( struct msg_queue *queue, struct message *msg ) +{ + unlink_message( &queue->post_list, msg ); + free_message( msg ); + if (!queue->post_list.first) change_queue_bits( queue, 0, QS_POSTMESSAGE ); +} + +/* send a message from the sender queue to the receiver queue */ +static int send_message( struct msg_queue *send_queue, struct msg_queue *recv_queue, + struct message *msg ) +{ + struct message_result *result = mem_alloc( sizeof(*result) ); + if (!result) return 0; + + /* put the result on the sender result stack */ + result->sender = send_queue; + result->receiver = recv_queue; + result->replied = 0; + result->send_next = send_queue->send_result; + send_queue->send_result = result; + + /* and put the message on the receiver queue */ + msg->result = result; + append_message( &recv_queue->send_list, msg ); + change_queue_bits( recv_queue, QS_SENDMESSAGE, 0 ); + return 1; +} + +/* receive a message, removing it from the sent queue */ +static void receive_message( struct msg_queue *queue, struct message *msg ) +{ + struct message_result *result = msg->result; + + unlink_message( &queue->send_list, msg ); + /* put the result on the receiver result stack */ + result->recv_next = queue->recv_result; + queue->recv_result = result; + free( msg ); + if (!queue->send_list.first) change_queue_bits( queue, 0, QS_SENDMESSAGE ); +} + +/* set the result of the current received message */ +static void reply_message( struct msg_queue *queue, unsigned int result, + unsigned int error, int remove ) +{ + struct message_result *res = queue->recv_result; + if (!res) set_error( STATUS_ACCESS_DENIED ); /* FIXME */ + + if (remove) + { + queue->recv_result = res->recv_next; + res->receiver = NULL; + if (!res->sender) /* no one waiting for it */ + { + free( res ); + return; + } + } + if (!res->replied) + { + res->result = result; + res->error = error; + res->replied = 1; + /* wake sender queue if waiting on this result */ + if (res->sender && res->sender->send_result == res) + change_queue_bits( res->sender, QS_SMRESULT, 0 ); + } +} + +/* retrieve the reply of the current message being sent */ +static unsigned int get_message_reply( struct msg_queue *queue, int cancel ) +{ + struct message_result *res = queue->send_result; + unsigned int ret = 0; + + set_error( STATUS_PENDING ); + + if (res && (res->replied || cancel)) + { + if (res->replied) + { + ret = res->result; + set_error( res->error ); + } + queue->send_result = res->send_next; + res->sender = NULL; + if (!res->receiver) free( res ); + if (!queue->send_result || !queue->send_result->replied) + change_queue_bits( queue, 0, QS_SMRESULT ); + } + return ret; +} + +/* empty a message list and free all the messages */ +static void empty_msg_list( struct message_list *list ) +{ + struct message *msg = list->first; + while (msg) + { + struct message *next = msg->next; + free_message( msg ); + msg = next; + } +} + +/* cleanup all pending results when deleting a queue */ +static void cleanup_results( struct msg_queue *queue ) +{ + struct message_result *result, *next; + + result = queue->send_result; + while (result) + { + next = result->send_next; + result->sender = NULL; + if (!result->receiver) free( result ); + result = next; + } + + while (queue->recv_result) reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1 ); +} + static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry ) { struct msg_queue *queue = (struct msg_queue *)obj; struct process *process = entry->thread->process; + /* a thread can only wait on its own queue */ + if (entry->thread->queue != queue) + { + set_error( STATUS_ACCESS_DENIED ); + return 0; + } /* if waiting on the main process queue, set the idle event */ - if (entry->thread == queue->thread && process->queue == queue) + if (process->queue == queue) { if (process->idle_event) set_event( process->idle_event ); } @@ -79,8 +347,10 @@ static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry * remove_queue( obj, entry ); + assert( entry->thread->queue == queue ); + /* if waiting on the main process queue, reset the idle event */ - if (entry->thread == queue->thread && process->queue == queue) + if (process->queue == queue) { if (process->idle_event) reset_event( process->idle_event ); } @@ -89,41 +359,438 @@ static void msg_queue_remove_queue(struct object *obj, struct wait_queue_entry * static void msg_queue_dump( struct object *obj, int verbose ) { struct msg_queue *queue = (struct msg_queue *)obj; - fprintf( stderr, "Msg queue signaled=%d owner=%p\n", queue->signaled, queue->thread ); + fprintf( stderr, "Msg queue bits=%x mask=%x\n", + queue->wake_bits, queue->wake_mask ); } static int msg_queue_signaled( struct object *obj, struct thread *thread ) { struct msg_queue *queue = (struct msg_queue *)obj; - return queue->signaled; + return is_signaled( queue ); } static int msg_queue_satisfied( struct object *obj, struct thread *thread ) { struct msg_queue *queue = (struct msg_queue *)obj; - queue->signaled = 0; + queue->wake_mask = 0; + queue->changed_mask = 0; return 0; /* Not abandoned */ } +static void msg_queue_destroy( struct object *obj ) +{ + struct msg_queue *queue = (struct msg_queue *)obj; + struct timer *timer = queue->first_timer; + + cleanup_results( queue ); + empty_msg_list( &queue->send_list ); + empty_msg_list( &queue->post_list ); + + while (timer) + { + struct timer *next = timer->next; + free( timer ); + timer = next; + } + if (queue->timeout) remove_timeout_user( queue->timeout ); +} + +/* set the next timer to expire */ +static void set_next_timer( struct msg_queue *queue, struct timer *timer ) +{ + if (queue->timeout) + { + remove_timeout_user( queue->timeout ); + queue->timeout = NULL; + } + if ((queue->next_timer = timer)) + queue->timeout = add_timeout_user( &timer->when, timer_callback, queue ); + + /* set/clear QS_TIMER bit */ + if (queue->next_timer == queue->first_timer) + change_queue_bits( queue, 0, QS_TIMER ); + else + change_queue_bits( queue, QS_TIMER, 0 ); +} + +/* callback for the next timer expiration */ +static void timer_callback( void *private ) +{ + struct msg_queue *queue = private; + + queue->timeout = NULL; + /* move on to the next timer */ + set_next_timer( queue, queue->next_timer->next ); +} + +/* link a timer at its rightful place in the queue list */ +static void link_timer( struct msg_queue *queue, struct timer *timer ) +{ + struct timer *pos = queue->next_timer; + + while (pos && time_before( &pos->when, &timer->when )) pos = pos->next; + + if (pos) /* insert before pos */ + { + if ((timer->prev = pos->prev)) timer->prev->next = timer; + else queue->first_timer = timer; + timer->next = pos; + pos->prev = timer; + } + else /* insert at end */ + { + timer->next = NULL; + timer->prev = queue->last_timer; + if (queue->last_timer) queue->last_timer->next = timer; + else queue->first_timer = timer; + queue->last_timer = timer; + } + /* check if we replaced the next timer */ + if (pos == queue->next_timer) set_next_timer( queue, timer ); +} + +/* remove a timer from the queue timer list */ +static void unlink_timer( struct msg_queue *queue, struct timer *timer ) +{ + if (timer->next) timer->next->prev = timer->prev; + else queue->last_timer = timer->prev; + if (timer->prev) timer->prev->next = timer->next; + else queue->first_timer = timer->next; + /* check if we removed the next timer */ + if (queue->next_timer == timer) set_next_timer( queue, timer->next ); +} + +/* restart an expired timer */ +static void restart_timer( struct msg_queue *queue, struct timer *timer ) +{ + struct timeval now; + unlink_timer( queue, timer ); + gettimeofday( &now, 0 ); + while (!time_before( &now, &timer->when )) add_timeout( &timer->when, timer->rate ); + link_timer( queue, timer ); +} + +/* find an expired timer matching the filtering parameters */ +static struct timer *find_expired_timer( struct msg_queue *queue, handle_t win, + unsigned int get_first, unsigned int get_last, + int remove ) +{ + struct timer *timer; + for (timer = queue->first_timer; (timer && timer != queue->next_timer); timer = timer->next) + { + if (win && timer->win != win) continue; + if (timer->msg >= get_first && timer->msg <= get_last) + { + if (remove) restart_timer( queue, timer ); + return timer; + } + } + return NULL; +} + +/* kill a timer */ +static int kill_timer( struct msg_queue *queue, handle_t win, unsigned int msg, unsigned int id ) +{ + struct timer *timer; + + for (timer = queue->first_timer; timer; timer = timer->next) + { + if (timer->win != win || timer->msg != msg || timer->id != id) continue; + unlink_timer( queue, timer ); + free( timer ); + return 1; + } + return 0; +} + +/* add a timer */ +static struct timer *set_timer( struct msg_queue *queue, unsigned int rate ) +{ + struct timer *timer = mem_alloc( sizeof(*timer) ); + if (timer) + { + timer->rate = rate; + gettimeofday( &timer->when, 0 ); + add_timeout( &timer->when, rate ); + link_timer( queue, timer ); + } + return timer; +} + +/* remove all messages and timers belonging to a certain window */ +static void cleanup_window( struct msg_queue *queue, handle_t win ) +{ + struct timer *timer; + struct message *msg; + + /* remove timers */ + timer = queue->first_timer; + while (timer) + { + struct timer *next = timer->next; + if (timer->win == win) + { + unlink_timer( queue, timer ); + free( timer ); + } + timer = next; + } + + /* remove sent messages */ + msg = queue->send_list.first; + while (msg) + { + struct message *next = msg->next; + if (msg->win == win) remove_sent_message( queue, msg ); + msg = next; + } + + /* remove posted messages */ + msg = queue->post_list.first; + while (msg) + { + struct message *next = msg->next; + if (msg->win == win) remove_posted_message( queue, msg ); + msg = next; + } +} + /* get the message queue of the current thread */ DECL_HANDLER(get_msg_queue) { - struct msg_queue *queue = current->queue; + struct msg_queue *queue = get_current_queue(); req->handle = 0; - if (!queue) queue = create_msg_queue( current ); if (queue) req->handle = alloc_handle( current->process, queue, SYNCHRONIZE, 0 ); } -/* wake up a message queue */ -DECL_HANDLER(wake_queue) + +/* set the message queue wake bits */ +DECL_HANDLER(set_queue_bits) { struct msg_queue *queue = (struct msg_queue *)get_handle_obj( current->process, req->handle, 0, &msg_queue_ops ); if (queue) { - queue->signaled = 1; - wake_up( &queue->obj, 0 ); + req->changed_mask = queue->changed_mask; + if (!req->mask_cond || (queue->changed_mask & req->mask_cond)) + change_queue_bits( queue, req->set, req->clear ); release_object( queue ); } } + + +/* set the current message queue wakeup mask */ +DECL_HANDLER(set_queue_mask) +{ + struct msg_queue *queue = get_current_queue(); + + if (queue) + { + queue->wake_mask = req->wake_mask; + queue->changed_mask = req->changed_mask; + req->wake_bits = queue->wake_bits; + req->changed_bits = queue->changed_bits; + if (is_signaled( queue )) + { + /* if skip wait is set, do what would have been done in the subsequent wait */ + if (req->skip_wait) msg_queue_satisfied( &queue->obj, current ); + else wake_up( &queue->obj, 0 ); + } + } +} + + +/* get the current message queue status */ +DECL_HANDLER(get_queue_status) +{ + struct msg_queue *queue = current->queue; + if (queue) + { + req->wake_bits = queue->wake_bits; + req->changed_bits = queue->changed_bits; + if (req->clear) queue->changed_bits = 0; + } + else req->wake_bits = req->changed_bits = 0; +} + + +/* send a message to a thread queue */ +DECL_HANDLER(send_message) +{ + struct message *msg; + struct msg_queue *send_queue = get_current_queue(); + struct msg_queue *recv_queue; + struct thread *thread = get_thread_from_id( req->id ); + + if (!thread) return; + + if (!(recv_queue = thread->queue)) + { + set_error( STATUS_INVALID_PARAMETER ); + release_object( thread ); + return; + } + + if ((msg = mem_alloc( sizeof(*msg) ))) + { + msg->type = req->type; + msg->win = req->win; + msg->msg = req->msg; + msg->wparam = req->wparam; + msg->lparam = req->lparam; + msg->info = req->info; + msg->result = NULL; + if (!req->posted) send_message( send_queue, recv_queue, msg ); + else + { + append_message( &recv_queue->post_list, msg ); + change_queue_bits( recv_queue, QS_POSTMESSAGE, 0 ); + } + } + release_object( thread ); +} + +/* get a message from the current queue */ +DECL_HANDLER(get_message) +{ + struct timer *timer; + struct message *msg; + struct msg_queue *queue = get_current_queue(); + + if (!queue) return; + + /* first check for sent messages */ + if ((msg = queue->send_list.first)) + { + req->sent = 1; + req->type = msg->type; + req->win = msg->win; + req->msg = msg->msg; + req->wparam = msg->wparam; + req->lparam = msg->lparam; + req->info = msg->info; + receive_message( queue, msg ); + return; + } + if (!req->posted) goto done; /* nothing else to check */ + + /* then try a posted message */ + req->sent = 0; + for (msg = queue->post_list.first; msg; msg = msg->next) + { + /* check against the filters */ + if (req->get_win && msg->win != req->get_win) continue; + if (req->msg >= req->get_first && req->msg <= req->get_last) + { + /* found one */ + req->type = msg->type; + req->win = msg->win; + req->msg = msg->msg; + req->wparam = msg->wparam; + req->lparam = msg->lparam; + req->info = msg->info; + if (req->remove) remove_posted_message( queue, msg ); + return; + } + } + + /* now check for WM_PAINT */ + if (queue->wake_bits & QS_PAINT) + { + req->type = 0; + req->win = 0; + req->msg = WM_PAINT; + req->wparam = 0; + req->lparam = 0; + req->info = 0; + return; + } + + /* now check for timer */ + if ((timer = find_expired_timer( queue, req->get_win, req->get_first, + req->get_last, req->remove ))) + { + req->type = 0; + req->win = timer->win; + req->msg = timer->msg; + req->wparam = timer->id; + req->lparam = timer->lparam; + req->info = 0; + return; + } + + done: + set_error( STATUS_PENDING ); /* FIXME */ +} + + +/* reply to a sent message */ +DECL_HANDLER(reply_message) +{ + if (current->queue) reply_message( current->queue, req->result, 0, req->remove ); + else set_error( STATUS_ACCESS_DENIED ); +} + + +/* retrieve the reply for the last message sent */ +DECL_HANDLER(get_message_reply) +{ + if (current->queue) req->result = get_message_reply( current->queue, req->cancel ); + else set_error( STATUS_ACCESS_DENIED ); +} + + +/* check if we are processing a sent message */ +DECL_HANDLER(in_send_message) +{ + int flags = 0; + + if (current->queue) + { + struct message_result *result = current->queue->recv_result; + if (result) + { + flags |= ISMEX_SEND; /* FIXME */ + if (result->replied || !result->sender) flags |= ISMEX_REPLIED; + } + } + req->flags = flags; +} + + +/* cleanup a queue when a window is deleted */ +DECL_HANDLER(cleanup_window_queue) +{ + if (current->queue) cleanup_window( current->queue, req->win ); +} + + +/* set a window timer */ +DECL_HANDLER(set_win_timer) +{ + struct timer *timer; + struct msg_queue *queue = get_current_queue(); + + if (!queue) return; + + /* remove it if it existed already */ + if (req->win) kill_timer( queue, req->win, req->msg, req->id ); + + if ((timer = set_timer( queue, req->rate ))) + { + timer->win = req->win; + timer->msg = req->msg; + timer->id = req->id; + timer->lparam = req->lparam; + } +} + +/* kill a window timer */ +DECL_HANDLER(kill_win_timer) +{ + struct msg_queue *queue = current->queue; + + if (!queue || !kill_timer( queue, req->win, req->msg, req->id )) + set_error( STATUS_INVALID_PARAMETER ); +} diff --git a/server/request.h b/server/request.h index 43ac0ae08e5..8d24e76482e 100644 --- a/server/request.h +++ b/server/request.h @@ -170,8 +170,18 @@ DECL_HANDLER(find_atom); DECL_HANDLER(get_atom_name); DECL_HANDLER(init_atom_table); DECL_HANDLER(get_msg_queue); -DECL_HANDLER(wake_queue); +DECL_HANDLER(set_queue_bits); +DECL_HANDLER(set_queue_mask); +DECL_HANDLER(get_queue_status); DECL_HANDLER(wait_input_idle); +DECL_HANDLER(send_message); +DECL_HANDLER(get_message); +DECL_HANDLER(reply_message); +DECL_HANDLER(get_message_reply); +DECL_HANDLER(in_send_message); +DECL_HANDLER(cleanup_window_queue); +DECL_HANDLER(set_win_timer); +DECL_HANDLER(kill_win_timer); DECL_HANDLER(create_serial); DECL_HANDLER(get_serial_info); DECL_HANDLER(set_serial_info); @@ -284,8 +294,18 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_get_atom_name, (req_handler)req_init_atom_table, (req_handler)req_get_msg_queue, - (req_handler)req_wake_queue, + (req_handler)req_set_queue_bits, + (req_handler)req_set_queue_mask, + (req_handler)req_get_queue_status, (req_handler)req_wait_input_idle, + (req_handler)req_send_message, + (req_handler)req_get_message, + (req_handler)req_reply_message, + (req_handler)req_get_message_reply, + (req_handler)req_in_send_message, + (req_handler)req_cleanup_window_queue, + (req_handler)req_set_win_timer, + (req_handler)req_kill_win_timer, (req_handler)req_create_serial, (req_handler)req_get_serial_info, (req_handler)req_set_serial_info, diff --git a/server/thread.c b/server/thread.c index ed01952a114..6d35d5ddd83 100644 --- a/server/thread.c +++ b/server/thread.c @@ -169,6 +169,16 @@ static void cleanup_thread( struct thread *thread ) if (thread->reply_fd != -1) close( thread->reply_fd ); if (thread->wait_fd != -1) close( thread->wait_fd ); if (thread->request_fd) release_object( thread->request_fd ); + if (thread->queue) + { + if (thread->process->queue == thread->queue) + { + release_object( thread->process->queue ); + thread->process->queue = NULL; + } + release_object( thread->queue ); + thread->queue = NULL; + } for (i = 0; i < MAX_INFLIGHT_FDS; i++) { if (thread->inflight[i].client != -1) @@ -191,14 +201,13 @@ static void destroy_thread( struct object *obj ) assert( obj->ops == &thread_ops ); assert( !thread->debug_ctx ); /* cannot still be debugging something */ - release_object( thread->process ); if (thread->next) thread->next->prev = thread->prev; if (thread->prev) thread->prev->next = thread->next; else first_thread = thread->next; while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc ); if (thread->info) release_object( thread->info ); - if (thread->queue) release_object( thread->queue ); cleanup_thread( thread ); + release_object( thread->process ); } /* dump a thread on stdout for debugging purposes */ @@ -223,6 +232,7 @@ struct thread *get_thread_from_id( void *id ) struct thread *t = first_thread; while (t && (t != id)) t = t->next; if (t) grab_object( t ); + else set_error( STATUS_INVALID_PARAMETER ); return t; } diff --git a/server/trace.c b/server/trace.c index f1648ccc1fc..a0f1fc24272 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1414,10 +1414,41 @@ static void dump_get_msg_queue_reply( const struct get_msg_queue_request *req ) fprintf( stderr, " handle=%d", req->handle ); } -static void dump_wake_queue_request( const struct wake_queue_request *req ) +static void dump_set_queue_bits_request( const struct set_queue_bits_request *req ) { fprintf( stderr, " handle=%d,", req->handle ); - fprintf( stderr, " bits=%08x", req->bits ); + fprintf( stderr, " set=%08x,", req->set ); + fprintf( stderr, " clear=%08x,", req->clear ); + fprintf( stderr, " mask_cond=%08x", req->mask_cond ); +} + +static void dump_set_queue_bits_reply( const struct set_queue_bits_request *req ) +{ + fprintf( stderr, " changed_mask=%08x", req->changed_mask ); +} + +static void dump_set_queue_mask_request( const struct set_queue_mask_request *req ) +{ + fprintf( stderr, " wake_mask=%08x,", req->wake_mask ); + fprintf( stderr, " changed_mask=%08x,", req->changed_mask ); + fprintf( stderr, " skip_wait=%d", req->skip_wait ); +} + +static void dump_set_queue_mask_reply( const struct set_queue_mask_request *req ) +{ + fprintf( stderr, " wake_bits=%08x,", req->wake_bits ); + fprintf( stderr, " changed_bits=%08x", req->changed_bits ); +} + +static void dump_get_queue_status_request( const struct get_queue_status_request *req ) +{ + fprintf( stderr, " clear=%d", req->clear ); +} + +static void dump_get_queue_status_reply( const struct get_queue_status_request *req ) +{ + fprintf( stderr, " wake_bits=%08x,", req->wake_bits ); + fprintf( stderr, " changed_bits=%08x", req->changed_bits ); } static void dump_wait_input_idle_request( const struct wait_input_idle_request *req ) @@ -1431,6 +1462,84 @@ static void dump_wait_input_idle_reply( const struct wait_input_idle_request *re fprintf( stderr, " event=%d", req->event ); } +static void dump_send_message_request( const struct send_message_request *req ) +{ + fprintf( stderr, " posted=%d,", req->posted ); + fprintf( stderr, " id=%p,", req->id ); + fprintf( stderr, " type=%d,", req->type ); + fprintf( stderr, " win=%d,", req->win ); + fprintf( stderr, " msg=%08x,", req->msg ); + fprintf( stderr, " wparam=%08x,", req->wparam ); + fprintf( stderr, " lparam=%08x,", req->lparam ); + fprintf( stderr, " info=%08x", req->info ); +} + +static void dump_get_message_request( const struct get_message_request *req ) +{ + fprintf( stderr, " remove=%d,", req->remove ); + fprintf( stderr, " posted=%d,", req->posted ); + fprintf( stderr, " get_win=%d,", req->get_win ); + fprintf( stderr, " get_first=%08x,", req->get_first ); + fprintf( stderr, " get_last=%08x", req->get_last ); +} + +static void dump_get_message_reply( const struct get_message_request *req ) +{ + fprintf( stderr, " sent=%d,", req->sent ); + fprintf( stderr, " type=%d,", req->type ); + fprintf( stderr, " win=%d,", req->win ); + fprintf( stderr, " msg=%08x,", req->msg ); + fprintf( stderr, " wparam=%08x,", req->wparam ); + fprintf( stderr, " lparam=%08x,", req->lparam ); + fprintf( stderr, " info=%08x", req->info ); +} + +static void dump_reply_message_request( const struct reply_message_request *req ) +{ + fprintf( stderr, " result=%08x,", req->result ); + fprintf( stderr, " remove=%d", req->remove ); +} + +static void dump_get_message_reply_request( const struct get_message_reply_request *req ) +{ + fprintf( stderr, " cancel=%d", req->cancel ); +} + +static void dump_get_message_reply_reply( const struct get_message_reply_request *req ) +{ + fprintf( stderr, " result=%08x", req->result ); +} + +static void dump_in_send_message_request( const struct in_send_message_request *req ) +{ +} + +static void dump_in_send_message_reply( const struct in_send_message_request *req ) +{ + fprintf( stderr, " flags=%d", req->flags ); +} + +static void dump_cleanup_window_queue_request( const struct cleanup_window_queue_request *req ) +{ + fprintf( stderr, " win=%d", req->win ); +} + +static void dump_set_win_timer_request( const struct set_win_timer_request *req ) +{ + fprintf( stderr, " win=%d,", req->win ); + fprintf( stderr, " msg=%08x,", req->msg ); + fprintf( stderr, " id=%08x,", req->id ); + fprintf( stderr, " rate=%08x,", req->rate ); + fprintf( stderr, " lparam=%08x", req->lparam ); +} + +static void dump_kill_win_timer_request( const struct kill_win_timer_request *req ) +{ + fprintf( stderr, " win=%d,", req->win ); + fprintf( stderr, " msg=%08x,", req->msg ); + fprintf( stderr, " id=%08x", req->id ); +} + static void dump_create_serial_request( const struct create_serial_request *req ) { fprintf( stderr, " access=%08x,", req->access ); @@ -1589,8 +1698,18 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_atom_name_request, (dump_func)dump_init_atom_table_request, (dump_func)dump_get_msg_queue_request, - (dump_func)dump_wake_queue_request, + (dump_func)dump_set_queue_bits_request, + (dump_func)dump_set_queue_mask_request, + (dump_func)dump_get_queue_status_request, (dump_func)dump_wait_input_idle_request, + (dump_func)dump_send_message_request, + (dump_func)dump_get_message_request, + (dump_func)dump_reply_message_request, + (dump_func)dump_get_message_reply_request, + (dump_func)dump_in_send_message_request, + (dump_func)dump_cleanup_window_queue_request, + (dump_func)dump_set_win_timer_request, + (dump_func)dump_kill_win_timer_request, (dump_func)dump_create_serial_request, (dump_func)dump_get_serial_info_request, (dump_func)dump_set_serial_info_request, @@ -1700,8 +1819,18 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_atom_name_reply, (dump_func)0, (dump_func)dump_get_msg_queue_reply, - (dump_func)0, + (dump_func)dump_set_queue_bits_reply, + (dump_func)dump_set_queue_mask_reply, + (dump_func)dump_get_queue_status_reply, (dump_func)dump_wait_input_idle_reply, + (dump_func)0, + (dump_func)dump_get_message_reply, + (dump_func)0, + (dump_func)dump_get_message_reply_reply, + (dump_func)dump_in_send_message_reply, + (dump_func)0, + (dump_func)0, + (dump_func)0, (dump_func)dump_create_serial_reply, (dump_func)dump_get_serial_info_reply, (dump_func)0, @@ -1811,8 +1940,18 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "get_atom_name", "init_atom_table", "get_msg_queue", - "wake_queue", + "set_queue_bits", + "set_queue_mask", + "get_queue_status", "wait_input_idle", + "send_message", + "get_message", + "reply_message", + "get_message_reply", + "in_send_message", + "cleanup_window_queue", + "set_win_timer", + "kill_win_timer", "create_serial", "get_serial_info", "set_serial_info", diff --git a/windows/clipboard.c b/windows/clipboard.c index 25b7adeac53..0b0c7289ca3 100644 --- a/windows/clipboard.c +++ b/windows/clipboard.c @@ -131,6 +131,7 @@ BOOL CLIPBOARD_IsLocked() * by another client. However the handler must have access to the * clipboard in order to update data in response to this message. */ +#if 0 MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() ); if ( queue @@ -141,6 +142,10 @@ BOOL CLIPBOARD_IsLocked() bIsLocked = FALSE; QUEUE_Unlock( queue ); +#else + /* FIXME: queue check no longer possible */ + bIsLocked = FALSE; +#endif } return bIsLocked; diff --git a/windows/message.c b/windows/message.c index 5648db3d3fc..383281af331 100644 --- a/windows/message.c +++ b/windows/message.c @@ -13,6 +13,7 @@ #include "wine/winbase16.h" #include "message.h" #include "winerror.h" +#include "server.h" #include "win.h" #include "heap.h" #include "hook.h" @@ -24,6 +25,7 @@ #include "winproc.h" #include "user.h" #include "thread.h" +#include "task.h" #include "options.h" #include "controls.h" #include "struct32.h" @@ -115,9 +117,9 @@ static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last, POINT16 pt; HANDLE16 hQ = GetFastQueue16(); MESSAGEQUEUE *queue = QUEUE_Lock(hQ); - BOOL mouseClick = ((message == WM_LBUTTONDOWN) || - (message == WM_RBUTTONDOWN) || - (message == WM_MBUTTONDOWN))?1:0; + int mouseClick = ((message == WM_LBUTTONDOWN) || + (message == WM_RBUTTONDOWN) || + (message == WM_MBUTTONDOWN)); DWORD retvalue; /* Find the window to dispatch this mouse message to */ @@ -155,7 +157,7 @@ static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last, /* Wake up the other task */ QUEUE_Unlock( queue ); queue = QUEUE_Lock( pWnd->hmemTaskQ ); - if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE ); + if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE, 0 ); QUEUE_Unlock( queue ); retvalue = SYSQ_MSG_ABANDON; @@ -387,7 +389,7 @@ static DWORD MSG_TranslateKbdMsg( HWND hTopWnd, DWORD first, DWORD last, /* Wake up the other task */ queue = QUEUE_Lock( pWnd->hmemTaskQ ); - if (queue) QUEUE_SetWakeBit( queue, QS_KEY ); + if (queue) QUEUE_SetWakeBit( queue, QS_KEY, 0 ); QUEUE_Unlock( queue ); WIN_ReleaseWndPtr(pWnd); return SYSQ_MSG_ABANDON; @@ -771,127 +773,59 @@ UINT WINAPI GetDoubleClickTime(void) static LRESULT MSG_SendMessageInterThread( HQUEUE16 hDestQueue, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, - DWORD timeout, WORD flags, + DWORD timeout, WORD type, LRESULT *pRes) { - MESSAGEQUEUE *queue, *destQ; - SMSG *smsg; - LRESULT retVal = 1; - int iWndsLocks; - - if (pRes) *pRes = 0; + MESSAGEQUEUE *destQ; + BOOL ret; + int iWndsLocks; + LRESULT result = 0; - if (IsTaskLocked16() || !IsWindow(hwnd)) - return 0; + TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n", hwnd, msg, SPY_GetMsgName(msg), wParam, lParam ); - /* create a SMSG structure to hold SendMessage() parameters */ - if (! (smsg = (SMSG *) HeapAlloc( GetProcessHeap(), 0, sizeof(SMSG) )) ) - return 0; - if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0; + if (!(destQ = QUEUE_Lock( hDestQueue ))) return 0; - if (!(destQ = QUEUE_Lock( hDestQueue ))) + SERVER_START_REQ( send_message ) { - QUEUE_Unlock( queue ); - return 0; + req->posted = FALSE; + req->id = destQ->teb->tid; + req->type = type; + req->win = hwnd; + req->msg = msg; + req->wparam = wParam; + req->lparam = lParam; + req->info = 0; + ret = !SERVER_CALL_ERR(); } - - TRACE_(sendmsg)("SM: %s [%04x] (%04x -> %04x)\n", - SPY_GetMsgName(msg), msg, queue->self, hDestQueue ); - - /* fill up SMSG structure */ - smsg->hWnd = hwnd; - smsg->msg = msg; - smsg->wParam = wParam; - smsg->lParam = lParam; - - smsg->lResult = 0; - smsg->hSrcQueue = pRes ? GetFastQueue16() : 0; - smsg->hDstQueue = hDestQueue; - smsg->flags = flags; - - if (pRes) { - /* add smsg struct in the processing SM list of the source queue */ - QUEUE_AddSMSG(queue, SM_PROCESSING_LIST, smsg); - } else { - /* this is a notification message, we don't need a reply */ - smsg->flags |= SMSG_ALREADY_REPLIED | SMSG_RECEIVER_CLEANS; - } - - /* add smsg struct in the pending list of the destination queue */ - if (QUEUE_AddSMSG(destQ, SM_PENDING_LIST, smsg) == FALSE) - { - retVal = 0; - goto CLEANUP; - } - - if (!pRes) goto CLEANUP; /* don't need a reply */ + SERVER_END_REQ; + QUEUE_Unlock( destQ ); + if (!ret) return 0; iWndsLocks = WIN_SuspendWndsLock(); /* wait for the result */ - while ( TRUE ) + QUEUE_WaitBits( QS_SMRESULT, timeout ); + + SERVER_START_REQ( get_message_reply ) { - /* - * The sequence is crucial to avoid deadlock situations: - * - first, we clear the QS_SMRESULT bit - * - then, we check the SMSG_HAVE_RESULT bit - * - only if this isn't set, we enter the wait state. - * - * As the receiver first sets the SMSG_HAVE_RESULT and then wakes us, - * we are guaranteed that -should we now clear the QS_SMRESULT that - * was signalled already by the receiver- we will not start waiting. - */ - - if ( smsg->flags & SMSG_HAVE_RESULT ) - { -got: - *pRes = smsg->lResult; - TRACE_(sendmsg)("smResult = %08x\n", (unsigned)*pRes ); - break; - } - - QUEUE_ClearWakeBit( queue, QS_SMRESULT ); - - if ( smsg->flags & SMSG_HAVE_RESULT ) - goto got; - - if( QUEUE_WaitBits( QS_SMRESULT, timeout ) == 0 ) - { - /* return with timeout */ - SetLastError( 0 ); - retVal = 0; - break; - } + req->cancel = 1; + if ((ret = !SERVER_CALL_ERR())) result = req->result; } + SERVER_END_REQ; + + TRACE( "hwnd %x msg %x (%s) wp %x lp %lx got reply %lx (err=%ld)\n", + hwnd, msg, SPY_GetMsgName(msg), wParam, lParam, result, GetLastError() ); + + if (!ret && (GetLastError() == ERROR_IO_PENDING)) + { + if (timeout == INFINITE) ERR("no timeout but no result\n"); + SetLastError(0); /* timeout */ + } + + if (pRes) *pRes = result; + WIN_RestoreWndsLock(iWndsLocks); - - /* remove the smsg from the processing list of the source queue */ - QUEUE_RemoveSMSG( queue, SM_PROCESSING_LIST, smsg ); - - /* Note: the destination thread is in charge of removing the smsg from - the pending list */ - - /* In the case of an early reply (or a timeout), sender thread will - released the smsg structure if the receiver thread is done - (SMSG_RECEIVED set). If the receiver thread isn't done, - SMSG_RECEIVER_CLEANS_UP flag is set, and it will be the receiver - responsibility to release smsg */ - EnterCriticalSection( &queue->cSection ); - - if (smsg->flags & SMSG_RECEIVED) - HeapFree(GetProcessHeap(), 0, smsg); - else - smsg->flags |= SMSG_RECEIVER_CLEANS; - - LeaveCriticalSection( &queue->cSection ); - - -CLEANUP: - QUEUE_Unlock( queue ); - QUEUE_Unlock( destQ ); - - TRACE_(sendmsg)("done!\n"); - return retVal; + return ret; } @@ -908,77 +842,14 @@ void WINAPI ReplyMessage16( LRESULT result ) */ BOOL WINAPI ReplyMessage( LRESULT result ) { - MESSAGEQUEUE *senderQ = 0; - MESSAGEQUEUE *queue = 0; - SMSG *smsg; - BOOL ret = FALSE; - - if (!(queue = QUEUE_Lock( GetFastQueue16() ))) - return FALSE; - - TRACE_(sendmsg)("ReplyMessage, queue %04x\n", queue->self); - - - if ( !(smsg = queue->smWaiting) - || !( (senderQ = QUEUE_Lock( smsg->hSrcQueue )) - || (smsg->flags & SMSG_ALREADY_REPLIED)) ) - goto ReplyMessageEnd; - - if ( !(smsg->flags & SMSG_ALREADY_REPLIED) ) + BOOL ret; + SERVER_START_REQ( reply_message ) { - /* This is the first reply, so pass result to sender */ - - TRACE_(sendmsg)("\trpm: smResult = %08lx\n", (long) result ); - - EnterCriticalSection(&senderQ->cSection); - - smsg->lResult = result; - smsg->flags |= SMSG_ALREADY_REPLIED; - - /* check if it's an early reply (called by the application) or - a regular reply (called by ReceiveMessage) */ - if ( !(smsg->flags & SMSG_SENDING_REPLY) ) - smsg->flags |= SMSG_EARLY_REPLY; - - smsg->flags |= SMSG_HAVE_RESULT; - - LeaveCriticalSection(&senderQ->cSection); - - /* tell the sending task that its reply is ready */ - QUEUE_SetWakeBit( senderQ, QS_SMRESULT ); - - ret = TRUE; + req->result = result; + req->remove = 0; + ret = !SERVER_CALL_ERR(); } - - if (smsg->flags & SMSG_SENDING_REPLY) - { - /* remove msg from the waiting list, since this is the last - ReplyMessage */ - QUEUE_RemoveSMSG( queue, SM_WAITING_LIST, smsg ); - - if (senderQ) EnterCriticalSection(&senderQ->cSection); - - /* tell the sender we're all done with smsg structure */ - smsg->flags |= SMSG_RECEIVED; - - /* sender will set SMSG_RECEIVER_CLEANS_UP if it wants the - receiver to clean up smsg, it could only happen when there is - an early reply or a timeout */ - if ( smsg->flags & SMSG_RECEIVER_CLEANS ) - { - TRACE_(sendmsg)("Receiver cleans up!\n" ); - HeapFree( GetProcessHeap(), 0, smsg ); - } - - if (senderQ) LeaveCriticalSection(&senderQ->cSection); - } - -ReplyMessageEnd: - if ( senderQ ) - QUEUE_Unlock( senderQ ); - if ( queue ) - QUEUE_Unlock( queue ); - + SERVER_END_REQ; return ret; } @@ -1116,9 +987,9 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, iWndsLocks = WIN_SuspendWndsLock(); while(1) - { - QMSG *qmsg; - + { + WORD wakeBits = HIWORD(GetQueueStatus( mask )); + hQueue = GetFastQueue16(); msgQueue = QUEUE_Lock( hQueue ); if (!msgQueue) @@ -1127,10 +998,7 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, return FALSE; } - EnterCriticalSection( &msgQueue->cSection ); - msgQueue->changeBits = 0; - LeaveCriticalSection( &msgQueue->cSection ); - +#if 0 /* First handle a message put by SendMessage() */ while ( QUEUE_ReceiveMessage( msgQueue ) ) @@ -1152,36 +1020,69 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, break; } LeaveCriticalSection( &msgQueue->cSection ); - +#endif + /* Now find a normal message */ retry: - if ((QUEUE_TestWakeBit(msgQueue, mask & QS_POSTMESSAGE)) && - ((qmsg = QUEUE_FindMsg( msgQueue, hwnd, first, last )) != 0)) + if (wakeBits & (QS_POSTMESSAGE|QS_TIMER|QS_PAINT)) { - /* Try to convert message to requested type */ - MSG tmpMsg = qmsg->msg; - if ( !MSG_ConvertMsg( &tmpMsg, qmsg->type, type ) ) + QMSG qmsg; + if (QUEUE_FindMsg( hwnd, first, last, flags & PM_REMOVE, FALSE, &qmsg )) { - ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n", - SPY_GetMsgName(tmpMsg.message)); - QUEUE_RemoveMsg( msgQueue, qmsg ); - goto retry; + /* Try to convert message to requested type */ + MSG tmpMsg = qmsg.msg; + if ( !MSG_ConvertMsg( &tmpMsg, qmsg.type, type ) ) + { + ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n", + SPY_GetMsgName(tmpMsg.message)); + /* remove it (FIXME) */ + if (!(flags & PM_REMOVE)) QUEUE_FindMsg( hwnd, first, last, TRUE, FALSE, &qmsg ); + goto retry; + } + + msg = tmpMsg; + msgQueue->GetMessageTimeVal = msg.time; + msgQueue->GetMessagePosVal = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y ); + msgQueue->GetMessageExtraInfoVal = qmsg.extraInfo; + + /* need to fill the window handle for WM_PAINT message */ + if (msg.message == WM_PAINT) + { + WND* wndPtr; + msg.hwnd = WIN_FindWinToRepaint( hwnd , hQueue ); + if ((wndPtr = WIN_FindWndPtr(msg.hwnd))) + { + if( wndPtr->dwStyle & WS_MINIMIZE && + (HICON) GetClassLongA(wndPtr->hwndSelf, GCL_HICON) ) + { + msg.message = WM_PAINTICON; + msg.wParam = 1; + } + + if( !hwnd || msg.hwnd == hwnd || IsChild16(hwnd,msg.hwnd) ) + { + if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate) + { + wndPtr->flags &= ~WIN_INTERNAL_PAINT; + QUEUE_DecPaintCount( hQueue ); + } + WIN_ReleaseWndPtr(wndPtr); + break; + } + WIN_ReleaseWndPtr(wndPtr); + } + } + else break; } - - msg = tmpMsg; - msgQueue->GetMessageTimeVal = msg.time; - msgQueue->GetMessagePosVal = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y ); - msgQueue->GetMessageExtraInfoVal = qmsg->extraInfo; - - if (flags & PM_REMOVE) QUEUE_RemoveMsg( msgQueue, qmsg ); - break; } changeBits = MSG_JournalPlayBackMsg(); +#if 0 /* FIXME */ EnterCriticalSection( &msgQueue->cSection ); msgQueue->changeBits |= changeBits; LeaveCriticalSection( &msgQueue->cSection ); +#endif /* Now find a hardware event */ @@ -1194,68 +1095,14 @@ static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, break; } - /* Check again for SendMessage */ - - while ( QUEUE_ReceiveMessage( msgQueue ) ) - ; - - /* Now find a WM_PAINT message */ - - if (QUEUE_TestWakeBit(msgQueue, mask & QS_PAINT)) - { - WND* wndPtr; - msg.hwnd = WIN_FindWinToRepaint( hwnd , hQueue ); - msg.message = WM_PAINT; - msg.wParam = 0; - msg.lParam = 0; - - if ((wndPtr = WIN_FindWndPtr(msg.hwnd))) - { - if( wndPtr->dwStyle & WS_MINIMIZE && - (HICON) GetClassLongA(wndPtr->hwndSelf, GCL_HICON) ) - { - msg.message = WM_PAINTICON; - msg.wParam = 1; - } - - if( !hwnd || msg.hwnd == hwnd || IsChild16(hwnd,msg.hwnd) ) - { - if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate) - { - wndPtr->flags &= ~WIN_INTERNAL_PAINT; - QUEUE_DecPaintCount( hQueue ); - } - WIN_ReleaseWndPtr(wndPtr); - break; - } - WIN_ReleaseWndPtr(wndPtr); - } - } - - /* Check for timer messages, but yield first */ - -#if 0 /* FIXME */ - if (!(flags & PM_NOYIELD)) - { - UserYield16(); - while ( QUEUE_ReceiveMessage( msgQueue ) ) - ; - } -#endif - - if (QUEUE_TestWakeBit(msgQueue, mask & QS_TIMER)) - { - if (TIMER_GetTimerMsg(&msg, hwnd, hQueue, flags & PM_REMOVE)) break; - } - if (peek) { #if 0 /* FIXME */ if (!(flags & PM_NOYIELD)) UserYield16(); #endif /* check for graphics events */ - if (USER_Driver.pMsgWaitForMultipleObjects) - USER_Driver.pMsgWaitForMultipleObjects( 0, NULL, FALSE, 0 ); + if (USER_Driver.pMsgWaitForMultipleObjectsEx) + USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 ); QUEUE_Unlock( msgQueue ); WIN_RestoreWndsLock(iWndsLocks); @@ -1556,23 +1403,38 @@ BOOL WINAPI GetMessageW( /*********************************************************************** * MSG_PostToQueue */ -static BOOL MSG_PostToQueue( HQUEUE16 hQueue, int type, HWND hwnd, +static BOOL MSG_PostToQueue( DWORD tid, int type, HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { - MSG msg; + unsigned int res; - if ( !hQueue ) return FALSE; + TRACE( "posting %x %x (%s) %x %lx\n", hwnd, message, SPY_GetMsgName(message), wParam, lParam ); - msg.hwnd = hwnd; - msg.message = message; - msg.wParam = wParam; - msg.lParam = lParam; - msg.time = GetTickCount(); - GetCursorPos(&msg.pt); + SERVER_START_REQ( send_message ) + { + req->posted = TRUE; + req->id = (void *)tid; + req->type = type; + req->win = hwnd; + req->msg = message; + req->wparam = wParam; + req->lparam = lParam; + req->info = 0; + res = SERVER_CALL(); + } + SERVER_END_REQ; - return QUEUE_AddMsg( hQueue, type, &msg, 0 ); + if (res) + { + if (res == STATUS_INVALID_PARAMETER) + SetLastError( ERROR_INVALID_THREAD_ID ); + else + SetLastError( RtlNtStatusToDosError(res) ); + } + return !res; } + /*********************************************************************** * MSG_IsPointerMessage * @@ -1652,7 +1514,6 @@ static BOOL MSG_IsPointerMessage(UINT message, WPARAM wParam, LPARAM lParam) { static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { - HQUEUE16 hQueue; WND *wndPtr; /* See thread on wine-devel around 6.2.2001. Basically posted messages @@ -1680,7 +1541,7 @@ static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message, { TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04X l=%08lX !\n", wndPtr->hwndSelf, message, wParam, lParam); - MSG_PostToQueue( wndPtr->hmemTaskQ, type, + MSG_PostToQueue( GetWindowThreadProcessId( wndPtr->hwndSelf, NULL ), type, wndPtr->hwndSelf, message, wParam, lParam ); } } @@ -1689,11 +1550,8 @@ static BOOL MSG_PostMessage( int type, HWND hwnd, UINT message, return TRUE; } - wndPtr = WIN_FindWndPtr( hwnd ); - hQueue = wndPtr? wndPtr->hmemTaskQ : 0; - WIN_ReleaseWndPtr(wndPtr); - - return MSG_PostToQueue( hQueue, type, hwnd, message, wParam, lParam ); + return MSG_PostToQueue( GetWindowThreadProcessId( hwnd, NULL ), + type, hwnd, message, wParam, lParam ); } /*********************************************************************** @@ -1730,8 +1588,9 @@ BOOL WINAPI PostMessageW( HWND hwnd, UINT message, WPARAM wParam, BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message, WPARAM16 wParam, LPARAM lParam ) { - return MSG_PostToQueue( GetTaskQueue16(hTask), QMSG_WIN16, - 0, message, wParam, lParam ); + TDB *pTask = TASK_GetPtr( hTask ); + if (!pTask) return FALSE; + return MSG_PostToQueue( (DWORD)pTask->teb->tid, QMSG_WIN16, 0, message, wParam, lParam ); } /********************************************************************** @@ -1740,8 +1599,7 @@ BOOL16 WINAPI PostAppMessage16( HTASK16 hTask, UINT16 message, BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message, WPARAM wParam, LPARAM lParam ) { - return MSG_PostToQueue( GetThreadQueue16(idThread), QMSG_WIN32A, - 0, message, wParam, lParam ); + return MSG_PostToQueue( idThread, QMSG_WIN32A, 0, message, wParam, lParam ); } /********************************************************************** @@ -1750,8 +1608,7 @@ BOOL WINAPI PostThreadMessageA( DWORD idThread, UINT message, BOOL WINAPI PostThreadMessageW( DWORD idThread, UINT message, WPARAM wParam, LPARAM lParam ) { - return MSG_PostToQueue( GetThreadQueue16(idThread), QMSG_WIN32W, - 0, message, wParam, lParam ); + return MSG_PostToQueue( idThread, QMSG_WIN32W, 0, message, wParam, lParam ); } @@ -1784,7 +1641,7 @@ static void MSG_CallWndProcHook( LPMSG pmsg, BOOL bUnicode ) * 1 otherwise */ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam, - LPARAM lParam, DWORD timeout, WORD flags, + LPARAM lParam, DWORD timeout, WORD type, LRESULT *pRes) { WND * wndPtr = 0; @@ -1814,7 +1671,7 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam, TRACE("BROADCAST Message to hWnd=%04x m=%04X w=%04lX l=%08lX !\n", wndPtr->hwndSelf, msg, (DWORD)wParam, lParam); MSG_SendMessage( wndPtr->hwndSelf, msg, wParam, lParam, - timeout, flags, pRes); + timeout, type, pRes); } } WIN_ReleaseWndPtr(wndPtr); @@ -1825,29 +1682,35 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam, if (HOOK_IsHooked( WH_CALLWNDPROC )) { - if (flags & SMSG_UNICODE) - MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE); - else if (flags & SMSG_WIN32) - MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE); - else + switch(type) { - LPCWPSTRUCT16 pmsg; + case QMSG_WIN16: + { + LPCWPSTRUCT16 pmsg; - if ((pmsg = SEGPTR_NEW(CWPSTRUCT16))) - { - pmsg->hwnd = hwnd & 0xffff; - pmsg->message= msg & 0xffff; - pmsg->wParam = wParam & 0xffff; - pmsg->lParam = lParam; - HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1, - (LPARAM)SEGPTR_GET(pmsg) ); - hwnd = pmsg->hwnd; - msg = pmsg->message; - wParam = pmsg->wParam; - lParam = pmsg->lParam; - SEGPTR_FREE( pmsg ); - } - } + if ((pmsg = SEGPTR_NEW(CWPSTRUCT16))) + { + pmsg->hwnd = hwnd & 0xffff; + pmsg->message= msg & 0xffff; + pmsg->wParam = wParam & 0xffff; + pmsg->lParam = lParam; + HOOK_CallHooks16( WH_CALLWNDPROC, HC_ACTION, 1, + (LPARAM)SEGPTR_GET(pmsg) ); + hwnd = pmsg->hwnd; + msg = pmsg->message; + wParam = pmsg->wParam; + lParam = pmsg->lParam; + SEGPTR_FREE( pmsg ); + } + } + break; + case QMSG_WIN32A: + MSG_CallWndProcHook( (LPMSG)&hwnd, FALSE); + break; + case QMSG_WIN32W: + MSG_CallWndProcHook( (LPMSG)&hwnd, TRUE); + break; + } } if (!(wndPtr = WIN_FindWndPtr( hwnd ))) @@ -1860,33 +1723,35 @@ static LRESULT MSG_SendMessage( HWND hwnd, UINT msg, WPARAM wParam, ret = 0; /* Don't send anything if the task is dying */ goto END; } - if (flags & SMSG_WIN32) + if (type != QMSG_WIN16) SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam ); else SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam ); if (wndPtr->hmemTaskQ && wndPtr->hmemTaskQ != GetFastQueue16()) ret = MSG_SendMessageInterThread( wndPtr->hmemTaskQ, hwnd, msg, - wParam, lParam, timeout, flags, pRes ); + wParam, lParam, timeout, type, pRes ); else { - LRESULT res; + LRESULT res = 0; /* Call the right CallWindowProc flavor */ - if (flags & SMSG_UNICODE) - res = CallWindowProcW( (WNDPROC)wndPtr->winproc, - hwnd, msg, wParam, lParam ); - else if (flags & SMSG_WIN32) - res = CallWindowProcA( (WNDPROC)wndPtr->winproc, - hwnd, msg, wParam, lParam ); - else - res = CallWindowProc16( (WNDPROC16)wndPtr->winproc, - (HWND16) hwnd, (UINT16) msg, - (WPARAM16) wParam, lParam ); + switch(type) + { + case QMSG_WIN16: + res = CallWindowProc16( (WNDPROC16)wndPtr->winproc, hwnd, msg, wParam, lParam ); + break; + case QMSG_WIN32A: + res = CallWindowProcA( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam ); + break; + case QMSG_WIN32W: + res = CallWindowProcW( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam ); + break; + } if (pRes) *pRes = res; } - if (flags & SMSG_WIN32) + if (type != QMSG_WIN16) SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, pRes?*pRes:0, wParam, lParam ); else SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, pRes?*pRes:0, wParam, lParam ); @@ -1903,7 +1768,7 @@ LRESULT WINAPI SendMessage16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, LPARAM lParam) { LRESULT res; - MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, 0, &res); + MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN16, &res); return res; } @@ -1916,8 +1781,7 @@ LRESULT WINAPI SendMessageA( HWND hwnd, UINT msg, WPARAM wParam, { LRESULT res; - MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, - SMSG_WIN32, &res); + MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32A, &res); return res; } @@ -1952,8 +1816,7 @@ LRESULT WINAPI SendMessageW( ) { LRESULT res; - MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, - SMSG_WIN32 | SMSG_UNICODE, &res); + MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, &res); return res; } @@ -1971,7 +1834,7 @@ LRESULT WINAPI SendMessageTimeout16( HWND16 hwnd, UINT16 msg, WPARAM16 wParam, /* FIXME: need support for SMTO_BLOCK */ - ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, 0, &msgRet); + ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN16, &msgRet); if (resultp) *resultp = (WORD) msgRet; return ret; } @@ -1989,8 +1852,7 @@ LRESULT WINAPI SendMessageTimeoutA( HWND hwnd, UINT msg, WPARAM wParam, /* FIXME: need support for SMTO_BLOCK */ - ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, SMSG_WIN32, - &msgRet); + ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32A, &msgRet); if (resultp) *resultp = (DWORD) msgRet; return ret; @@ -2009,8 +1871,7 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam, /* FIXME: need support for SMTO_BLOCK */ - ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, - SMSG_WIN32 | SMSG_UNICODE, &msgRet); + ret = MSG_SendMessage(hwnd, msg, wParam, lParam, timeout, QMSG_WIN32W, &msgRet); if (resultp) *resultp = (DWORD) msgRet; return ret; @@ -2022,77 +1883,82 @@ LRESULT WINAPI SendMessageTimeoutW( HWND hwnd, UINT msg, WPARAM wParam, * * WaitMessage() suspends a thread until events appear in the thread's * queue. - * - * BUGS - * - * Is supposed to return BOOL under Win32. - * - * Thread-local message queues are not supported. - * - * CONFORMANCE - * - * ECMA-234, Win32 - * */ -void WINAPI WaitMessage( void ) +BOOL WINAPI WaitMessage(void) { - QUEUE_WaitBits( QS_ALLINPUT, INFINITE ); + return (MsgWaitForMultipleObjectsEx( 0, NULL, INFINITE, QS_ALLINPUT, 0 ) != WAIT_FAILED); } + /*********************************************************************** - * MsgWaitForMultipleObjects (USER32.@) + * MsgWaitForMultipleObjectsEx (USER32.@) */ -DWORD WINAPI MsgWaitForMultipleObjects( DWORD nCount, HANDLE *pHandles, - BOOL fWaitAll, DWORD dwMilliseconds, - DWORD dwWakeMask ) +DWORD WINAPI MsgWaitForMultipleObjectsEx( DWORD count, CONST HANDLE *pHandles, + DWORD timeout, DWORD mask, DWORD flags ) { - DWORD i; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - DWORD ret; - + DWORD i, ret; HQUEUE16 hQueue = GetFastQueue16(); - MESSAGEQUEUE *msgQueue = QUEUE_Lock( hQueue ); - if (!msgQueue) return WAIT_FAILED; + MESSAGEQUEUE *msgQueue; - if (nCount > MAXIMUM_WAIT_OBJECTS-1) + if (count > MAXIMUM_WAIT_OBJECTS-1) { SetLastError( ERROR_INVALID_PARAMETER ); - QUEUE_Unlock( msgQueue ); return WAIT_FAILED; } - EnterCriticalSection( &msgQueue->cSection ); - msgQueue->changeBits = 0; - msgQueue->wakeMask = dwWakeMask; - LeaveCriticalSection( &msgQueue->cSection ); + if (!(msgQueue = QUEUE_Lock( hQueue ))) return WAIT_FAILED; + + /* set the queue mask */ + SERVER_START_REQ( set_queue_mask ) + { + req->wake_mask = (flags & MWMO_INPUTAVAILABLE) ? mask : 0; + req->changed_mask = mask; + req->skip_wait = 0; + SERVER_CALL(); + } + SERVER_END_REQ; /* Add the thread event to the handle list */ - for (i = 0; i < nCount; i++) handles[i] = pHandles[i]; - handles[nCount] = msgQueue->server_queue; - if (USER_Driver.pMsgWaitForMultipleObjects) + for (i = 0; i < count; i++) handles[i] = pHandles[i]; + handles[count] = msgQueue->server_queue; + + + if (USER_Driver.pMsgWaitForMultipleObjectsEx) { - ret = USER_Driver.pMsgWaitForMultipleObjects(nCount+1, handles, fWaitAll, dwMilliseconds); - if (ret == nCount+1) ret = nCount; /* pretend the msg queue is ready */ + ret = USER_Driver.pMsgWaitForMultipleObjectsEx( count+1, handles, timeout, mask, flags ); + if (ret == count+1) ret = count; /* pretend the msg queue is ready */ } else - ret = WaitForMultipleObjects( nCount+1, handles, fWaitAll, dwMilliseconds ); - + ret = WaitForMultipleObjectsEx( count+1, handles, flags & MWMO_WAITALL, + timeout, flags & MWMO_ALERTABLE ); QUEUE_Unlock( msgQueue ); return ret; } + /*********************************************************************** - * MsgWaitForMultipleObjects (USER.640) + * MsgWaitForMultipleObjects (USER32.@) */ -DWORD WINAPI MsgWaitForMultipleObjects16( DWORD nCount, HANDLE *pHandles, - BOOL fWaitAll, DWORD dwMilliseconds, - DWORD dwWakeMask ) +DWORD WINAPI MsgWaitForMultipleObjects( DWORD count, CONST HANDLE *handles, + BOOL wait_all, DWORD timeout, DWORD mask ) { - TRACE("(%lu,%p,%u,%lu,0x%lx)\n", - nCount, pHandles, fWaitAll, dwMilliseconds, dwWakeMask); - return MsgWaitForMultipleObjects(nCount, pHandles, fWaitAll, dwMilliseconds, dwWakeMask); + return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask, + wait_all ? MWMO_WAITALL : 0 ); } + +/*********************************************************************** + * MsgWaitForMultipleObjects16 (USER.640) + */ +DWORD WINAPI MsgWaitForMultipleObjects16( DWORD count, CONST HANDLE *handles, + BOOL wait_all, DWORD timeout, DWORD mask ) +{ + return MsgWaitForMultipleObjectsEx( count, handles, timeout, mask, + wait_all ? MWMO_WAITALL : 0 ); +} + + struct accent_char { BYTE ac_accent; @@ -2594,17 +2460,25 @@ BOOL16 WINAPI InSendMessage16(void) */ BOOL WINAPI InSendMessage(void) { - MESSAGEQUEUE *queue; - BOOL ret; + return (InSendMessageEx(NULL) & (ISMEX_SEND|ISMEX_REPLIED)) == ISMEX_SEND; +} - if (!(queue = QUEUE_Lock( GetFastQueue16() ))) - return 0; - ret = (BOOL)queue->smWaiting; - QUEUE_Unlock( queue ); +/*********************************************************************** + * InSendMessageEx (USER32.@) + */ +DWORD WINAPI InSendMessageEx( LPVOID reserved ) +{ + DWORD ret = 0; + SERVER_START_REQ( in_send_message ) + { + if (!SERVER_CALL_ERR()) ret = req->flags; + } + SERVER_END_REQ; return ret; } + /*********************************************************************** * BroadcastSystemMessage (USER32.@) */ @@ -2623,8 +2497,7 @@ LONG WINAPI BroadcastSystemMessage( */ BOOL WINAPI SendNotifyMessageA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { - return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, - SMSG_WIN32, NULL); + return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32A, NULL); } /*********************************************************************** @@ -2632,8 +2505,7 @@ BOOL WINAPI SendNotifyMessageA(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) */ BOOL WINAPI SendNotifyMessageW(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { - return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, - SMSG_WIN32 | SMSG_UNICODE, NULL); + return MSG_SendMessage(hwnd, msg, wParam, lParam, INFINITE, QMSG_WIN32W, NULL); } /*********************************************************************** diff --git a/windows/queue.c b/windows/queue.c index b66c53ba588..c2413c1863a 100644 --- a/windows/queue.c +++ b/windows/queue.c @@ -1,4 +1,5 @@ -/* * Message queues related functions +/* + * Message queues related functions * * Copyright 1993, 1994 Alexandre Julliard */ @@ -20,12 +21,11 @@ #include "server.h" #include "spy.h" -DECLARE_DEBUG_CHANNEL(msg); DECLARE_DEBUG_CHANNEL(sendmsg); +DEFAULT_DEBUG_CHANNEL(msg); #define MAX_QUEUE_SIZE 120 /* Max. size of a message queue */ -static HQUEUE16 hFirstQueue = 0; static HQUEUE16 hExitingQueue = 0; static HQUEUE16 hmemSysMsgQueue = 0; static MESSAGEQUEUE *sysMsgQueue = NULL; @@ -59,7 +59,7 @@ PERQUEUEDATA * PERQDATA_CreateInstance( ) TRACE_(msg)("()\n"); /* Share a single instance of perQData for all 16 bit tasks */ - if ( ( bIsWin16 = THREAD_IsWin16( NtCurrentTeb() ) ) ) + if ( ( bIsWin16 = !(NtCurrentTeb()->tibflags & TEBF_WIN32) ) ) { /* If previously allocated, just bump up ref count */ if ( pQDataWin16 ) @@ -363,21 +363,14 @@ void QUEUE_DumpQueue( HQUEUE16 hQueue ) EnterCriticalSection( &pq->cSection ); - DPRINTF( "next: %12.4x Intertask SendMessage:\n" - "thread: %10p ----------------------\n" - "firstMsg: %8p smWaiting: %10p\n" - "lastMsg: %8p smPending: %10p\n" - "msgCount: %8.4x smProcessing: %10p\n" + DPRINTF( "thread: %10p Intertask SendMessage:\n" + "firstMsg: %8p lastMsg: %8p\n" "lockCount: %7.4x\n" "paints: %10.4x\n" - "timers: %10.4x\n" - "wakeBits: %8.4x\n" - "wakeMask: %8.4x\n" "hCurHook: %8.4x\n", - pq->next, pq->teb, pq->firstMsg, pq->smWaiting, pq->lastMsg, - pq->smPending, pq->msgCount, pq->smProcessing, - (unsigned)pq->lockCount, pq->wPaintCount, pq->wTimerCount, - pq->wakeBits, pq->wakeMask, pq->hCurHook); + pq->teb, pq->firstMsg, pq->lastMsg, + (unsigned)pq->lockCount, pq->wPaintCount, + pq->hCurHook); LeaveCriticalSection( &pq->cSection ); @@ -385,34 +378,6 @@ void QUEUE_DumpQueue( HQUEUE16 hQueue ) } -/*********************************************************************** - * QUEUE_WalkQueues - */ -void QUEUE_WalkQueues(void) -{ - char module[10]; - HQUEUE16 hQueue = hFirstQueue; - - DPRINTF( "Queue Msgs Thread Task Module\n" ); - while (hQueue) - { - MESSAGEQUEUE *queue = QUEUE_Lock( hQueue ); - if (!queue) - { - WARN_(msg)("Bad queue handle %04x\n", hQueue ); - return; - } - if (!GetModuleName16( queue->teb->htask16, module, sizeof(module ))) - strcpy( module, "???" ); - DPRINTF( "%04x %4d %p %04x %s\n", hQueue,queue->msgCount, - queue->teb, queue->teb->htask16, module ); - hQueue = queue->next; - QUEUE_Unlock( queue ); - } - DPRINTF( "\n" ); -} - - /*********************************************************************** * QUEUE_IsExitingQueue */ @@ -452,24 +417,25 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData ) if ( !msgQueue ) return 0; - SERVER_START_REQ( get_msg_queue ) + if (bCreatePerQData) { - SERVER_CALL_ERR(); - handle = req->handle; + SERVER_START_REQ( get_msg_queue ) + { + SERVER_CALL_ERR(); + handle = req->handle; + } + SERVER_END_REQ; + if (!handle) + { + ERR_(msg)("Cannot get thread queue"); + GlobalFree16( hQueue ); + return 0; + } + msgQueue->server_queue = handle; } - SERVER_END_REQ; - if (!handle) - { - ERR_(msg)("Cannot get thread queue"); - GlobalFree16( hQueue ); - return 0; - } - msgQueue->server_queue = handle; - msgQueue->server_queue = ConvertToGlobalHandle( msgQueue->server_queue ); - msgQueue->self = hQueue; - msgQueue->wakeBits = msgQueue->changeBits = 0; - + msgQueue->self = hQueue; + InitializeCriticalSection( &msgQueue->cSection ); MakeCriticalSectionGlobal( &msgQueue->cSection ); @@ -483,44 +449,6 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData ) } -/*********************************************************************** - * QUEUE_FlushMessage - * - * Try to reply to all pending sent messages on exit. - */ -static void QUEUE_FlushMessages( MESSAGEQUEUE *queue ) -{ - SMSG *smsg; - MESSAGEQUEUE *senderQ = 0; - - if( queue ) - { - EnterCriticalSection( &queue->cSection ); - - /* empty the list of pending SendMessage waiting to be received */ - while (queue->smPending) - { - smsg = QUEUE_RemoveSMSG( queue, SM_PENDING_LIST, 0); - - senderQ = QUEUE_Lock( smsg->hSrcQueue ); - if ( !senderQ ) - continue; - - /* return 0, to unblock other thread */ - smsg->lResult = 0; - smsg->flags |= SMSG_HAVE_RESULT; - QUEUE_SetWakeBit( senderQ, QS_SMRESULT); - - QUEUE_Unlock( senderQ ); - } - - QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE ); - - LeaveCriticalSection( &queue->cSection ); - } -} - - /*********************************************************************** * QUEUE_DeleteMsgQueue * @@ -532,7 +460,6 @@ static void QUEUE_FlushMessages( MESSAGEQUEUE *queue ) BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ) { MESSAGEQUEUE * msgQueue = QUEUE_Lock(hQueue); - HQUEUE16 *pPrev; TRACE_(msg)("(): Deleting message queue %04x\n", hQueue); @@ -547,9 +474,6 @@ BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ) if( hCursorQueue == hQueue ) hCursorQueue = 0; if( hActiveQueue == hQueue ) hActiveQueue = 0; - /* flush sent messages */ - QUEUE_FlushMessages( msgQueue ); - HeapLock( GetProcessHeap() ); /* FIXME: a bit overkill */ /* Release per queue data if present */ @@ -558,24 +482,7 @@ BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue ) PERQDATA_Release( msgQueue->pQData ); msgQueue->pQData = 0; } - - /* remove the message queue from the global link list */ - pPrev = &hFirstQueue; - while (*pPrev && (*pPrev != hQueue)) - { - MESSAGEQUEUE *msgQ = (MESSAGEQUEUE*)GlobalLock16(*pPrev); - /* sanity check */ - if ( !msgQ || (msgQ->magic != QUEUE_MAGIC) ) - { - /* HQUEUE link list is corrupted, try to exit gracefully */ - ERR_(msg)("HQUEUE link list corrupted!\n"); - pPrev = 0; - break; - } - pPrev = &msgQ->next; - } - if (pPrev && *pPrev) *pPrev = msgQueue->next; msgQueue->self = 0; HeapUnlock( GetProcessHeap() ); @@ -619,47 +526,34 @@ MESSAGEQUEUE *QUEUE_GetSysQueue(void) * * See "Windows Internals", p.449 */ -static BOOL QUEUE_TrySetWakeBit( MESSAGEQUEUE *queue, WORD bit, BOOL always ) +static BOOL QUEUE_TrySetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear, BOOL always ) { BOOL wake = FALSE; - EnterCriticalSection( &queue->cSection ); + TRACE_(msg)("queue = %04x, set = %04x, clear = %04x, always = %d\n", + queue->self, set, clear, always ); + if (!queue->server_queue) return FALSE; - TRACE_(msg)("queue = %04x (wm=%04x), bit = %04x, always = %d\n", - queue->self, queue->wakeMask, bit, always ); - - if ((queue->wakeMask & bit) || always) + SERVER_START_REQ( set_queue_bits ) { - if (bit & QS_MOUSE) pMouseQueue = queue; - if (bit & QS_KEY) pKbdQueue = queue; - queue->changeBits |= bit; - queue->wakeBits |= bit; + req->handle = queue->server_queue; + req->set = set; + req->clear = clear; + req->mask_cond = always ? 0 : set; + if (!SERVER_CALL()) wake = (req->changed_mask & set) != 0; } - if (queue->wakeMask & bit) + SERVER_END_REQ; + + if (wake || always) { - queue->wakeMask = 0; - wake = TRUE; + if (set & QS_MOUSE) pMouseQueue = queue; + if (set & QS_KEY) pKbdQueue = queue; } - - LeaveCriticalSection( &queue->cSection ); - - if ( wake ) - { - /* Wake up thread waiting for message */ - SERVER_START_REQ( wake_queue ) - { - req->handle = queue->server_queue; - req->bits = bit; - SERVER_CALL(); - } - SERVER_END_REQ; - } - return wake; } -void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit ) +void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear ) { - QUEUE_TrySetWakeBit( queue, bit, TRUE ); + QUEUE_TrySetWakeBit( queue, set, clear, TRUE ); } @@ -668,25 +562,9 @@ void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD bit ) */ void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit ) { - EnterCriticalSection( &queue->cSection ); - queue->changeBits &= ~bit; - queue->wakeBits &= ~bit; - LeaveCriticalSection( &queue->cSection ); + QUEUE_SetWakeBit( queue, 0, bit ); } -/*********************************************************************** - * QUEUE_TestWakeBit - */ -WORD QUEUE_TestWakeBit( MESSAGEQUEUE *queue, WORD bit ) -{ - WORD ret; - EnterCriticalSection( &queue->cSection ); - ret = queue->wakeBits & bit; - LeaveCriticalSection( &queue->cSection ); - return ret; -} - - /*********************************************************************** * QUEUE_WaitBits * @@ -708,38 +586,44 @@ int QUEUE_WaitBits( WORD bits, DWORD timeout ) for (;;) { + unsigned int wake_bits = 0, changed_bits = 0; DWORD dwlc; - EnterCriticalSection( &queue->cSection ); + SERVER_START_REQ( set_queue_mask ) + { + req->wake_mask = QS_SENDMESSAGE; + req->changed_mask = bits | QS_SENDMESSAGE; + req->skip_wait = 1; + if (!SERVER_CALL()) + { + wake_bits = req->wake_bits; + changed_bits = req->changed_bits; + } + } + SERVER_END_REQ; - if (queue->changeBits & bits) + if (changed_bits & bits) { /* One of the bits is set; we can return */ - queue->wakeMask = 0; - - LeaveCriticalSection( &queue->cSection ); QUEUE_Unlock( queue ); return 1; } - if (queue->wakeBits & QS_SENDMESSAGE) + if (wake_bits & QS_SENDMESSAGE) { /* Process the sent message immediately */ - queue->wakeMask = 0; - - LeaveCriticalSection( &queue->cSection ); - QUEUE_ReceiveMessage( queue ); - continue; /* nested sm crux */ + QMSG msg; + QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg ); + continue; /* nested sm crux */ } - queue->wakeMask = bits | QS_SENDMESSAGE; - TRACE_(msg)("%04x: wakeMask is %04x, waiting\n", queue->self, queue->wakeMask); - LeaveCriticalSection( &queue->cSection ); + TRACE_(msg)("(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n", + queue->self, bits, wake_bits, changed_bits ); ReleaseThunkLock( &dwlc ); if (dwlc) TRACE_(msg)("had win16 lock\n"); - if (USER_Driver.pMsgWaitForMultipleObjects) - USER_Driver.pMsgWaitForMultipleObjects( 1, &queue->server_queue, FALSE, timeout ); + if (USER_Driver.pMsgWaitForMultipleObjectsEx) + USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, timeout, 0, 0 ); else WaitForSingleObject( queue->server_queue, timeout ); if (dwlc) RestoreThunkLock( dwlc ); @@ -747,323 +631,98 @@ int QUEUE_WaitBits( WORD bits, DWORD timeout ) } -/*********************************************************************** - * QUEUE_AddSMSG - * - * This routine is called when a SMSG need to be added to one of the three - * SM list. (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST) - */ -BOOL QUEUE_AddSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg ) +/* handle the reception of a sent message by calling the corresponding window proc */ +static void handle_sent_message( QMSG *msg ) { - TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, - smsg, SPY_GetMsgName(smsg->msg)); - - switch (list) + LRESULT result = 0; + MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() ); + DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */ + WND *wndPtr = WIN_FindWndPtr( msg->msg.hwnd ); + + TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n", + msg->msg.hwnd, msg->msg.message, SPY_GetMsgName(msg->msg.message), + msg->msg.wParam, msg->msg.lParam ); + + queue->GetMessageExtraInfoVal = msg->extraInfo; + + /* call the right version of CallWindowProcXX */ + switch(msg->type) { - case SM_PROCESSING_LIST: - /* don't need to be thread safe, only accessed by the - thread associated with the sender queue */ - smsg->nextProcessing = queue->smProcessing; - queue->smProcessing = smsg; - break; - - case SM_WAITING_LIST: - /* don't need to be thread safe, only accessed by the - thread associated with the receiver queue */ - smsg->nextWaiting = queue->smWaiting; - queue->smWaiting = smsg; - break; - - case SM_PENDING_LIST: - { - /* make it thread safe, could be accessed by the sender and - receiver thread */ - SMSG **prev; - - EnterCriticalSection( &queue->cSection ); - smsg->nextPending = NULL; - prev = &queue->smPending; - while ( *prev ) - prev = &(*prev)->nextPending; - *prev = smsg; - LeaveCriticalSection( &queue->cSection ); - - QUEUE_SetWakeBit( queue, QS_SENDMESSAGE ); - break; - } - - default: - ERR_(sendmsg)("Invalid list: %d", list); - break; + case QMSG_WIN16: + result = CallWindowProc16( (WNDPROC16)wndPtr->winproc, + (HWND16) msg->msg.hwnd, + (UINT16) msg->msg.message, + LOWORD(msg->msg.wParam), + msg->msg.lParam ); + break; + case QMSG_WIN32A: + result = CallWindowProcA( wndPtr->winproc, msg->msg.hwnd, msg->msg.message, + msg->msg.wParam, msg->msg.lParam ); + break; + case QMSG_WIN32W: + result = CallWindowProcW( wndPtr->winproc, msg->msg.hwnd, msg->msg.message, + msg->msg.wParam, msg->msg.lParam ); + break; } - return TRUE; + queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */ + WIN_ReleaseWndPtr(wndPtr); + QUEUE_Unlock( queue ); + + SERVER_START_REQ( reply_message ) + { + req->result = result; + req->remove = 1; + SERVER_CALL(); + } + SERVER_END_REQ; } -/*********************************************************************** - * QUEUE_RemoveSMSG - * - * This routine is called when a SMSG needs to be removed from one of the three - * SM lists (SM_PROCESSING_LIST, SM_PENDING_LIST, SM_WAITING_LIST). - * If smsg == 0, remove the first smsg from the specified list - */ -SMSG *QUEUE_RemoveSMSG( MESSAGEQUEUE *queue, int list, SMSG *smsg ) -{ - - switch (list) - { - case SM_PROCESSING_LIST: - /* don't need to be thread safe, only accessed by the - thread associated with the sender queue */ - - /* if smsg is equal to null, it means the first in the list */ - if (!smsg) - smsg = queue->smProcessing; - - TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, - smsg, SPY_GetMsgName(smsg->msg)); - /* In fact SM_PROCESSING_LIST is a stack, and smsg - should be always at the top of the list */ - if ( (smsg != queue->smProcessing) || !queue->smProcessing ) - { - ERR_(sendmsg)("smsg not at the top of Processing list, smsg=0x%p queue=0x%p\n", smsg, queue); - return 0; - } - else - { - queue->smProcessing = smsg->nextProcessing; - smsg->nextProcessing = 0; - } - return smsg; - - case SM_WAITING_LIST: - /* don't need to be thread safe, only accessed by the - thread associated with the receiver queue */ - - /* if smsg is equal to null, it means the first in the list */ - if (!smsg) - smsg = queue->smWaiting; - - TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, - smsg, SPY_GetMsgName(smsg->msg)); - /* In fact SM_WAITING_LIST is a stack, and smsg - should be always at the top of the list */ - if ( (smsg != queue->smWaiting) || !queue->smWaiting ) - { - ERR_(sendmsg)("smsg not at the top of Waiting list, smsg=0x%p queue=0x%p\n", smsg, queue); - return 0; - } - else - { - queue->smWaiting = smsg->nextWaiting; - smsg->nextWaiting = 0; - } - return smsg; - - case SM_PENDING_LIST: - /* make it thread safe, could be accessed by the sender and - receiver thread */ - EnterCriticalSection( &queue->cSection ); - - if (!smsg) - smsg = queue->smPending; - if ( (smsg != queue->smPending) || !queue->smPending ) - { - ERR_(sendmsg)("should always remove the top one in Pending list, smsg=0x%p queue=0x%p\n", smsg, queue); - LeaveCriticalSection( &queue->cSection ); - return 0; - } - - TRACE_(sendmsg)("queue=%x, list=%d, smsg=%p msg=%s\n", queue->self, list, - smsg, SPY_GetMsgName(smsg->msg)); - - queue->smPending = smsg->nextPending; - smsg->nextPending = 0; - - /* if no more SMSG in Pending list, clear QS_SENDMESSAGE flag */ - if (!queue->smPending) - QUEUE_ClearWakeBit( queue, QS_SENDMESSAGE ); - - LeaveCriticalSection( &queue->cSection ); - return smsg; - - default: - ERR_(sendmsg)("Invalid list: %d\n", list); - break; - } - - return 0; -} - - -/*********************************************************************** - * QUEUE_ReceiveMessage - * - * This routine is called to check whether a sent message is waiting - * for the queue. If so, it is received and processed. - */ -BOOL QUEUE_ReceiveMessage( MESSAGEQUEUE *queue ) -{ - LRESULT result = 0; - SMSG *smsg; - MESSAGEQUEUE *senderQ; - - EnterCriticalSection( &queue->cSection ); - if ( !((queue->wakeBits & QS_SENDMESSAGE) && queue->smPending) ) - { - LeaveCriticalSection( &queue->cSection ); - return FALSE; - } - LeaveCriticalSection( &queue->cSection ); - - TRACE_(sendmsg)("queue %04x\n", queue->self ); - - /* remove smsg on the top of the pending list and put it in the processing list */ - smsg = QUEUE_RemoveSMSG(queue, SM_PENDING_LIST, 0); - QUEUE_AddSMSG(queue, SM_WAITING_LIST, smsg); - - TRACE_(sendmsg)("RM: %s [%04x] (%04x -> %04x)\n", - SPY_GetMsgName(smsg->msg), smsg->msg, smsg->hSrcQueue, smsg->hDstQueue ); - - if (IsWindow( smsg->hWnd )) - { - WND *wndPtr = WIN_FindWndPtr( smsg->hWnd ); - DWORD extraInfo = queue->GetMessageExtraInfoVal; /* save ExtraInfo */ - - /* use sender queue extra info value while calling the window proc */ - senderQ = QUEUE_Lock( smsg->hSrcQueue ); - if (senderQ) - { - queue->GetMessageExtraInfoVal = senderQ->GetMessageExtraInfoVal; - QUEUE_Unlock( senderQ ); - } - - /* call the right version of CallWindowProcXX */ - if (smsg->flags & SMSG_WIN32) - { - TRACE_(sendmsg)("\trcm: msg is Win32\n" ); - if (smsg->flags & SMSG_UNICODE) - result = CallWindowProcW( wndPtr->winproc, - smsg->hWnd, smsg->msg, - smsg->wParam, smsg->lParam ); - else - result = CallWindowProcA( wndPtr->winproc, - smsg->hWnd, smsg->msg, - smsg->wParam, smsg->lParam ); - } - else /* Win16 message */ - result = CallWindowProc16( (WNDPROC16)wndPtr->winproc, - (HWND16) smsg->hWnd, - (UINT16) smsg->msg, - LOWORD (smsg->wParam), - smsg->lParam ); - - queue->GetMessageExtraInfoVal = extraInfo; /* Restore extra info */ - WIN_ReleaseWndPtr(wndPtr); - TRACE_(sendmsg)("result = %08x\n", (unsigned)result ); - } - else WARN_(sendmsg)("\trcm: bad hWnd\n"); - - - /* set SMSG_SENDING_REPLY flag to tell ReplyMessage16, it's not - an early reply */ - smsg->flags |= SMSG_SENDING_REPLY; - ReplyMessage( result ); - - TRACE_(sendmsg)("done!\n" ); - return TRUE; -} - - - -/*********************************************************************** - * QUEUE_AddMsg - * - * Add a message to the queue. Return FALSE if queue is full. - */ -BOOL QUEUE_AddMsg( HQUEUE16 hQueue, int type, MSG *msg, DWORD extraInfo ) -{ - MESSAGEQUEUE *msgQueue; - QMSG *qmsg; - - - if (!(msgQueue = QUEUE_Lock( hQueue ))) return FALSE; - - /* allocate new message in global heap for now */ - if (!(qmsg = (QMSG *) HeapAlloc( GetProcessHeap(), 0, sizeof(QMSG) ) )) - { - QUEUE_Unlock( msgQueue ); - return 0; - } - - EnterCriticalSection( &msgQueue->cSection ); - - /* Store message */ - qmsg->type = type; - qmsg->msg = *msg; - qmsg->extraInfo = extraInfo; - - /* insert the message in the link list */ - qmsg->nextMsg = 0; - qmsg->prevMsg = msgQueue->lastMsg; - - if (msgQueue->lastMsg) - msgQueue->lastMsg->nextMsg = qmsg; - - /* update first and last anchor in message queue */ - msgQueue->lastMsg = qmsg; - if (!msgQueue->firstMsg) - msgQueue->firstMsg = qmsg; - - msgQueue->msgCount++; - - LeaveCriticalSection( &msgQueue->cSection ); - - QUEUE_SetWakeBit( msgQueue, QS_POSTMESSAGE ); - QUEUE_Unlock( msgQueue ); - - return TRUE; -} - - - /*********************************************************************** * QUEUE_FindMsg * * Find a message matching the given parameters. Return -1 if none available. */ -QMSG* QUEUE_FindMsg( MESSAGEQUEUE * msgQueue, HWND hwnd, int first, int last ) +BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove, BOOL sent_only, QMSG *msg ) { - QMSG* qmsg; + BOOL ret = FALSE, sent = FALSE; - EnterCriticalSection( &msgQueue->cSection ); + if (!first && !last) last = ~0; - if (!msgQueue->msgCount) - qmsg = 0; - else if (!hwnd && !first && !last) - qmsg = msgQueue->firstMsg; - else + for (;;) { - /* look in linked list for message matching first and last criteria */ - for (qmsg = msgQueue->firstMsg; qmsg; qmsg = qmsg->nextMsg) + SERVER_START_REQ( get_message ) { - MSG *msg = &(qmsg->msg); - - if (!hwnd || (msg->hwnd == hwnd)) + req->remove = remove; + req->posted = !sent_only; + req->get_win = hwnd; + req->get_first = first; + req->get_last = last; + if ((ret = !SERVER_CALL())) { - if (!first && !last) - break; /* found it */ - - if ((msg->message >= first) && (!last || (msg->message <= last))) - break; /* found it */ + sent = req->sent; + msg->type = req->type; + msg->msg.hwnd = req->win; + msg->msg.message = req->msg; + msg->msg.wParam = req->wparam; + msg->msg.lParam = req->lparam; + msg->msg.time = 0; /* FIXME */ + msg->msg.pt.x = 0; /* FIXME */ + msg->msg.pt.y = 0; /* FIXME */ + msg->extraInfo = req->info; } - } - } - - LeaveCriticalSection( &msgQueue->cSection ); + } + SERVER_END_REQ; - return qmsg; + if (!ret || !sent) break; + handle_sent_message( msg ); + } + + if (ret) TRACE( "got hwnd %x msg %x (%s) wp %x lp %lx\n", + msg->msg.hwnd, msg->msg.message, SPY_GetMsgName(msg->msg.message), + msg->msg.wParam, msg->msg.lParam ); + return ret; } @@ -1092,82 +751,25 @@ void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg ) /* deallocate the memory for the message */ HeapFree( GetProcessHeap(), 0, qmsg ); - - msgQueue->msgCount--; - if (!msgQueue->msgCount) msgQueue->wakeBits &= ~QS_POSTMESSAGE; LeaveCriticalSection( &msgQueue->cSection ); } -#if 0 /*********************************************************************** - * QUEUE_WakeSomeone + * QUEUE_CleanupWindow * - * Wake a queue upon reception of a hardware event. + * Cleanup the queue to account for a window being deleted. */ -static void QUEUE_WakeSomeone( UINT message ) +void QUEUE_CleanupWindow( HWND hwnd ) { - WND* wndPtr = NULL; - WORD wakeBit; - HWND hwnd; - HQUEUE16 hQueue = 0; - MESSAGEQUEUE *queue = NULL; - - if (hCursorQueue) - hQueue = hCursorQueue; - - if( (message >= WM_KEYFIRST) && (message <= WM_KEYLAST) ) + SERVER_START_REQ( cleanup_window_queue ) { - wakeBit = QS_KEY; - if( hActiveQueue ) - hQueue = hActiveQueue; + req->win = hwnd; + SERVER_CALL(); } - else - { - wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON; - if( (hwnd = GetCapture()) ) - if( (wndPtr = WIN_FindWndPtr( hwnd )) ) - { - hQueue = wndPtr->hmemTaskQ; - WIN_ReleaseWndPtr(wndPtr); - } - } - - if( (hwnd = GetSysModalWindow16()) ) - { - if( (wndPtr = WIN_FindWndPtr( hwnd )) ) - { - hQueue = wndPtr->hmemTaskQ; - WIN_ReleaseWndPtr(wndPtr); - } - } - - if (hQueue) - { - queue = QUEUE_Lock( hQueue ); - QUEUE_SetWakeBit( queue, wakeBit ); - QUEUE_Unlock( queue ); - return; - } - - /* Search for someone to wake */ - hQueue = hFirstQueue; - while ( (queue = QUEUE_Lock( hQueue )) ) - { - if (QUEUE_TrySetWakeBit( queue, wakeBit, FALSE )) - { - QUEUE_Unlock( queue ); - return; - } - - hQueue = queue->next; - QUEUE_Unlock( queue ); - } - - WARN_(msg)("couldn't find queue\n"); + SERVER_END_REQ; } -#endif /*********************************************************************** @@ -1227,8 +829,6 @@ void hardware_event( UINT message, WPARAM wParam, LPARAM lParam, sysMsgQueue->lastMsg = qmsg; if (!sysMsgQueue->firstMsg) sysMsgQueue->firstMsg = qmsg; - - sysMsgQueue->msgCount++; } /* Store message */ @@ -1252,7 +852,7 @@ void hardware_event( UINT message, WPARAM wParam, LPARAM lParam, if ((message >= WM_KEYFIRST) && (message <= WM_KEYLAST)) wakeBit = QS_KEY; else wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON; - QUEUE_SetWakeBit( queue, wakeBit ); + QUEUE_SetWakeBit( queue, wakeBit, 0 ); QUEUE_Unlock( queue ); } } @@ -1289,7 +889,7 @@ void QUEUE_IncPaintCount( HQUEUE16 hQueue ) EnterCriticalSection( &queue->cSection ); queue->wPaintCount++; LeaveCriticalSection( &queue->cSection ); - QUEUE_SetWakeBit( queue, QS_PAINT ); + QUEUE_SetWakeBit( queue, QS_PAINT, 0 ); QUEUE_Unlock( queue ); } @@ -1304,39 +904,7 @@ void QUEUE_DecPaintCount( HQUEUE16 hQueue ) if (!(queue = QUEUE_Lock( hQueue ))) return; EnterCriticalSection( &queue->cSection ); queue->wPaintCount--; - if (!queue->wPaintCount) queue->wakeBits &= ~QS_PAINT; - LeaveCriticalSection( &queue->cSection ); - QUEUE_Unlock( queue ); -} - - -/*********************************************************************** - * QUEUE_IncTimerCount - */ -void QUEUE_IncTimerCount( HQUEUE16 hQueue ) -{ - MESSAGEQUEUE *queue; - - if (!(queue = QUEUE_Lock( hQueue ))) return; - EnterCriticalSection( &queue->cSection ); - queue->wTimerCount++; - LeaveCriticalSection( &queue->cSection ); - QUEUE_SetWakeBit( queue, QS_TIMER ); - QUEUE_Unlock( queue ); -} - - -/*********************************************************************** - * QUEUE_DecTimerCount - */ -void QUEUE_DecTimerCount( HQUEUE16 hQueue ) -{ - MESSAGEQUEUE *queue; - - if (!(queue = QUEUE_Lock( hQueue ))) return; - EnterCriticalSection( &queue->cSection ); - queue->wTimerCount--; - if (!queue->wTimerCount) queue->wakeBits &= ~QS_TIMER; + if (!queue->wPaintCount) QUEUE_ClearWakeBit( queue, QS_PAINT ); LeaveCriticalSection( &queue->cSection ); QUEUE_Unlock( queue ); } @@ -1367,14 +935,7 @@ void WINAPI PostQuitMessage16( INT16 exitCode ) */ void WINAPI PostQuitMessage( INT exitCode ) { - MESSAGEQUEUE *queue; - - if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return; - EnterCriticalSection( &queue->cSection ); - queue->wPostQMsg = TRUE; - queue->wExitCode = (WORD)exitCode; - LeaveCriticalSection( &queue->cSection ); - QUEUE_Unlock( queue ); + PostThreadMessageW( GetCurrentThreadId(), WM_QUIT, exitCode, 0 ); } @@ -1470,9 +1031,6 @@ HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags ) HeapLock( GetProcessHeap() ); /* FIXME: a bit overkill */ SetThreadQueue16( 0, hQueue ); teb->queue = hQueue; - - queuePtr->next = hFirstQueue; - hFirstQueue = hQueue; HeapUnlock( GetProcessHeap() ); QUEUE_Unlock( queuePtr ); @@ -1486,17 +1044,7 @@ HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags ) */ DWORD WINAPI GetQueueStatus16( UINT16 flags ) { - MESSAGEQUEUE *queue; - DWORD ret; - - if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0; - EnterCriticalSection( &queue->cSection ); - ret = MAKELONG( queue->changeBits, queue->wakeBits ); - queue->changeBits = 0; - LeaveCriticalSection( &queue->cSection ); - QUEUE_Unlock( queue ); - - return ret & MAKELONG( flags, flags ); + return GetQueueStatus( flags ); } /*********************************************************************** @@ -1504,17 +1052,16 @@ DWORD WINAPI GetQueueStatus16( UINT16 flags ) */ DWORD WINAPI GetQueueStatus( UINT flags ) { - MESSAGEQUEUE *queue; - DWORD ret; + DWORD ret = 0; - if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0; - EnterCriticalSection( &queue->cSection ); - ret = MAKELONG( queue->changeBits, queue->wakeBits ); - queue->changeBits = 0; - LeaveCriticalSection( &queue->cSection ); - QUEUE_Unlock( queue ); - - return ret & MAKELONG( flags, flags ); + SERVER_START_REQ( get_queue_status ) + { + req->clear = 1; + SERVER_CALL(); + ret = MAKELONG( req->changed_bits & flags, req->wake_bits & flags ); + } + SERVER_END_REQ; + return ret; } @@ -1526,6 +1073,23 @@ BOOL16 WINAPI GetInputState16(void) return GetInputState(); } +/*********************************************************************** + * GetInputState (USER32.@) + */ +BOOL WINAPI GetInputState(void) +{ + DWORD ret = 0; + + SERVER_START_REQ( get_queue_status ) + { + req->clear = 0; + SERVER_CALL(); + ret = req->wake_bits & (QS_KEY | QS_MOUSEBUTTON); + } + SERVER_END_REQ; + return ret; +} + /*********************************************************************** * WaitForInputIdle (USER32.@) */ @@ -1552,10 +1116,8 @@ DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut) ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE ); if ( ret == ( WAIT_OBJECT_0 + 1 )) { - MESSAGEQUEUE * queue; - if (!(queue = QUEUE_Lock( GetFastQueue16() ))) return 0xFFFFFFFF; - QUEUE_ReceiveMessage ( queue ); - QUEUE_Unlock ( queue ); + QMSG msg; + QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg ); continue; } if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) @@ -1573,50 +1135,24 @@ DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut) return WAIT_TIMEOUT; } -/*********************************************************************** - * GetInputState (USER32.@) - */ -BOOL WINAPI GetInputState(void) -{ - MESSAGEQUEUE *queue; - BOOL ret; - - if (!(queue = QUEUE_Lock( GetFastQueue16() ))) - return FALSE; - EnterCriticalSection( &queue->cSection ); - ret = queue->wakeBits & (QS_KEY | QS_MOUSEBUTTON); - LeaveCriticalSection( &queue->cSection ); - QUEUE_Unlock( queue ); - - return ret; -} - /*********************************************************************** * UserYield (USER.332) * UserYield16 (USER32.@) */ void WINAPI UserYield16(void) { - MESSAGEQUEUE *queue; + QMSG msg; /* Handle sent messages */ - queue = QUEUE_Lock( GetFastQueue16() ); - - while ( queue && QUEUE_ReceiveMessage( queue ) ) + while (QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg )) ; - QUEUE_Unlock( queue ); - /* Yield */ OldYield16(); /* Handle sent messages again */ - queue = QUEUE_Lock( GetFastQueue16() ); - - while ( queue && QUEUE_ReceiveMessage( queue ) ) + while (QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg )) ; - - QUEUE_Unlock( queue ); } /*********************************************************************** diff --git a/windows/timer.c b/windows/timer.c index 99935f375e4..030da6655fe 100644 --- a/windows/timer.c +++ b/windows/timer.c @@ -8,10 +8,12 @@ #include "wingdi.h" #include "wine/winuser16.h" #include "winuser.h" +#include "winerror.h" + #include "queue.h" #include "winproc.h" -#include "services.h" #include "message.h" +#include "server.h" #include "debugtools.h" DEFAULT_DEBUG_CHANNEL(timer); @@ -24,15 +26,13 @@ typedef struct tagTIMER UINT16 msg; /* WM_TIMER or WM_SYSTIMER */ UINT id; UINT timeout; - HANDLE hService; - BOOL expired; HWINDOWPROC proc; } TIMER; #define NB_TIMERS 34 #define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */ -#define SYS_TIMER_RATE 54925 +#define SYS_TIMER_RATE 55 /* min. timer rate in ms (actually 54.925)*/ static TIMER TimersArray[NB_TIMERS]; @@ -46,18 +46,6 @@ static CRITICAL_SECTION csTimer = CRITICAL_SECTION_INIT; */ static void TIMER_ClearTimer( TIMER * pTimer ) { - if ( pTimer->hService != INVALID_HANDLE_VALUE ) - { - SERVICE_Delete( pTimer->hService ); - pTimer->hService = INVALID_HANDLE_VALUE; - } - - if ( pTimer->expired ) - { - QUEUE_DecTimerCount( pTimer->hq ); - pTimer->expired = FALSE; - } - pTimer->hwnd = 0; pTimer->msg = 0; pTimer->id = 0; @@ -81,7 +69,7 @@ void TIMER_RemoveWindowTimers( HWND hwnd ) for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++) if ((pTimer->hwnd == hwnd) && pTimer->timeout) TIMER_ClearTimer( pTimer ); - + LeaveCriticalSection( &csTimer ); } @@ -106,85 +94,6 @@ void TIMER_RemoveQueueTimers( HQUEUE16 hqueue ) } -/*********************************************************************** - * TIMER_CheckTimer - */ -static void CALLBACK TIMER_CheckTimer( ULONG_PTR timer_ptr ) -{ - TIMER *pTimer = (TIMER *)timer_ptr; - HQUEUE16 wakeQueue = 0; - - EnterCriticalSection( &csTimer ); - - /* Paranoid check to prevent a race condition ... */ - if ( !pTimer->timeout ) - { - LeaveCriticalSection( &csTimer ); - return; - } - - if ( !pTimer->expired ) - { - TRACE("Timer expired: %04x, %04x, %04x, %08lx\n", - pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc); - - pTimer->expired = TRUE; - wakeQueue = pTimer->hq; - } - - LeaveCriticalSection( &csTimer ); - - /* Note: This has to be done outside the csTimer critical section, - otherwise we'll get deadlocks. */ - - if ( wakeQueue ) - QUEUE_IncTimerCount( wakeQueue ); -} - - -/*********************************************************************** - * TIMER_GetTimerMsg - * - * Build a message for an expired timer. - */ -BOOL TIMER_GetTimerMsg( MSG *msg, HWND hwnd, - HQUEUE16 hQueue, BOOL remove ) -{ - TIMER *pTimer; - int i; - - EnterCriticalSection( &csTimer ); - - for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++) - if ( pTimer->timeout != 0 && pTimer->expired - && (hwnd? (pTimer->hwnd == hwnd) : (pTimer->hq == hQueue)) ) - break; - - if ( i == NB_TIMERS ) - { - LeaveCriticalSection( &csTimer ); - return FALSE; /* No timer */ - } - - TRACE("Timer got message: %04x, %04x, %04x, %08lx\n", - pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc); - - if (remove) - pTimer->expired = FALSE; - - /* Build the message */ - msg->hwnd = pTimer->hwnd; - msg->message = pTimer->msg; - msg->wParam = pTimer->id; - msg->lParam = (LONG)pTimer->proc; - msg->time = GetTickCount(); - - LeaveCriticalSection( &csTimer ); - - return TRUE; -} - - /*********************************************************************** * TIMER_SetTimer */ @@ -193,12 +102,20 @@ static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout, { int i; TIMER * pTimer; + HWINDOWPROC winproc = 0; + + if (GetWindowThreadProcessId( hwnd, NULL ) != GetCurrentThreadId()) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return 0; + } if (!timeout) { /* timeout==0 is a legal argument UB 990821*/ WARN("Timeout== 0 not implemented, using timeout=1\n"); timeout=1; } + EnterCriticalSection( &csTimer ); /* Check if there's already a timer with the same hwnd and id */ @@ -228,21 +145,28 @@ static UINT TIMER_SetTimer( HWND hwnd, UINT id, UINT timeout, if (!hwnd) id = i + 1; + if (proc) WINPROC_SetProc( &winproc, proc, type, WIN_PROC_TIMER ); + + SERVER_START_REQ( set_win_timer ) + { + req->win = hwnd; + req->msg = sys ? WM_SYSTIMER : WM_TIMER; + req->id = id; + req->rate = max( timeout, SYS_TIMER_RATE ); + req->lparam = (unsigned int)winproc; + SERVER_CALL(); + } + SERVER_END_REQ; + /* Add the timer */ pTimer->hwnd = hwnd; - pTimer->hq = (hwnd) ? GetThreadQueue16( GetWindowThreadProcessId( hwnd, NULL ) ) - : GetFastQueue16( ); + pTimer->hq = GetFastQueue16(); pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER; pTimer->id = id; pTimer->timeout = timeout; - pTimer->proc = (HWINDOWPROC)0; - if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER ); + pTimer->proc = winproc; - pTimer->expired = FALSE; - pTimer->hService = SERVICE_AddTimer( max( timeout, (SYS_TIMER_RATE+500)/1000 ), - TIMER_CheckTimer, (ULONG_PTR)pTimer ); - TRACE("Timer added: %p, %04x, %04x, %04x, %08lx\n", pTimer, pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc ); @@ -262,6 +186,15 @@ static BOOL TIMER_KillTimer( HWND hwnd, UINT id, BOOL sys ) int i; TIMER * pTimer; + SERVER_START_REQ( kill_win_timer ) + { + req->win = hwnd; + req->msg = sys ? WM_SYSTIMER : WM_TIMER; + req->id = id; + SERVER_CALL(); + } + SERVER_END_REQ; + EnterCriticalSection( &csTimer ); /* Find the timer */ diff --git a/windows/win.c b/windows/win.c index a31f7567cb7..77a73c656f1 100644 --- a/windows/win.c +++ b/windows/win.c @@ -458,29 +458,8 @@ static WND* WIN_DestroyWindow( WND* wndPtr ) /* toss stale messages from the queue */ - if( wndPtr->hmemTaskQ ) - { - BOOL bPostQuit = FALSE; - WPARAM wQuitParam = 0; - MESSAGEQUEUE* msgQ = (MESSAGEQUEUE*) QUEUE_Lock(wndPtr->hmemTaskQ); - QMSG *qmsg; - - while( (qmsg = QUEUE_FindMsg(msgQ, hwnd, 0, 0)) != 0 ) - { - if( qmsg->msg.message == WM_QUIT ) - { - bPostQuit = TRUE; - wQuitParam = qmsg->msg.wParam; - } - QUEUE_RemoveMsg(msgQ, qmsg); - } - - QUEUE_Unlock(msgQ); - - /* repost WM_QUIT to make sure this app exits its message loop */ - if( bPostQuit ) PostQuitMessage(wQuitParam); - wndPtr->hmemTaskQ = 0; - } + QUEUE_CleanupWindow( hwnd ); + wndPtr->hmemTaskQ = 0; if (!(wndPtr->dwStyle & WS_CHILD)) if (wndPtr->wIDmenu) diff --git a/windows/x11drv/event.c b/windows/x11drv/event.c index 743f89452a5..9757619175c 100644 --- a/windows/x11drv/event.c +++ b/windows/x11drv/event.c @@ -167,17 +167,18 @@ void X11DRV_Synchronize( void ) /*********************************************************************** - * MsgWaitForMultipleObjects (X11DRV.@) + * MsgWaitForMultipleObjectsEx (X11DRV.@) */ -DWORD X11DRV_MsgWaitForMultipleObjects( DWORD count, HANDLE *handles, - BOOL wait_all, DWORD timeout ) +DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, + DWORD timeout, DWORD mask, DWORD flags ) { HANDLE new_handles[MAXIMUM_WAIT_OBJECTS+1]; /* FIXME! */ DWORD i, ret; struct x11drv_thread_data *data = NtCurrentTeb()->driver_data; if (!data || data->process_event_count) - return WaitForMultipleObjects( count, handles, wait_all, timeout ); + return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL, + timeout, flags & MWMO_ALERTABLE ); for (i = 0; i < count; i++) new_handles[i] = handles[i]; new_handles[count] = data->display_fd; @@ -187,7 +188,8 @@ DWORD X11DRV_MsgWaitForMultipleObjects( DWORD count, HANDLE *handles, XFlush( gdi_display ); XFlush( data->display ); wine_tsx11_unlock(); - ret = WaitForMultipleObjects( count+1, new_handles, wait_all, timeout ); + ret = WaitForMultipleObjectsEx( count+1, new_handles, flags & MWMO_WAITALL, + timeout, flags & MWMO_ALERTABLE ); if (ret == count) process_events( data->display ); data->process_event_count--; return ret;