1 /*
2  * Unit tests for BroadcastSystemMessage
3  *
4  * Copyright 2008 Maarten Lankhorst
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #ifndef __REACTOS__
22 #define _WIN32_WINNT 0x0501
23 #endif
24 
25 #include <stdarg.h>
26 #include <stdio.h>
27 
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 
34 #include "wine/test.h"
35 
36 typedef LONG (WINAPI *PBROADCAST)( DWORD,LPDWORD,UINT,WPARAM,LPARAM );
37 typedef LONG (WINAPI *PBROADCASTEX)( DWORD,LPDWORD,UINT,WPARAM,LPARAM,PBSMINFO );
38 static HANDLE hevent;
39 
40 static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
41 {
42     if (msg == WM_NULL)
43     {
44         trace("main_window_procA: Sleeping for %lu ms\n", wparam);
45         if (wparam)
46         {
47             if (WaitForSingleObject(hevent, wparam) == WAIT_TIMEOUT)
48                 SetEvent(hevent);
49         }
50         trace("main_window_procA: Returning WM_NULL with parameter %08lx\n", lparam);
51         return lparam;
52     }
53 
54     return DefWindowProcA(hwnd, msg, wparam, lparam);
55 }
56 
57 static BOOL init_procs(void)
58 {
59     WNDCLASSA cls;
60 
61     hevent = CreateEventA(NULL, TRUE, FALSE, "Asynchronous checking event");
62 
63     cls.style = CS_DBLCLKS;
64     cls.lpfnWndProc = main_window_procA;
65     cls.cbClsExtra = 0;
66     cls.cbWndExtra = 0;
67     cls.hInstance = GetModuleHandleA(0);
68     cls.hIcon = 0;
69     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
70     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
71     cls.lpszMenuName = NULL;
72     cls.lpszClassName = "MainWindowClass";
73 
74     if (!RegisterClassA(&cls))
75         return FALSE;
76 
77     if (!CreateWindowExA(0, "MainWindowClass", "Main window", WS_CAPTION | WS_SYSMENU |
78                                WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP, 100, 100, 200,
79                                200, 0, 0, GetModuleHandleA(NULL), NULL))
80         return FALSE;
81     return TRUE;
82 }
83 
84 static void test_parameters(PBROADCAST broadcast, const char *functionname)
85 {
86     LONG ret;
87     DWORD recips;
88 
89     SetLastError(0xcafebabe);
90     recips = BSM_APPLICATIONS;
91     ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 );
92     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
93     {
94         win_skip("%s is not implemented\n", functionname);
95         return;
96     }
97     ok(!ret || broken(ret), "Returned: %d\n", ret);
98     if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
99 
100     SetLastError(0xcafebabe);
101     recips = BSM_APPLICATIONS;
102     ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 );
103     ok(!ret || broken(ret), "Returned: %d\n", ret);
104     if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
105 
106 if (0) /* TODO: Check the hang flags */
107 {
108     SetLastError(0xcafebabe);
109     recips = BSM_APPLICATIONS;
110     ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 );
111     ok(0, "Last error: %08x\n", GetLastError());
112     ok(0, "Returned: %d\n", ret);
113 
114     SetLastError(0xcafebabe);
115     recips = BSM_APPLICATIONS;
116     ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0 );
117     ok(0, "Last error: %08x\n", GetLastError());
118     ok(0, "Returned: %d\n", ret);
119 
120     SetLastError(0xcafebabe);
121     recips = BSM_APPLICATIONS;
122     ret = broadcast( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 );
123     ok(0, "Last error: %08x\n", GetLastError());
124     ok(0, "Returned: %d\n", ret);
125 
126     SetLastError(0xcafebabe);
127     recips = BSM_APPLICATIONS;
128     ret = broadcast( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 );
129     ok(0, "Last error: %08x\n", GetLastError());
130     ok(0, "Returned: %d\n", ret);
131 }
132 
133     recips = BSM_APPLICATIONS;
134     ResetEvent(hevent);
135     ret = broadcast( BSF_POSTMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, 0 );
136     ok(ret==1, "Returned: %d\n", ret);
137     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
138     PulseEvent(hevent);
139 
140     SetLastError( 0xdeadbeef );
141     recips = BSM_APPLICATIONS;
142     ret = broadcast( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0 );
143     if (ret)
144     {
145         ok(ret==1, "Returned: %d\n", ret);
146         ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
147         PulseEvent(hevent);
148 
149         recips = BSM_APPLICATIONS;
150         ret = broadcast( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
151         ok(ret==1, "Returned: %d\n", ret);
152         ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
153         PulseEvent(hevent);
154 
155         recips = BSM_APPLICATIONS;
156         ret = broadcast( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
157         ok(!ret, "Returned: %d\n", ret);
158         ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
159         PulseEvent(hevent);
160     }
161     else  /* BSF_SENDNOTIFYMESSAGE not supported on NT4 */
162         ok( GetLastError() == ERROR_INVALID_PARAMETER, "failed with err %u\n", GetLastError() );
163 
164     recips = BSM_APPLICATIONS;
165     ret = broadcast( 0, &recips, WM_NULL, 100, 0 );
166     ok(ret==1, "Returned: %d\n", ret);
167     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
168     PulseEvent(hevent);
169 }
170 
171 /* BSF_SENDNOTIFYMESSAGE and BSF_QUERY are both synchronous within the same process
172  * However you should be able to distinguish them by sending the BROADCAST_QUERY_DENY flag
173  */
174 
175 static void test_parametersEx(PBROADCASTEX broadcastex)
176 {
177     LONG ret;
178     DWORD recips;
179 
180     SetLastError(0xcafebabe);
181     recips = BSM_APPLICATIONS;
182     ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL );
183     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
184     ok(!ret, "Returned: %d\n", ret);
185 
186     SetLastError(0xcafebabe);
187     recips = BSM_APPLICATIONS;
188     ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL );
189     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
190     ok(!ret, "Returned: %d\n", ret);
191 
192 if (0) /* TODO: Check the hang flags */
193 {
194     SetLastError(0xcafebabe);
195     recips = BSM_APPLICATIONS;
196     ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
197     ok(0, "Last error: %08x\n", GetLastError());
198     ok(0, "Returned: %d\n", ret);
199 
200     SetLastError(0xcafebabe);
201     recips = BSM_APPLICATIONS;
202     ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0, NULL );
203     ok(0, "Last error: %08x\n", GetLastError());
204     ok(0, "Returned: %d\n", ret);
205 
206     SetLastError(0xcafebabe);
207     recips = BSM_APPLICATIONS;
208     ret = broadcastex( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
209     ok(0, "Last error: %08x\n", GetLastError());
210     ok(0, "Returned: %d\n", ret);
211 
212     SetLastError(0xcafebabe);
213     recips = BSM_APPLICATIONS;
214     ret = broadcastex( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
215     ok(0, "Last error: %08x\n", GetLastError());
216     ok(0, "Returned: %d\n", ret);
217 }
218 
219     recips = BSM_APPLICATIONS;
220     ResetEvent(hevent);
221     ret = broadcastex( BSF_POSTMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, 0, NULL );
222     ok(ret==1, "Returned: %d\n", ret);
223     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
224     PulseEvent(hevent);
225 
226     recips = BSM_APPLICATIONS;
227     ret = broadcastex( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0, NULL );
228     ok(ret==1, "Returned: %d\n", ret);
229     ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
230     PulseEvent(hevent);
231 
232     recips = BSM_APPLICATIONS;
233     ret = broadcastex( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL );
234     ok(ret==1, "Returned: %d\n", ret);
235     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
236     PulseEvent(hevent);
237 
238     recips = BSM_APPLICATIONS;
239     ret = broadcastex( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL );
240     ok(!ret, "Returned: %d\n", ret);
241     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
242     PulseEvent(hevent);
243 
244     recips = BSM_APPLICATIONS;
245     ret = broadcastex( 0, &recips, WM_NULL, 100, 0, NULL );
246     ok(ret==1, "Returned: %d\n", ret);
247     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
248     PulseEvent(hevent);
249 }
250 
251 static void test_noprivileges(void)
252 {
253     HANDLE token;
254     DWORD recips;
255     BOOL ret;
256 
257     static const DWORD BSM_ALL_RECIPS = BSM_VXDS | BSM_NETDRIVER |
258                                         BSM_INSTALLABLEDRIVERS | BSM_APPLICATIONS;
259 
260     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
261     {
262         skip("Can't open security token for process\n");
263         return;
264     }
265     if (!AdjustTokenPrivileges(token, TRUE, NULL, 0, NULL, NULL))
266     {
267         skip("Can't adjust security token for process\n");
268         return;
269     }
270 
271     trace("Trying privileged edition!\n");
272     SetLastError(0xcafebabe);
273     recips = BSM_ALLDESKTOPS;
274     ResetEvent(hevent);
275     ret = BroadcastSystemMessageExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL );
276     ok(ret==1, "Returned: %d error %u\n", ret, GetLastError());
277     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
278     ok(recips == BSM_ALLDESKTOPS ||
279        recips == BSM_ALL_RECIPS, /* win2k3 */
280        "Received by: %08x\n", recips);
281     PulseEvent(hevent);
282 
283     SetLastError(0xcafebabe);
284     recips = BSM_ALLCOMPONENTS;
285     ResetEvent(hevent);
286     ret = BroadcastSystemMessageExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL );
287     ok(ret==1, "Returned: %d error %u\n", ret, GetLastError());
288     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
289     ok(recips == BSM_ALLCOMPONENTS ||
290        recips == BSM_ALL_RECIPS, /* win2k3 */
291        "Received by: %08x\n", recips);
292     PulseEvent(hevent);
293 
294     SetLastError(0xcafebabe);
295     recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS;
296     ResetEvent(hevent);
297     ret = BroadcastSystemMessageExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL );
298     ok(ret==1, "Returned: %d error %u\n", ret, GetLastError());
299     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
300     ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS) ||
301        recips == BSM_APPLICATIONS, /* win2k3 */
302        "Received by: %08x\n", recips);
303     PulseEvent(hevent);
304 
305     SetLastError(0xcafebabe);
306     recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS;
307     ResetEvent(hevent);
308     ret = BroadcastSystemMessageExW( BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL );
309     ok(!ret, "Returned: %d\n", ret);
310     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
311     ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS) ||
312        recips == BSM_APPLICATIONS, /* win2k3 */
313        "Received by: %08x\n", recips);
314     PulseEvent(hevent);
315 }
316 
317 START_TEST(broadcast)
318 {
319     if (!init_procs())
320         return;
321 
322     trace("Running BroadcastSystemMessageA tests\n");
323     test_parameters(BroadcastSystemMessageA, "BroadcastSystemMessageA");
324 
325     trace("Running BroadcastSystemMessageW tests\n");
326     test_parameters(BroadcastSystemMessageW, "BroadcastSystemMessageW");
327 
328     trace("Running BroadcastSystemMessageExA tests\n");
329     test_parametersEx(BroadcastSystemMessageExA);
330 
331     trace("Running BroadcastSystemMessageExW tests\n");
332     test_parametersEx(BroadcastSystemMessageExW);
333 
334     trace("Attempting privileges checking tests\n");
335     test_noprivileges();
336 }
337