From 039e13118ed61add68d370780d1c6bdb930b4a66 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sat, 26 Jul 2003 20:36:43 +0000 Subject: [PATCH] Implemented inter-thread SendMessageCallback. --- dlls/user/message.c | 34 ++++++- include/wine/server_protocol.h | 4 +- server/protocol.def | 8 +- server/queue.c | 169 +++++++++++++++++++++++---------- server/trace.c | 1 + windows/input.c | 24 ++--- 6 files changed, 174 insertions(+), 66 deletions(-) diff --git a/dlls/user/message.c b/dlls/user/message.c index a7ca4832d7a..ff32ec29f17 100644 --- a/dlls/user/message.c +++ b/dlls/user/message.c @@ -38,6 +38,7 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(msg); +WINE_DECLARE_DEBUG_CHANNEL(relay); #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE #define WM_NCMOUSELAST WM_NCMBUTTONDBLCLK @@ -1468,6 +1469,26 @@ static BOOL process_hardware_message( MSG *msg, ULONG_PTR extra_info, HWND hwnd, } +/*********************************************************************** + * call_sendmsg_callback + * + * Call the callback function of SendMessageCallback. + */ +static inline void call_sendmsg_callback( SENDASYNCPROC callback, HWND hwnd, UINT msg, + ULONG_PTR data, LRESULT result ) +{ + if (TRACE_ON(relay)) + DPRINTF( "%04lx:Call message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n", + GetCurrentThreadId(), callback, hwnd, SPY_GetMsgName( msg, hwnd ), + data, result ); + callback( hwnd, msg, data, result ); + if (TRACE_ON(relay)) + DPRINTF( "%04lx:Ret message callback %p (hwnd=%p,msg=%s,data=%08lx,result=%08lx)\n", + GetCurrentThreadId(), callback, hwnd, SPY_GetMsgName( msg, hwnd ), + data, result ); +} + + /*********************************************************************** * MSG_peek_message * @@ -1540,6 +1561,10 @@ BOOL MSG_peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, int flags ) case MSG_CALLBACK: info.flags = ISMEX_CALLBACK; break; + case MSG_CALLBACK_RESULT: + call_sendmsg_callback( (SENDASYNCPROC)info.msg.wParam, info.msg.hwnd, + info.msg.message, extra_info, info.msg.lParam ); + goto next; case MSG_OTHER_PROCESS: info.flags = ISMEX_SEND; if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam, @@ -1690,6 +1715,13 @@ static BOOL put_message_in_queue( DWORD dest_tid, const struct send_message_info req->lparam = info->lparam; req->time = GetCurrentTime(); req->timeout = timeout; + + if (info->type == MSG_CALLBACK) + { + req->callback = info->callback; + req->info = info->data; + } + if (info->flags & SMTO_ABORTIFHUNG) req->flags |= SEND_MSG_ABORT_IF_HUNG; for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] ); if ((res = wine_server_call( req ))) @@ -2043,7 +2075,7 @@ BOOL WINAPI SendMessageCallbackW( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpa if (dest_tid == GetCurrentThreadId()) { result = call_window_proc( hwnd, msg, wparam, lparam, TRUE, TRUE ); - callback( hwnd, msg, data, result ); + call_sendmsg_callback( callback, hwnd, msg, data, result ); return TRUE; } FIXME( "callback will not be called\n" ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index fe451abf117..38f10e26879 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2214,6 +2214,7 @@ struct send_message_request unsigned int time; unsigned int info; int timeout; + void* callback; /* VARARG(data,bytes); */ }; struct send_message_reply @@ -2227,6 +2228,7 @@ enum message_type MSG_UNICODE, MSG_NOTIFY, MSG_CALLBACK, + MSG_CALLBACK_RESULT, MSG_OTHER_PROCESS, MSG_POSTED, MSG_HARDWARE @@ -3645,6 +3647,6 @@ union generic_reply struct open_token_reply open_token_reply; }; -#define SERVER_PROTOCOL_VERSION 117 +#define SERVER_PROTOCOL_VERSION 118 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index c3e37ccd819..bf672b74382 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1574,6 +1574,7 @@ enum char_info_mode unsigned int time; /* message time */ unsigned int info; /* extra info */ int timeout; /* timeout for reply */ + void* callback; /* callback address */ VARARG(data,bytes); /* message data for sent messages */ @END @@ -1583,6 +1584,7 @@ enum message_type MSG_UNICODE, /* Unicode message (from SendMessageW) */ MSG_NOTIFY, /* notify message (from SendNotifyMessageW), always Unicode */ MSG_CALLBACK, /* callback message (from SendMessageCallbackW), always Unicode */ + MSG_CALLBACK_RESULT,/* result of a callback message */ MSG_OTHER_PROCESS, /* sent from other process, may include vararg data, always Unicode */ MSG_POSTED, /* posted message (from PostMessageW), always Unicode */ MSG_HARDWARE /* hardware message */ @@ -1600,12 +1602,12 @@ enum message_type int type; /* message type */ user_handle_t win; /* window handle */ unsigned int msg; /* message code */ - unsigned int wparam; /* parameters */ - unsigned int lparam; /* parameters */ + unsigned int wparam; /* parameters (callback function for MSG_CALLBACK_RESULT) */ + unsigned int lparam; /* parameters (result for MSG_CALLBACK_RESULT) */ int x; /* x position */ int y; /* y position */ unsigned int time; /* message time */ - unsigned int info; /* extra info */ + unsigned int info; /* extra info (callback argument for MSG_CALLBACK_RESULT) */ size_t total; /* total size of extra data */ VARARG(data,bytes); /* message data for sent messages */ @END diff --git a/server/queue.c b/server/queue.c index eb2c11cf0b0..65bb680fe31 100644 --- a/server/queue.c +++ b/server/queue.c @@ -42,16 +42,17 @@ enum message_kind { SEND_MESSAGE, POST_MESSAGE }; 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 */ - void *data; /* message reply data */ - unsigned int data_size; /* size of message reply data */ - struct timeout_user *timeout; /* result timeout */ + struct list sender_entry; /* entry 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 *callback_msg; /* message to queue for callback */ + void *data; /* message reply data */ + unsigned int data_size; /* size of message reply data */ + struct timeout_user *timeout; /* result timeout */ }; struct message @@ -110,22 +111,23 @@ struct thread_input struct msg_queue { - 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 */ - int paint_count; /* pending paint messages count */ + 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 */ + int paint_count; /* pending paint messages count */ struct message_list msg_list[NB_MSG_KINDS]; /* lists of 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 */ - struct thread_input *input; /* thread input descriptor */ - struct hook_table *hooks; /* hook table */ - struct timeval last_get_msg; /* time of last get message call */ + struct list send_result; /* stack of sent messages waiting for result */ + struct list callback_result; /* list of callback 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 */ + struct thread_input *input; /* thread input descriptor */ + struct hook_table *hooks; /* hook table */ + struct timeval last_get_msg; /* time of last get message call */ }; static void msg_queue_dump( struct object *obj, int verbose ); @@ -214,7 +216,6 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->changed_bits = 0; queue->changed_mask = 0; queue->paint_count = 0; - queue->send_result = NULL; queue->recv_result = NULL; queue->first_timer = NULL; queue->last_timer = NULL; @@ -223,6 +224,8 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->input = (struct thread_input *)grab_object( input ); queue->hooks = NULL; gettimeofday( &queue->last_get_msg, NULL ); + list_init( &queue->send_result ); + list_init( &queue->callback_result ); for (i = 0; i < NB_MSG_KINDS; i++) queue->msg_list[i].first = queue->msg_list[i].last = NULL; @@ -359,9 +362,20 @@ static void free_result( struct message_result *result ) { if (result->timeout) remove_timeout_user( result->timeout ); if (result->data) free( result->data ); + if (result->callback_msg) free( result->callback_msg ); free( result ); } +/* remove the result from the sender list it is on */ +static inline void remove_result_from_sender( struct message_result *result ) +{ + assert( result->sender ); + + list_remove( &result->sender_entry ); + result->sender = NULL; + if (!result->receiver) free_result( result ); +} + /* store the message result in the appropriate structure */ static void store_message_result( struct message_result *res, unsigned int result, unsigned int error ) @@ -374,9 +388,25 @@ static void store_message_result( struct message_result *res, unsigned int resul remove_timeout_user( res->timeout ); res->timeout = NULL; } - /* wake sender queue if waiting on this result */ - if (res->sender && res->sender->send_result == res) - set_queue_bits( res->sender, QS_SMRESULT ); + if (res->sender) + { + if (res->callback_msg) + { + /* queue the callback message in the sender queue */ + res->callback_msg->lparam = result; + append_message( &res->sender->msg_list[SEND_MESSAGE], res->callback_msg ); + set_queue_bits( res->sender, QS_SENDMESSAGE ); + res->callback_msg = NULL; + remove_result_from_sender( res ); + } + else + { + /* wake sender queue if waiting on this result */ + if (list_head(&res->sender->send_result) == &res->sender_entry) + set_queue_bits( res->sender, QS_SMRESULT ); + } + } + } /* free a message when deleting a queue or window */ @@ -427,20 +457,49 @@ static void result_timeout( void *private ) /* allocate and fill a message result structure */ static struct message_result *alloc_message_result( struct msg_queue *send_queue, struct msg_queue *recv_queue, - unsigned int timeout ) + struct message *msg, unsigned int timeout, + void *callback, unsigned int callback_data ) { struct message_result *result = mem_alloc( sizeof(*result) ); if (result) { - /* put the result on the sender result stack */ result->sender = send_queue; result->receiver = recv_queue; result->replied = 0; result->data = NULL; result->data_size = 0; result->timeout = NULL; - result->send_next = send_queue->send_result; - send_queue->send_result = result; + + if (msg->type == MSG_CALLBACK) + { + struct message *callback_msg = mem_alloc( sizeof(*callback_msg) ); + if (!callback_msg) + { + free( result ); + return NULL; + } + callback_msg->type = MSG_CALLBACK_RESULT; + callback_msg->win = msg->win; + callback_msg->msg = msg->msg; + callback_msg->wparam = (unsigned int)callback; + callback_msg->lparam = 0; + callback_msg->time = get_tick_count(); + callback_msg->x = 0; + callback_msg->y = 0; + callback_msg->info = callback_data; + callback_msg->result = NULL; + callback_msg->data = NULL; + callback_msg->data_size = 0; + + result->callback_msg = callback_msg; + list_add_head( &send_queue->callback_result, &result->sender_entry ); + } + else + { + result->callback_msg = NULL; + list_add_head( &send_queue->send_result, &result->sender_entry ); + } + if (timeout != -1) { struct timeval when; @@ -577,15 +636,16 @@ static void empty_msg_list( struct message_list *list ) /* cleanup all pending results when deleting a queue */ static void cleanup_results( struct msg_queue *queue ) { - struct message_result *result, *next; + struct list *entry; - result = queue->send_result; - while (result) + while ((entry = list_head( &queue->send_result )) != NULL) { - next = result->send_next; - result->sender = NULL; - if (!result->receiver) free_result( result ); - result = next; + remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) ); + } + + while ((entry = list_head( &queue->callback_result )) != NULL) + { + remove_result_from_sender( LIST_ENTRY( entry, struct message_result, sender_entry ) ); } while (queue->recv_result) @@ -1309,9 +1369,10 @@ DECL_HANDLER(send_message) case MSG_ASCII: case MSG_UNICODE: case MSG_CALLBACK: - if (!(msg->result = alloc_message_result( send_queue, recv_queue, req->timeout ))) + if (!(msg->result = alloc_message_result( send_queue, recv_queue, msg, + req->timeout, req->callback, req->info ))) { - free( msg ); + free_message( msg ); break; } /* fall through */ @@ -1333,6 +1394,7 @@ DECL_HANDLER(send_message) case MSG_HARDWARE: queue_hardware_message( recv_queue, msg ); break; + case MSG_CALLBACK_RESULT: /* cannot send this one */ default: set_error( STATUS_INVALID_PARAMETER ); free( msg ); @@ -1442,16 +1504,19 @@ DECL_HANDLER(reply_message) /* retrieve the reply for the last message sent */ DECL_HANDLER(get_message_reply) { + struct message_result *result; + struct list *entry; struct msg_queue *queue = current->queue; if (queue) { - struct message_result *result = queue->send_result; - set_error( STATUS_PENDING ); reply->result = 0; - if (result && (result->replied || req->cancel)) + if (!(entry = list_head( &queue->send_result ))) return; /* no reply ready */ + + result = LIST_ENTRY( entry, struct message_result, sender_entry ); + if (result->replied || req->cancel) { if (result->replied) { @@ -1465,11 +1530,15 @@ DECL_HANDLER(get_message_reply) result->data_size = 0; } } - queue->send_result = result->send_next; - result->sender = NULL; - if (!result->receiver) free_result( result ); - if (!queue->send_result || !queue->send_result->replied) - clear_queue_bits( queue, QS_SMRESULT ); + remove_result_from_sender( result ); + + entry = list_head( &queue->send_result ); + if (!entry) clear_queue_bits( queue, QS_SMRESULT ); + else + { + result = LIST_ENTRY( entry, struct message_result, sender_entry ); + if (!result->replied) clear_queue_bits( queue, QS_SMRESULT ); + } } } else set_error( STATUS_ACCESS_DENIED ); diff --git a/server/trace.c b/server/trace.c index d9f683353d7..22b542a81c0 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1844,6 +1844,7 @@ static void dump_send_message_request( const struct send_message_request *req ) fprintf( stderr, " time=%08x,", req->time ); fprintf( stderr, " info=%08x,", req->info ); fprintf( stderr, " timeout=%d,", req->timeout ); + fprintf( stderr, " callback=%p,", req->callback ); fprintf( stderr, " data=" ); dump_varargs_bytes( cur_size ); } diff --git a/windows/input.c b/windows/input.c index 3326129a0ec..2cca5876807 100644 --- a/windows/input.c +++ b/windows/input.c @@ -112,17 +112,19 @@ static void queue_hardware_message( UINT message, HWND hwnd, WPARAM wParam, LPAR { SERVER_START_REQ( send_message ) { - req->id = GetCurrentThreadId(); - req->type = MSG_HARDWARE; - req->win = hwnd; - req->msg = message; - req->wparam = wParam; - req->lparam = lParam; - req->x = xPos; - req->y = yPos; - req->time = time; - req->info = extraInfo; - req->timeout = 0; + req->id = GetCurrentThreadId(); + req->type = MSG_HARDWARE; + req->flags = 0; + req->win = hwnd; + req->msg = message; + req->wparam = wParam; + req->lparam = lParam; + req->x = xPos; + req->y = yPos; + req->time = time; + req->info = extraInfo; + req->timeout = -1; + req->callback = NULL; wine_server_call( req ); } SERVER_END_REQ;