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 #include "precomp.h"
22 
23 typedef LONG (WINAPI *PBROADCAST)( DWORD,LPDWORD,UINT,WPARAM,LPARAM );
24 typedef LONG (WINAPI *PBROADCASTEX)( DWORD,LPDWORD,UINT,WPARAM,LPARAM,PBSMINFO );
25 static PBROADCAST pBroadcastA;
26 static PBROADCAST pBroadcastW;
27 static PBROADCASTEX pBroadcastExA;
28 static PBROADCASTEX pBroadcastExW;
29 static HANDLE hevent;
30 
31 static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
32 {
33     if (msg == WM_NULL)
34     {
35         trace("main_window_procA: Sleeping for %lu ms\n", wparam);
36         if (wparam)
37         {
38             if (WaitForSingleObject(hevent, wparam) == WAIT_TIMEOUT)
39                 SetEvent(hevent);
40         }
41         trace("main_window_procA: Returning WM_NULL with parameter %08lx\n", lparam);
42         return lparam;
43     }
44 
45     return DefWindowProcA(hwnd, msg, wparam, lparam);
46 }
47 
48 static BOOL init_procs(void)
49 {
50     WNDCLASSA cls;
51     HANDLE user32 = GetModuleHandleA("user32.dll");
52     pBroadcastA = (PBROADCAST)GetProcAddress(user32, "BroadcastSystemMessageA");
53     if (!pBroadcastA)
54         pBroadcastA = (PBROADCAST)GetProcAddress(user32, "BroadcastSystemMessage");
55     ok(pBroadcastA != NULL, "No BroadcastSystemMessage found\n");
56     if (!pBroadcastA)
57     {
58         win_skip("BroadcastA is not available\n");
59         return FALSE;
60     }
61 
62     pBroadcastW = (PBROADCAST)GetProcAddress(user32, "BroadcastSystemMessageW");
63     pBroadcastExA = (PBROADCASTEX)GetProcAddress(user32, "BroadcastSystemMessageExA");
64     pBroadcastExW = (PBROADCASTEX)GetProcAddress(user32, "BroadcastSystemMessageExW");
65 
66     hevent = CreateEventA(NULL, TRUE, FALSE, "Asynchronous checking event");
67 
68     cls.style = CS_DBLCLKS;
69     cls.lpfnWndProc = main_window_procA;
70     cls.cbClsExtra = 0;
71     cls.cbWndExtra = 0;
72     cls.hInstance = GetModuleHandleA(0);
73     cls.hIcon = 0;
74     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
75     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
76     cls.lpszMenuName = NULL;
77     cls.lpszClassName = "MainWindowClass";
78 
79     if (!RegisterClassA(&cls))
80         return FALSE;
81 
82     if (!CreateWindowExA(0, "MainWindowClass", "Main window", WS_CAPTION | WS_SYSMENU |
83                                WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP, 100, 100, 200,
84                                200, 0, 0, GetModuleHandleA(NULL), NULL))
85         return FALSE;
86     return TRUE;
87 }
88 
89 static void test_parameters(PBROADCAST broadcast, const char *functionname)
90 {
91     LONG ret;
92     DWORD recips;
93 
94     SetLastError(0xcafebabe);
95     recips = BSM_APPLICATIONS;
96     ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 );
97     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
98     {
99         win_skip("%s is not implemented\n", functionname);
100         return;
101     }
102     ok(!ret || broken(ret), "Returned: %d\n", ret);
103     if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
104 
105     SetLastError(0xcafebabe);
106     recips = BSM_APPLICATIONS;
107     ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 );
108     ok(!ret || broken(ret), "Returned: %d\n", ret);
109     if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
110 
111 if (0) /* TODO: Check the hang flags */
112 {
113     SetLastError(0xcafebabe);
114     recips = BSM_APPLICATIONS;
115     ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 );
116     ok(0, "Last error: %08x\n", GetLastError());
117     ok(0, "Returned: %d\n", ret);
118 
119     SetLastError(0xcafebabe);
120     recips = BSM_APPLICATIONS;
121     ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0 );
122     ok(0, "Last error: %08x\n", GetLastError());
123     ok(0, "Returned: %d\n", ret);
124 
125     SetLastError(0xcafebabe);
126     recips = BSM_APPLICATIONS;
127     ret = broadcast( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 );
128     ok(0, "Last error: %08x\n", GetLastError());
129     ok(0, "Returned: %d\n", ret);
130 
131     SetLastError(0xcafebabe);
132     recips = BSM_APPLICATIONS;
133     ret = broadcast( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 );
134     ok(0, "Last error: %08x\n", GetLastError());
135     ok(0, "Returned: %d\n", ret);
136 }
137 
138     recips = BSM_APPLICATIONS;
139     ResetEvent(hevent);
140     ret = broadcast( BSF_POSTMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, 0 );
141     ok(ret==1, "Returned: %d\n", ret);
142     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
143     PulseEvent(hevent);
144 
145     SetLastError( 0xdeadbeef );
146     recips = BSM_APPLICATIONS;
147     ret = broadcast( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0 );
148     if (ret)
149     {
150         ok(ret==1, "Returned: %d\n", ret);
151         ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
152         PulseEvent(hevent);
153 
154         recips = BSM_APPLICATIONS;
155         ret = broadcast( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
156         ok(ret==1, "Returned: %d\n", ret);
157         ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
158         PulseEvent(hevent);
159 
160         recips = BSM_APPLICATIONS;
161         ret = broadcast( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
162         ok(!ret, "Returned: %d\n", ret);
163         ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
164         PulseEvent(hevent);
165     }
166     else  /* BSF_SENDNOTIFYMESSAGE not supported on NT4 */
167         ok( GetLastError() == ERROR_INVALID_PARAMETER, "failed with err %u\n", GetLastError() );
168 
169     recips = BSM_APPLICATIONS;
170     ret = broadcast( 0, &recips, WM_NULL, 100, 0 );
171     ok(ret==1, "Returned: %d\n", ret);
172     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
173     PulseEvent(hevent);
174 }
175 
176 /* BSF_SENDNOTIFYMESSAGE and BSF_QUERY are both synchronous within the same process
177  * However you should be able to distinguish them by sending the BROADCAST_QUERY_DENY flag
178  */
179 
180 static void test_parametersEx(PBROADCASTEX broadcastex)
181 {
182     LONG ret;
183     DWORD recips;
184 
185     SetLastError(0xcafebabe);
186     recips = BSM_APPLICATIONS;
187     ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL );
188     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
189     ok(!ret, "Returned: %d\n", ret);
190 
191     SetLastError(0xcafebabe);
192     recips = BSM_APPLICATIONS;
193     ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL );
194     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
195     ok(!ret, "Returned: %d\n", ret);
196 
197 if (0) /* TODO: Check the hang flags */
198 {
199     SetLastError(0xcafebabe);
200     recips = BSM_APPLICATIONS;
201     ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
202     ok(0, "Last error: %08x\n", GetLastError());
203     ok(0, "Returned: %d\n", ret);
204 
205     SetLastError(0xcafebabe);
206     recips = BSM_APPLICATIONS;
207     ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0, NULL );
208     ok(0, "Last error: %08x\n", GetLastError());
209     ok(0, "Returned: %d\n", ret);
210 
211     SetLastError(0xcafebabe);
212     recips = BSM_APPLICATIONS;
213     ret = broadcastex( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
214     ok(0, "Last error: %08x\n", GetLastError());
215     ok(0, "Returned: %d\n", ret);
216 
217     SetLastError(0xcafebabe);
218     recips = BSM_APPLICATIONS;
219     ret = broadcastex( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
220     ok(0, "Last error: %08x\n", GetLastError());
221     ok(0, "Returned: %d\n", ret);
222 }
223 
224     recips = BSM_APPLICATIONS;
225     ResetEvent(hevent);
226     ret = broadcastex( BSF_POSTMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, 0, NULL );
227     ok(ret==1, "Returned: %d\n", ret);
228     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
229     PulseEvent(hevent);
230 
231     recips = BSM_APPLICATIONS;
232     ret = broadcastex( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0, NULL );
233     ok(ret==1, "Returned: %d\n", ret);
234     ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
235     PulseEvent(hevent);
236 
237     recips = BSM_APPLICATIONS;
238     ret = broadcastex( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL );
239     ok(ret==1, "Returned: %d\n", ret);
240     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
241     PulseEvent(hevent);
242 
243     recips = BSM_APPLICATIONS;
244     ret = broadcastex( BSF_SENDNOTIFYMESSAGE|BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL );
245     ok(!ret, "Returned: %d\n", ret);
246     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
247     PulseEvent(hevent);
248 
249     recips = BSM_APPLICATIONS;
250     ret = broadcastex( 0, &recips, WM_NULL, 100, 0, NULL );
251     ok(ret==1, "Returned: %d\n", ret);
252     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
253     PulseEvent(hevent);
254 }
255 
256 static BOOL (WINAPI *pOpenProcessToken)(HANDLE, DWORD, HANDLE*);
257 static BOOL (WINAPI *pAdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD);
258 
259 static void test_noprivileges(void)
260 {
261     HANDLE advapi32 = GetModuleHandleA("advapi32");
262     HANDLE token;
263     DWORD recips;
264     BOOL ret;
265 
266     static const DWORD BSM_ALL_RECIPS = BSM_VXDS | BSM_NETDRIVER |
267                                         BSM_INSTALLABLEDRIVERS | BSM_APPLICATIONS;
268 
269     pOpenProcessToken = (void *)GetProcAddress(advapi32, "OpenProcessToken");
270     pAdjustTokenPrivileges = (void *)GetProcAddress(advapi32, "AdjustTokenPrivileges");
271     if (!pOpenProcessToken || !pAdjustTokenPrivileges || !pOpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
272     {
273         skip("Can't open security token for process\n");
274         return;
275     }
276     if (!pAdjustTokenPrivileges(token, TRUE, NULL, 0, NULL, NULL))
277     {
278         skip("Can't adjust security token for process\n");
279         return;
280     }
281 
282     trace("Trying privileged edition!\n");
283     SetLastError(0xcafebabe);
284     recips = BSM_ALLDESKTOPS;
285     ResetEvent(hevent);
286     ret = pBroadcastExW( 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_ALLDESKTOPS ||
290        recips == BSM_ALL_RECIPS, /* win2k3 */
291        "Received by: %08x\n", recips);
292     PulseEvent(hevent);
293 
294     SetLastError(0xcafebabe);
295     recips = BSM_ALLCOMPONENTS;
296     ResetEvent(hevent);
297     ret = pBroadcastExW( 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_ALLCOMPONENTS ||
301        recips == BSM_ALL_RECIPS, /* 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 = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, 0, NULL );
309     ok(ret==1, "Returned: %d error %u\n", ret, GetLastError());
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     SetLastError(0xcafebabe);
317     recips = BSM_ALLDESKTOPS|BSM_APPLICATIONS;
318     ResetEvent(hevent);
319     ret = pBroadcastExW( BSF_QUERY, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL );
320     ok(!ret, "Returned: %d\n", ret);
321     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
322     ok(recips == (BSM_ALLDESKTOPS|BSM_APPLICATIONS) ||
323        recips == BSM_APPLICATIONS, /* win2k3 */
324        "Received by: %08x\n", recips);
325     PulseEvent(hevent);
326 }
327 
328 START_TEST(broadcast)
329 {
330     if (!init_procs())
331         return;
332 
333     trace("Running BroadcastSystemMessageA tests\n");
334     test_parameters(pBroadcastA, "BroadcastSystemMessageA");
335     if (pBroadcastW)
336     {
337         trace("Running BroadcastSystemMessageW tests\n");
338         test_parameters(pBroadcastW, "BroadcastSystemMessageW");
339     }
340     else
341         win_skip("No BroadcastSystemMessageW, skipping\n");
342     if (pBroadcastExA)
343     {
344         trace("Running BroadcastSystemMessageExA tests\n");
345         test_parametersEx(pBroadcastExA);
346     }
347     else
348         win_skip("No BroadcastSystemMessageExA, skipping\n");
349     if (pBroadcastExW)
350     {
351         trace("Running BroadcastSystemMessageExW tests\n");
352         test_parametersEx(pBroadcastExW);
353         trace("Attempting privileges checking tests\n");
354         test_noprivileges();
355     }
356     else
357         win_skip("No BroadcastSystemMessageExW, skipping\n");
358 }
359