From 73791620b8d59cd93652aad4cb68127179aaf295 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 6 Mar 2008 10:50:19 -0800 Subject: [PATCH] user32: Add a better stub for broadcastsystemmessage --- dlls/user32/message.c | 165 +++++++++++++++++++++++++++++++++++---- include/wine/server_protocol.h | 20 +++++- server/protocol.def | 10 +++ server/request.h | 2 + server/trace.c | 15 ++++ server/user.h | 1 + server/window.c | 5 + server/winstation.c | 33 ++++++++ 8 files changed, 233 insertions(+), 18 deletions(-) diff --git a/dlls/user32/message.c b/dlls/user32/message.c index eb0168f..6d4e967 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -2,6 +2,7 @@ * Window messaging support * * Copyright 2001 Alexandre Julliard + * Copyright 2008 Maarten Lankhorst * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -3336,6 +3337,116 @@ UINT WINAPI RegisterWindowMessageW( LPCWSTR str ) return ret; } +typedef struct BroadCastParameters +{ + DWORD flags; + LPDWORD recipients; + UINT msg; + WPARAM wp; + LPARAM lp; + DWORD success; +} BroadcastParm; + +static BOOL CALLBACK broadcastsystemmessagewindowcallback( HWND hw, LPARAM lp ) +{ + BroadcastParm *parm = (BroadcastParm*)lp; + DWORD timeoutflags; + DWORD_PTR retval = 0; + LONG lresult; + + TRACE("Telling window %p\n", hw); + + if (parm->flags & BSF_IGNORECURRENTTASK && WIN_IsCurrentProcess(hw)) + return TRUE; + + switch (parm->flags & (BSF_QUERY|BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE)) + { + case BSF_POSTMESSAGE: + PostMessageW( hw, parm->msg, parm->wp, parm->lp ); + break; + + case BSF_SENDNOTIFYMESSAGE: + SendNotifyMessageW( hw, parm->msg, parm->wp, parm->lp ); + break; + + case BSF_QUERY: + switch (parm->flags & (BSF_FORCEIFHUNG|BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG)) + { + case BSF_NOHANG: + case BSF_FORCEIFHUNG: + timeoutflags = SMTO_ABORTIFHUNG; + break; + case BSF_NOTIMEOUTIFNOTHUNG: + timeoutflags = SMTO_NOTIMEOUTIFNOTHUNG; + break; + default: + timeoutflags = SMTO_NORMAL; + break; + } + lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, timeoutflags, 2000, &retval ); + if (!lresult && GetLastError() == ERROR_TIMEOUT) + { + WARN("Timed out!\n"); + return parm->flags & BSF_FORCEIFHUNG; + } + return retval != BROADCAST_QUERY_DENY; + } + + return TRUE; +} + +static BOOL CALLBACK broadcastsystemmessagetopwindowcallback(HWND top_window, LPARAM lp) +{ + BOOL ret; + + TRACE("top_window: %p\n", top_window); + ret = EnumChildWindows( top_window, broadcastsystemmessagewindowcallback, lp ); + TRACE("-->%d\n", ret); + return ret; +} + +static BOOL WINAPI WIN_EnumTopWindows( HWINSTA winsta, LPARAM lp ) +{ + unsigned int index = 0; + HWND top_window; + BOOL ret = TRUE, sret; + + while (ret) + { + SERVER_START_REQ( enum_top_windows ) + { + req->winstation = winsta; + req->index = index; + sret = wine_server_call( req ); + index = reply->next; + top_window = reply->top_window; + } + SERVER_END_REQ; + if (sret == STATUS_NO_MORE_ENTRIES) + break; + else if (sret) + { + WARN("Error %08x occured\n", sret); + SetLastError( RtlNtStatusToDosError( sret ) ); + return FALSE; + } + ret = broadcastsystemmessagetopwindowcallback( top_window, lp ); + } + return ret; +} + +static BOOL CALLBACK broadcastsystemmessagewindowstationcallback( LPWSTR winsta, LPARAM lp ) +{ + BOOL ret; + HWINSTA hwinsta = OpenWindowStationW( winsta, FALSE, WINSTA_ENUMDESKTOPS ); + TRACE("hwinsta: %p/%s/%08x\n", hwinsta, debugstr_w( winsta ), GetLastError()); + if (!hwinsta) + return TRUE; + ret = WIN_EnumTopWindows( hwinsta, lp ); + CloseWindowStation( hwinsta ); + TRACE("-->%d\n", ret); + return ret; +} /*********************************************************************** * BroadcastSystemMessageA (USER32.@) @@ -3343,17 +3454,8 @@ UINT WINAPI RegisterWindowMessageW( LPCWSTR str ) */ LONG WINAPI BroadcastSystemMessageA( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp ) { - if ((*recipients & BSM_APPLICATIONS) || (*recipients == BSM_ALLCOMPONENTS)) - { - FIXME( "(%08x,%08x,%08x,%08lx,%08lx): semi-stub!\n", flags, *recipients, msg, wp, lp ); - PostMessageA( HWND_BROADCAST, msg, wp, lp ); - return 1; - } - else - { - FIXME( "(%08x,%08x,%08x,%08lx,%08lx): stub!\n", flags, *recipients, msg, wp, lp); - return -1; - } + map_wparam_AtoW( msg, &wp, WMCHAR_MAP_NOMAPPING ); + return BroadcastSystemMessageW( flags, recipients, msg, wp, lp ); } @@ -3362,17 +3464,46 @@ LONG WINAPI BroadcastSystemMessageA( DWORD flags, LPDWORD recipients, UINT msg, */ LONG WINAPI BroadcastSystemMessageW( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp ) { - if ((*recipients & BSM_APPLICATIONS) || (*recipients == BSM_ALLCOMPONENTS)) + BroadcastParm parm; + DWORD recips = BSM_ALLCOMPONENTS; + BOOL ret = TRUE; + + TRACE("Flags: %08x, recipients: %p(0x%x), msg: %04x, wparam: %08lx, lparam: %08lx\n", flags, recipients, + (recipients ? *recipients : recips), msg, wp, lp); + + FIXME("partial stub!\n"); + + if (!!(flags & BSF_QUERY) + !!(flags & BSF_POSTMESSAGE) + !!(flags & BSF_SENDNOTIFYMESSAGE) > 1) { - FIXME( "(%08x,%08x,%08x,%08lx,%08lx): semi-stub!\n", flags, *recipients, msg, wp, lp ); - PostMessageW( HWND_BROADCAST, msg, wp, lp ); - return 1; + SetLastError(ERROR_INVALID_PARAMETER); + return -1; } - else + + if (!!(flags & BSF_FORCEIFHUNG) + !!(flags & BSF_NOHANG) + !!(flags & BSF_NOTIMEOUTIFNOTHUNG) > 1) { - FIXME( "(%08x,%08x,%08x,%08lx,%08lx): stub!\n", flags, *recipients, msg, wp, lp ); + SetLastError(ERROR_INVALID_PARAMETER); return -1; } + + if (!(flags & (BSF_QUERY|BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE))) + /* It ignores values by default */ + flags |= BSF_POSTMESSAGE; + + if (!recipients) + recipients = &recips; + + parm.flags = flags; + parm.recipients = recipients; + parm.msg = msg; + parm.wp = wp; + parm.lp = lp; + + if (*recipients & BSM_APPLICATIONS || *recipients == BSM_ALLCOMPONENTS) + ret = EnumWindowStationsW(broadcastsystemmessagewindowstationcallback, (LONG_PTR)&parm); + else + FIXME("Recipients %08x not supported!\n", *recipients); + + return ret; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index a659d82..7852eee 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3279,6 +3279,21 @@ struct enum_winstation_reply +struct enum_top_windows_request +{ + struct request_header __header; + obj_handle_t winstation; + unsigned int index; +}; +struct enum_top_windows_reply +{ + struct reply_header __header; + unsigned int next; + obj_handle_t top_window; +}; + + + struct create_desktop_request { struct request_header __header; @@ -4452,6 +4467,7 @@ enum request REQ_get_process_winstation, REQ_set_process_winstation, REQ_enum_winstation, + REQ_enum_top_windows, REQ_create_desktop, REQ_open_desktop, REQ_close_desktop, @@ -4692,6 +4708,7 @@ union generic_request struct get_process_winstation_request get_process_winstation_request; struct set_process_winstation_request set_process_winstation_request; struct enum_winstation_request enum_winstation_request; + struct enum_top_windows_request enum_top_windows_request; struct create_desktop_request create_desktop_request; struct open_desktop_request open_desktop_request; struct close_desktop_request close_desktop_request; @@ -4930,6 +4947,7 @@ union generic_reply struct get_process_winstation_reply get_process_winstation_reply; struct set_process_winstation_reply set_process_winstation_reply; struct enum_winstation_reply enum_winstation_reply; + struct enum_top_windows_reply enum_top_windows_reply; struct create_desktop_reply create_desktop_reply; struct open_desktop_reply open_desktop_reply; struct close_desktop_reply close_desktop_reply; @@ -4994,6 +5012,6 @@ union generic_reply struct add_fd_completion_reply add_fd_completion_reply; }; -#define SERVER_PROTOCOL_VERSION 337 +#define SERVER_PROTOCOL_VERSION 338 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index ff8bf52..2d11002 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2385,6 +2385,16 @@ enum message_type @END +/* Enumerate all top window handles of a specified window station */ +@REQ(enum_top_windows) + obj_handle_t winstation; /* handle to the window station */ + unsigned int index; /* current index */ +@REPLY + unsigned int next; /* next index */ + obj_handle_t top_window; /* window station name */ +@END + + /* Create a desktop */ @REQ(create_desktop) unsigned int flags; /* desktop flags */ diff --git a/server/request.h b/server/request.h index 283ad97..0f75cf8 100644 --- a/server/request.h +++ b/server/request.h @@ -281,6 +281,7 @@ DECL_HANDLER(close_winstation); DECL_HANDLER(get_process_winstation); DECL_HANDLER(set_process_winstation); DECL_HANDLER(enum_winstation); +DECL_HANDLER(enum_top_windows); DECL_HANDLER(create_desktop); DECL_HANDLER(open_desktop); DECL_HANDLER(close_desktop); @@ -520,6 +521,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_get_process_winstation, (req_handler)req_set_process_winstation, (req_handler)req_enum_winstation, + (req_handler)req_enum_top_windows, (req_handler)req_create_desktop, (req_handler)req_open_desktop, (req_handler)req_close_desktop, diff --git a/server/trace.c b/server/trace.c index 61d0238..2f87b9f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2955,6 +2955,18 @@ static void dump_enum_winstation_reply( const struct enum_winstation_reply *req dump_varargs_unicode_str( cur_size ); } +static void dump_enum_top_windows_request( const struct enum_top_windows_request *req ) +{ + fprintf( stderr, " winstation=%p,", req->winstation ); + fprintf( stderr, " index=%08x", req->index ); +} + +static void dump_enum_top_windows_reply( const struct enum_top_windows_reply *req ) +{ + fprintf( stderr, " next=%08x,", req->next ); + fprintf( stderr, " top_window=%p", req->top_window ); +} + static void dump_create_desktop_request( const struct create_desktop_request *req ) { fprintf( stderr, " flags=%08x,", req->flags ); @@ -3952,6 +3964,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_process_winstation_request, (dump_func)dump_set_process_winstation_request, (dump_func)dump_enum_winstation_request, + (dump_func)dump_enum_top_windows_request, (dump_func)dump_create_desktop_request, (dump_func)dump_open_desktop_request, (dump_func)dump_close_desktop_request, @@ -4188,6 +4201,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_process_winstation_reply, (dump_func)0, (dump_func)dump_enum_winstation_reply, + (dump_func)dump_enum_top_windows_reply, (dump_func)dump_create_desktop_reply, (dump_func)dump_open_desktop_reply, (dump_func)0, @@ -4424,6 +4438,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "get_process_winstation", "set_process_winstation", "enum_winstation", + "enum_top_windows", "create_desktop", "open_desktop", "close_desktop", diff --git a/server/user.h b/server/user.h index 946b578..49198b9 100644 --- a/server/user.h +++ b/server/user.h @@ -137,6 +137,7 @@ extern struct thread *get_window_thread( user_handle_t handle ); extern user_handle_t window_from_point( struct desktop *desktop, int x, int y ); extern user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread ); extern struct window_class *get_window_class( user_handle_t window ); +extern obj_handle_t get_window_handle( struct window *window ); /* window class functions */ diff --git a/server/window.c b/server/window.c index 2633cd2..b3707b8 100644 --- a/server/window.c +++ b/server/window.c @@ -122,6 +122,11 @@ static inline struct window *get_window( user_handle_t handle ) return ret; } +obj_handle_t get_window_handle( struct window *window ) +{ + return window->handle; +} + /* check if window is the desktop */ static inline int is_desktop_window( const struct window *win ) { diff --git a/server/winstation.c b/server/winstation.c index 3b163a7..baed85e 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -679,3 +679,37 @@ DECL_HANDLER(enum_desktop) release_object( winstation ); set_error( STATUS_NO_MORE_ENTRIES ); } + + +/* enumerate top windows of desktops */ +DECL_HANDLER(enum_top_windows) +{ + struct winstation *winstation; + struct desktop *desktop; + unsigned int index = req->index; + obj_handle_t handle; + + if (!(winstation = (struct winstation *)get_handle_obj( current->process, req->winstation, + WINSTA_ENUMDESKTOPS, &winstation_ops ))) + return; + + while ((handle = enumerate_handles( current->process, &desktop_ops, &index ))) + { + if (!(desktop = get_desktop_obj( current->process, handle, DESKTOP_ENUMERATE ))) + continue; + + if (desktop->winstation == winstation && desktop->top_window) + { + release_object( desktop ); + release_object( winstation ); + clear_error(); + reply->next = index; + reply->top_window = get_window_handle(desktop->top_window); + return; + } + release_object( desktop ); + } + + release_object( winstation ); + set_error( STATUS_NO_MORE_ENTRIES ); +} -- 1.5.4.1