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 <stdarg.h>
22 #include <stdio.h>
23 
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 
30 #include "wine/test.h"
31 
32 typedef LONG (WINAPI *PBROADCAST)( DWORD,LPDWORD,UINT,WPARAM,LPARAM );
33 typedef LONG (WINAPI *PBROADCASTEX)( DWORD,LPDWORD,UINT,WPARAM,LPARAM,PBSMINFO );
34 static HANDLE hevent;
35 
36 static LRESULT WINAPI main_window_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
37 {
38     if (msg == WM_NULL)
39     {
40         trace("main_window_procA: Sleeping for %lu ms\n", wparam);
41         if (wparam)
42         {
43             if (WaitForSingleObject(hevent, wparam) == WAIT_TIMEOUT)
44                 SetEvent(hevent);
45         }
46         trace("main_window_procA: Returning WM_NULL with parameter %08lx\n", lparam);
47         return lparam;
48     }
49 
50     return DefWindowProcA(hwnd, msg, wparam, lparam);
51 }
52 
53 static BOOL init_procs(void)
54 {
55     WNDCLASSA cls;
56 
57     hevent = CreateEventA(NULL, TRUE, FALSE, "Asynchronous checking event");
58 
59     cls.style = CS_DBLCLKS;
60     cls.lpfnWndProc = main_window_procA;
61     cls.cbClsExtra = 0;
62     cls.cbWndExtra = 0;
63     cls.hInstance = GetModuleHandleA(0);
64     cls.hIcon = 0;
65     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
66     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
67     cls.lpszMenuName = NULL;
68     cls.lpszClassName = "MainWindowClass";
69 
70     if (!RegisterClassA(&cls))
71         return FALSE;
72 
73     if (!CreateWindowExA(0, "MainWindowClass", "Main window", WS_CAPTION | WS_SYSMENU |
74                                WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP, 100, 100, 200,
75                                200, 0, 0, GetModuleHandleA(NULL), NULL))
76         return FALSE;
77     return TRUE;
78 }
79 
80 static void test_parameters(PBROADCAST broadcast, const char *functionname)
81 {
82     LONG ret;
83     DWORD recips;
84 
85     SetLastError(0xcafebabe);
86     recips = BSM_APPLICATIONS;
87     ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 );
88     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
89     {
90         win_skip("%s is not implemented\n", functionname);
91         return;
92     }
93     ok(!ret || broken(ret), "Returned: %d\n", ret);
94     if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
95 
96     SetLastError(0xcafebabe);
97     recips = BSM_APPLICATIONS;
98     ret = broadcast( 0x80000000, &recips, WM_NULL, 0, 0 );
99     ok(!ret || broken(ret), "Returned: %d\n", ret);
100     if (!ret) ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
101 
102 if (0) /* TODO: Check the hang flags */
103 {
104     SetLastError(0xcafebabe);
105     recips = BSM_APPLICATIONS;
106     ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 );
107     ok(0, "Last error: %08x\n", GetLastError());
108     ok(0, "Returned: %d\n", ret);
109 
110     SetLastError(0xcafebabe);
111     recips = BSM_APPLICATIONS;
112     ret = broadcast( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0 );
113     ok(0, "Last error: %08x\n", GetLastError());
114     ok(0, "Returned: %d\n", ret);
115 
116     SetLastError(0xcafebabe);
117     recips = BSM_APPLICATIONS;
118     ret = broadcast( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 );
119     ok(0, "Last error: %08x\n", GetLastError());
120     ok(0, "Returned: %d\n", ret);
121 
122     SetLastError(0xcafebabe);
123     recips = BSM_APPLICATIONS;
124     ret = broadcast( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0 );
125     ok(0, "Last error: %08x\n", GetLastError());
126     ok(0, "Returned: %d\n", ret);
127 }
128 
129     SetLastError( 0xdeadbeef );
130     recips = BSM_APPLICATIONS;
131     ret = broadcast( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0 );
132     ok(ret==1, "Returned: %d\n", ret);
133     ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
134     PulseEvent(hevent);
135 
136     recips = BSM_APPLICATIONS;
137     ret = broadcast( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
138     ok(ret==1, "Returned: %d\n", ret);
139     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
140     PulseEvent(hevent);
141 }
142 
143 /* BSF_SENDNOTIFYMESSAGE and BSF_QUERY are both synchronous within the same process
144  * However you should be able to distinguish them by sending the BROADCAST_QUERY_DENY flag
145  */
146 
147 static void test_parametersEx(PBROADCASTEX broadcastex)
148 {
149     LONG ret;
150     DWORD recips;
151 
152     SetLastError(0xcafebabe);
153     recips = BSM_APPLICATIONS;
154     ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL );
155     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
156     ok(!ret, "Returned: %d\n", ret);
157 
158     SetLastError(0xcafebabe);
159     recips = BSM_APPLICATIONS;
160     ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL );
161     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
162     ok(!ret, "Returned: %d\n", ret);
163 
164 if (0) /* TODO: Check the hang flags */
165 {
166     SetLastError(0xcafebabe);
167     recips = BSM_APPLICATIONS;
168     ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
169     ok(0, "Last error: %08x\n", GetLastError());
170     ok(0, "Returned: %d\n", ret);
171 
172     SetLastError(0xcafebabe);
173     recips = BSM_APPLICATIONS;
174     ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0, NULL );
175     ok(0, "Last error: %08x\n", GetLastError());
176     ok(0, "Returned: %d\n", ret);
177 
178     SetLastError(0xcafebabe);
179     recips = BSM_APPLICATIONS;
180     ret = broadcastex( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
181     ok(0, "Last error: %08x\n", GetLastError());
182     ok(0, "Returned: %d\n", ret);
183 
184     SetLastError(0xcafebabe);
185     recips = BSM_APPLICATIONS;
186     ret = broadcastex( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
187     ok(0, "Last error: %08x\n", GetLastError());
188     ok(0, "Returned: %d\n", ret);
189 }
190 
191     recips = BSM_APPLICATIONS;
192     ret = broadcastex( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0, NULL );
193     ok(ret==1, "Returned: %d\n", ret);
194     ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
195     PulseEvent(hevent);
196 
197     recips = BSM_APPLICATIONS;
198     ret = broadcastex( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL );
199     ok(ret==1, "Returned: %d\n", ret);
200     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
201     PulseEvent(hevent);
202 }
203 
204 START_TEST(broadcast)
205 {
206     if (!init_procs())
207         return;
208 
209     trace("Running BroadcastSystemMessageA tests\n");
210     test_parameters(BroadcastSystemMessageA, "BroadcastSystemMessageA");
211 
212     trace("Running BroadcastSystemMessageW tests\n");
213     test_parameters(BroadcastSystemMessageW, "BroadcastSystemMessageW");
214 
215     trace("Running BroadcastSystemMessageExA tests\n");
216     test_parametersEx(BroadcastSystemMessageExA);
217 
218     trace("Running BroadcastSystemMessageExW tests\n");
219     test_parametersEx(BroadcastSystemMessageExW);
220 }
221