From b628185b2f1b05b5815b833ccdd3751d4732e455 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 1 Apr 2008 12:15:55 -0700 Subject: [PATCH] user32: Implement BroadcastSystemMessage, try 7 --- dlls/user32/message.c | 174 ++++++++++++++++++--- dlls/user32/tests/Makefile.in | 1 + dlls/user32/tests/broadcast.c | 351 ++++++++++++++++++++++++++++++++++++++++ dlls/user32/user32.spec | 4 +- dlls/user32/win.h | 2 +- dlls/user32/winstation.c | 15 ++- include/wine/server_protocol.h | 3 +- server/protocol.def | 1 + server/trace.c | 1 + server/winstation.c | 9 +- 10 files changed, 533 insertions(+), 28 deletions(-) create mode 100644 dlls/user32/tests/broadcast.c diff --git a/dlls/user32/message.c b/dlls/user32/message.c index cc2603f..214459a 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 @@ -3343,24 +3344,113 @@ UINT WINAPI RegisterWindowMessageW( LPCWSTR str ) return ret; } +typedef struct BroadcastParm +{ + DWORD flags; + LPDWORD recipients; + UINT msg; + WPARAM wp; + LPARAM lp; + DWORD success; + HWINSTA winsta; +} BroadcastParm; -/*********************************************************************** - * BroadcastSystemMessageA (USER32.@) - * BroadcastSystemMessage (USER32.@) - */ -LONG WINAPI BroadcastSystemMessageA( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp ) +static BOOL CALLBACK bcast_childwindow( HWND hw, LPARAM lp ) { - if ((*recipients & BSM_APPLICATIONS) || (*recipients == BSM_ALLCOMPONENTS)) + BroadcastParm *parm = (BroadcastParm*)lp; + DWORD_PTR retval = 0; + LONG lresult; + + if (parm->flags & BSF_IGNORECURRENTTASK && WIN_IsCurrentProcess(hw)) + { + TRACE("Not telling myself %p\n", hw); + return TRUE; + } + + /* I don't know 100% for sure if this is what the windows implementation does, but it fits the tests */ + if (parm->flags & BSF_QUERY) + { + TRACE("Telling window %p using SendMessageTimeout\n", hw); + + /* Not tested for conflicting flags */ + if (parm->flags & BSF_FORCEIFHUNG || parm->flags & BSF_NOHANG) + lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, SMTO_ABORTIFHUNG, 2000, &retval ); + else if (parm->flags & BSF_NOTIMEOUTIFNOTHUNG) + lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, SMTO_NOTIMEOUTIFNOTHUNG, 2000, &retval ); + else + lresult = SendMessageTimeoutW( hw, parm->msg, parm->wp, parm->lp, SMTO_NORMAL, 2000, &retval ); + + if (!lresult && GetLastError() == ERROR_TIMEOUT) + { + WARN("Timed out!\n"); + if (!(parm->flags & BSF_FORCEIFHUNG)) + goto fail; + } + if (retval == BROADCAST_QUERY_DENY) + goto fail; + + return TRUE; + +fail: + parm->success = 0; + return FALSE; + } + else if (parm->flags & BSF_POSTMESSAGE) { - FIXME( "(%08x,%08x,%08x,%08lx,%08lx): semi-stub!\n", flags, *recipients, msg, wp, lp ); - PostMessageA( HWND_BROADCAST, msg, wp, lp ); - return 1; + TRACE("Telling window %p using PostMessage\n", hw); + PostMessageW( hw, parm->msg, parm->wp, parm->lp ); } else { - FIXME( "(%08x,%08x,%08x,%08lx,%08lx): stub!\n", flags, *recipients, msg, wp, lp); - return -1; + TRACE("Telling window %p using SendNotifyMessage\n", hw); + SendNotifyMessageW( hw, parm->msg, parm->wp, parm->lp ); } + + return TRUE; +} + +static BOOL CALLBACK bcast_desktop( LPWSTR desktop, LPARAM lp ) +{ + BOOL ret; + HDESK hdesktop; + BroadcastParm *parm = (BroadcastParm*)lp; + + TRACE("desktop: %s\n", debugstr_w( desktop )); + + hdesktop = open_remote_desktop( parm->winsta, desktop, 0, FALSE, DESKTOP_ENUMERATE|DESKTOP_WRITEOBJECTS|STANDARD_RIGHTS_WRITE ); + if (!hdesktop) + { + FIXME("Could not open desktop %s\n", debugstr_w(desktop)); + return TRUE; + } + + ret = EnumDesktopWindows( hdesktop, bcast_childwindow, lp ); + CloseDesktop(hdesktop); + TRACE("-->%d\n", ret); + return parm->success; +} + +static BOOL CALLBACK bcast_winsta( 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; + ((BroadcastParm *)lp)->winsta = hwinsta; + ret = EnumDesktopsW( hwinsta, bcast_desktop, lp ); + CloseWindowStation( hwinsta ); + TRACE("-->%d\n", ret); + return ret; +} + +/*********************************************************************** + * BroadcastSystemMessageA (USER32.@) + * BroadcastSystemMessage (USER32.@) + */ +LONG WINAPI BroadcastSystemMessageA( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp ) +{ + return BroadcastSystemMessageExA( flags, recipients, msg, wp, lp, NULL ); } @@ -3369,19 +3459,65 @@ 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)) + return BroadcastSystemMessageExW( flags, recipients, msg, wp, lp, NULL ); +} + +/*********************************************************************** + * BroadcastSystemMessageExA (USER32.@) + */ +LONG WINAPI BroadcastSystemMessageExA( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp, PBSMINFO pinfo ) +{ + map_wparam_AtoW( msg, &wp, WMCHAR_MAP_NOMAPPING ); + return BroadcastSystemMessageExW( flags, recipients, msg, wp, lp, NULL ); +} + + +/*********************************************************************** + * BroadcastSystemMessageExW (USER32.@) + */ +LONG WINAPI BroadcastSystemMessageExW( DWORD flags, LPDWORD recipients, UINT msg, WPARAM wp, LPARAM lp, PBSMINFO pinfo ) +{ + BroadcastParm parm; + DWORD recips = BSM_ALLCOMPONENTS; + BOOL ret = TRUE; + static const DWORD all_flags = ( BSF_QUERY | BSF_IGNORECURRENTTASK | BSF_FLUSHDISK | BSF_NOHANG + | BSF_POSTMESSAGE | BSF_FORCEIFHUNG | BSF_NOTIMEOUTIFNOTHUNG + | BSF_ALLOWSFW | BSF_SENDNOTIFYMESSAGE | BSF_RETURNHDESK | BSF_LUID ); + + TRACE("Flags: %08x, recipients: %p(0x%x), msg: %04x, wparam: %08lx, lparam: %08lx\n", flags, recipients, + (recipients ? *recipients : recips), msg, wp, lp); + + if (flags & ~all_flags) { - 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 0; } - else + + if (!recipients) + recipients = &recips; + + if ( pinfo && flags & BSF_QUERY ) + FIXME("Not returning PBSMINFO information yet\n"); + + parm.flags = flags; + parm.recipients = recipients; + parm.msg = msg; + parm.wp = wp; + parm.lp = lp; + parm.success = TRUE; + + if (*recipients & BSM_ALLDESKTOPS || *recipients == BSM_ALLCOMPONENTS) + ret = EnumWindowStationsW(bcast_winsta, (LONG_PTR)&parm); + else if (*recipients & BSM_APPLICATIONS) { - FIXME( "(%08x,%08x,%08x,%08lx,%08lx): stub!\n", flags, *recipients, msg, wp, lp ); - return -1; + EnumWindows(bcast_childwindow, (LONG_PTR)&parm); + ret = parm.success; } -} + else + FIXME("Recipients %08x not supported!\n", *recipients); + return ret; +} /*********************************************************************** * SetMessageQueue (USER32.@) diff --git a/dlls/user32/tests/Makefile.in b/dlls/user32/tests/Makefile.in index c3794cc..102653f 100644 --- a/dlls/user32/tests/Makefile.in +++ b/dlls/user32/tests/Makefile.in @@ -6,6 +6,7 @@ TESTDLL = user32.dll IMPORTS = user32 gdi32 advapi32 kernel32 CTESTS = \ + broadcast.c \ class.c \ clipboard.c \ combo.c \ diff --git a/dlls/user32/tests/broadcast.c b/dlls/user32/tests/broadcast.c new file mode 100644 index 0000000..317a512 --- /dev/null +++ b/dlls/user32/tests/broadcast.c @@ -0,0 +1,351 @@ +/* + * Unit tests for broadcastwindowmessage + * + * 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#define _WIN32_WINNT 0x0501 + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" + +#include "wine/test.h" + +typedef LONG WINAPI (*PBROADCAST)( DWORD,LPDWORD,UINT,WPARAM,LPARAM ); +typedef LONG WINAPI (*PBROADCASTEX)( DWORD,LPDWORD,UINT,WPARAM,LPARAM,PBSMINFO ); +static PBROADCAST pBroadcastA; +static PBROADCAST pBroadcastW; +static PBROADCASTEX pBroadcastExA; +static PBROADCASTEX pBroadcastExW; +static HANDLE hevent; + +static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_NULL) + { + trace("main_window_procA: Sleeping for %lu ms\n", wparam); + if (wparam) + { + if (WaitForSingleObject(hevent, wparam) == WAIT_TIMEOUT) + SetEvent(hevent); + } + trace("main_window_procA: Returning WM_NULL with parameter %08lx\n", lparam); + return lparam; + } + + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +static BOOL init_procs(void) +{ + WNDCLASSA cls; + HANDLE user32 = GetModuleHandle("user32"); + pBroadcastA = (PBROADCAST)GetProcAddress(user32, "BroadcastSystemMessageA"); + if (!pBroadcastA) + pBroadcastA = (PBROADCAST)GetProcAddress(user32, "BroadcastSystemMessage"); + ok(pBroadcastA != NULL, "No BroadcastSystemMessage found\n"); + if (!pBroadcastA) + return FALSE; + + pBroadcastW = (PBROADCAST)GetProcAddress(user32, "BroadcastSystemMessageW"); + pBroadcastExA = (PBROADCASTEX)GetProcAddress(user32, "BroadcastSystemMessageExA"); + pBroadcastExW = (PBROADCASTEX)GetProcAddress(user32, "BroadcastSystemMessageExW"); + + hevent = CreateEventA(NULL, TRUE, FALSE, "Asynchronous checking event"); + + cls.style = CS_DBLCLKS; + cls.lpfnWndProc = main_window_procA; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(0); + cls.hIcon = 0; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "MainWindowClass"; + + if (!RegisterClassA(&cls)) + return 0; + + if (!CreateWindowExA(0, "MainWindowClass", "Main window", WS_CAPTION | WS_SYSMENU | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP, 100, 100, 200, + 200, 0, 0, GetModuleHandle(0), NULL)) + return FALSE; + return TRUE; +} + +static void test_parameters(PBROADCAST broadcast) +{ + LONG ret; + DWORD recips; + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 ); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); + ok(!ret, "Returned: %d\n", ret); + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 ); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); + ok(!ret, "Returned: %d\n", ret); + +#if 0 /* TODO: Check the hang flags */ + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 ); + ok(0, "Last error: %08x\n", GetLastError()); + ok(0, "Returned: %d\n", ret); + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0 ); + ok(0, "Last error: %08x\n", GetLastError()); + ok(0, "Returned: %d\n", ret); + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 ); + ok(0, "Last error: %08x\n", GetLastError()); + ok(0, "Returned: %d\n", ret); + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 ); + ok(0, "Last error: %08x\n", GetLastError()); + ok(0, "Returned: %d\n", ret); +#endif + + recips = BSM_APPLICATIONS; + ResetEvent(hevent); + ret = broadcast( BSF_POSTMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, 0 ); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + PulseEvent(hevent); + + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0 ); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n"); + PulseEvent(hevent); + + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY ); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + PulseEvent(hevent); + + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY ); + ok(!ret, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + PulseEvent(hevent); + + recips = BSM_APPLICATIONS; + ret = broadcast( 0, &recips, WM_NULL, 100, 0 ); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + PulseEvent(hevent); +} + +/* BSF_SENDNOTIFYMESSAGE and BSF_QUERY are both synchronous within the same process + * However you should be able to distinguish them by sending the BROADCAST_QUERY_DENY flag + */ + +static void test_parametersEx(PBROADCASTEX broadcastex) +{ + LONG ret; + DWORD recips; + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL ); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); + ok(!ret, "Returned: %d\n", ret); + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL ); + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError()); + ok(!ret, "Returned: %d\n", ret); + +#if 0 /* TODO: Check the hang flags */ + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL ); + ok(0, "Last error: %08x\n", GetLastError()); + ok(0, "Returned: %d\n", ret); + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0, NULL ); + ok(0, "Last error: %08x\n", GetLastError()); + ok(0, "Returned: %d\n", ret); + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL ); + ok(0, "Last error: %08x\n", GetLastError()); + ok(0, "Returned: %d\n", ret); + + SetLastError(0xcafebabe); + recips = BSM_APPLICATIONS; + ret = broadcast( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL ); + ok(0, "Last error: %08x\n", GetLastError()); + ok(0, "Returned: %d\n", ret); +#endif + + recips = BSM_APPLICATIONS; + ResetEvent(hevent); + ret = broadcastex( BSF_POSTMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + PulseEvent(hevent); + + recips = BSM_APPLICATIONS; + ret = broadcastex( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0, NULL ); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n"); + PulseEvent(hevent); + + recips = BSM_APPLICATIONS; + ret = broadcastex( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL ); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + PulseEvent(hevent); + + recips = BSM_APPLICATIONS; + ret = broadcastex( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL ); + ok(!ret, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + PulseEvent(hevent); + + recips = BSM_APPLICATIONS; + ret = broadcastex( 0, &recips, WM_NULL, 100, 0, NULL ); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + PulseEvent(hevent); +} + +typedef BOOL WINAPI (*pOpenProcessToken)(HANDLE, DWORD, HANDLE*); +pOpenProcessToken pOpen; + +typedef BOOL WINAPI (*pAdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); +pAdjustTokenPrivileges pAdjust; + +static void test_noprivileges() +{ + HANDLE advapi32 = GetModuleHandleA("advapi32"); + HANDLE token; + DWORD recips; + BOOL ret; + + pOpen = (pOpenProcessToken)GetProcAddress(advapi32, "OpenProcessToken"); + pAdjust = (pAdjustTokenPrivileges)GetProcAddress(advapi32, "AdjustTokenPrivileges"); + if (!pOpen || !pAdjust || !pOpen(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) + { + skip("Can't open security token for process\n"); + return; + } + if (!pAdjust(token, TRUE, NULL, 0, NULL, NULL)) + { + skip("Can't adjust security token for process\n"); + return; + } + + trace("Trying privileged edition!\n"); + SetLastError(0xcafebabe); + recips = BSM_ALLDESKTOPS; + ResetEvent(hevent); + ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); + todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "Last error: %08x\n", GetLastError()); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + ok(recips == BSM_ALLDESKTOPS, "Received by: %08x\n", recips); + PulseEvent(hevent); + + /* Wine sets last error to 0, so just use that one as token here so it doesn't fail */ + SetLastError(0); + recips = BSM_ALLCOMPONENTS; + ResetEvent(hevent); + ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); + ok(!GetLastError(), "Last error: %08x\n", GetLastError()); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + ok(recips == BSM_ALLCOMPONENTS, "Received by: %08x\n", recips); + PulseEvent(hevent); + + SetLastError(0xcafebabe); + recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS; + ResetEvent(hevent); + ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL ); + todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "Last error: %08x\n", GetLastError()); + ok(ret==1, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS), "Received by: %08x\n", recips); + PulseEvent(hevent); + + SetLastError(0xcafebabe); + recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS; + ResetEvent(hevent); + ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL ); + todo_wine ok(GetLastError() == ERROR_PRIVILEGE_NOT_HELD, "Last error: %08x\n", GetLastError()); + ok(!ret, "Returned: %d\n", ret); + ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n"); + ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS), "Received by: %08x\n", recips); + PulseEvent(hevent); +} + +START_TEST(broadcast) +{ + if (!init_procs()) + return; + + trace("Running BroadcastSystemMessageA tests\n"); + test_parameters(pBroadcastA); + if (pBroadcastW) + { + trace("Running BroadcastSystemMessageW tests\n"); + test_parameters(pBroadcastW); + } + else + skip("No BroadcastSystemMessageW, skipping\n"); + if (pBroadcastExA) + { + trace("Running BroadcastSystemMessageExA tests\n"); + test_parametersEx(pBroadcastExA); + } + else + skip("No BroadcastSystemMessageExA, skipping\n"); + if (pBroadcastExW) + { + trace("Running BroadcastSystemMessageExW tests\n"); + test_parametersEx(pBroadcastExW); + trace("Attempting privileges checking tests\n"); + test_noprivileges(); + } + else + skip("No BroadcastSystemMessageExW, skipping\n"); +} diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index 1ef9732..30c3f42 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -16,8 +16,8 @@ @ stdcall BringWindowToTop(long) @ stdcall BroadcastSystemMessage(long ptr long long long) BroadcastSystemMessageA @ stdcall BroadcastSystemMessageA(long ptr long long long) -# @ stub BroadcastSystemMessageExA -# @ stub BroadcastSystemMessageExW +@ stdcall BroadcastSystemMessageExA (long ptr long long long ptr) +@ stdcall BroadcastSystemMessageExW (long ptr long long long ptr) @ stdcall BroadcastSystemMessageW(long ptr long long long) # @ stub BuildReasonArray @ stdcall CalcChildScroll(long long) diff --git a/dlls/user32/win.h b/dlls/user32/win.h index 581c520..79903ed 100644 --- a/dlls/user32/win.h +++ b/dlls/user32/win.h @@ -89,7 +89,7 @@ extern BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL ) DECLSPEC_HIDDEN; extern HWND *WIN_ListChildren( HWND hwnd ) DECLSPEC_HIDDEN; extern LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode ) DECLSPEC_HIDDEN; extern void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta, UINT *id ) DECLSPEC_HIDDEN; - +extern HDESK WINAPI open_remote_desktop( HWINSTA hwinsta, LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access ) DECLSPEC_HIDDEN; /* user lock */ extern void USER_Lock(void) DECLSPEC_HIDDEN; extern void USER_Unlock(void) DECLSPEC_HIDDEN; diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c index d836471..31d2430 100644 --- a/dlls/user32/winstation.c +++ b/dlls/user32/winstation.c @@ -317,10 +317,7 @@ HDESK WINAPI OpenDesktopA( LPCSTR name, DWORD flags, BOOL inherit, ACCESS_MASK a } -/****************************************************************************** - * OpenDesktopW (USER32.@) - */ -HDESK WINAPI OpenDesktopW( LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access ) +HDESK WINAPI open_remote_desktop( HWINSTA hwinsta, LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access ) { HANDLE ret = 0; DWORD len = name ? strlenW(name) : 0; @@ -334,6 +331,7 @@ HDESK WINAPI OpenDesktopW( LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK req->flags = flags; req->access = access; req->attributes = OBJ_CASE_INSENSITIVE | (inherit ? OBJ_INHERIT : 0); + req->winsta = hwinsta; wine_server_add_data( req, name, len * sizeof(WCHAR) ); if (!wine_server_call( req )) ret = reply->handle; } @@ -342,6 +340,15 @@ HDESK WINAPI OpenDesktopW( LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK } +/****************************************************************************** + * OpenDesktopW (USER32.@) + */ +HDESK WINAPI OpenDesktopW( LPCWSTR name, DWORD flags, BOOL inherit, ACCESS_MASK access ) +{ + return open_remote_desktop( NULL, name, flags, inherit, access ); +} + + /*********************************************************************** * CloseDesktop (USER32.@) */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index eab9f9c..810464c 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3299,6 +3299,7 @@ struct create_desktop_reply struct open_desktop_request { struct request_header __header; + obj_handle_t winsta; unsigned int flags; unsigned int access; unsigned int attributes; @@ -4995,6 +4996,6 @@ union generic_reply struct add_fd_completion_reply add_fd_completion_reply; }; -#define SERVER_PROTOCOL_VERSION 338 +#define SERVER_PROTOCOL_VERSION 339 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 23aaed5..01d94d2 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2399,6 +2399,7 @@ enum message_type /* Open a handle to a desktop */ @REQ(open_desktop) + obj_handle_t winsta; /* window station to open (null allowed) */ unsigned int flags; /* desktop flags */ unsigned int access; /* wanted access rights */ unsigned int attributes; /* object attributes */ diff --git a/server/trace.c b/server/trace.c index aa3293e..bbae524 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2972,6 +2972,7 @@ static void dump_create_desktop_reply( const struct create_desktop_reply *req ) static void dump_open_desktop_request( const struct open_desktop_request *req ) { + fprintf( stderr, " winsta=%p,", req->winsta ); fprintf( stderr, " flags=%08x,", req->flags ); fprintf( stderr, " access=%08x,", req->access ); fprintf( stderr, " attributes=%08x,", req->attributes ); diff --git a/server/winstation.c b/server/winstation.c index ee78ba7..720bb12 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -508,7 +508,14 @@ DECL_HANDLER(open_desktop) struct unicode_str name; get_req_unicode_str( &name ); - if ((winstation = get_process_winstation( current->process, 0 /* FIXME: access rights? */ ))) + + /* FIXME: check access rights */ + if (!req->winsta) + winstation = get_process_winstation( current->process, 0 ); + else + winstation = (struct winstation *)get_handle_obj( current->process, req->winsta, 0, &winstation_ops ); + + if (winstation) { struct unicode_str full_str; WCHAR *full_name; -- 1.5.4.1