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     SetLastError( 0xdeadbeef );
134     recips = BSM_APPLICATIONS;
135     ret = broadcast( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0 );
136     ok(ret==1, "Returned: %d\n", ret);
137     ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
138     PulseEvent(hevent);
139 
140     recips = BSM_APPLICATIONS;
141     ret = broadcast( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY );
142     ok(ret==1, "Returned: %d\n", ret);
143     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
144     PulseEvent(hevent);
145 }
146 
147 /* BSF_SENDNOTIFYMESSAGE and BSF_QUERY are both synchronous within the same process
148  * However you should be able to distinguish them by sending the BROADCAST_QUERY_DENY flag
149  */
150 
151 static void test_parametersEx(PBROADCASTEX broadcastex)
152 {
153     LONG ret;
154     DWORD recips;
155 
156     SetLastError(0xcafebabe);
157     recips = BSM_APPLICATIONS;
158     ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL );
159     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
160     ok(!ret, "Returned: %d\n", ret);
161 
162     SetLastError(0xcafebabe);
163     recips = BSM_APPLICATIONS;
164     ret = broadcastex( 0x80000000, &recips, WM_NULL, 0, 0, NULL );
165     ok(GetLastError() == ERROR_INVALID_PARAMETER, "Last error: %08x\n", GetLastError());
166     ok(!ret, "Returned: %d\n", ret);
167 
168 if (0) /* TODO: Check the hang flags */
169 {
170     SetLastError(0xcafebabe);
171     recips = BSM_APPLICATIONS;
172     ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
173     ok(0, "Last error: %08x\n", GetLastError());
174     ok(0, "Returned: %d\n", ret);
175 
176     SetLastError(0xcafebabe);
177     recips = BSM_APPLICATIONS;
178     ret = broadcastex( BSF_QUERY|(BSF_NOHANG|BSF_NOTIMEOUTIFNOTHUNG), &recips, WM_NULL, 30000, 0, NULL );
179     ok(0, "Last error: %08x\n", GetLastError());
180     ok(0, "Returned: %d\n", ret);
181 
182     SetLastError(0xcafebabe);
183     recips = BSM_APPLICATIONS;
184     ret = broadcastex( BSF_QUERY|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
185     ok(0, "Last error: %08x\n", GetLastError());
186     ok(0, "Returned: %d\n", ret);
187 
188     SetLastError(0xcafebabe);
189     recips = BSM_APPLICATIONS;
190     ret = broadcastex( BSF_POSTMESSAGE|(BSF_NOTIMEOUTIFNOTHUNG|BSF_FORCEIFHUNG), &recips, WM_NULL, 30000, 0, NULL );
191     ok(0, "Last error: %08x\n", GetLastError());
192     ok(0, "Returned: %d\n", ret);
193 }
194 
195     recips = BSM_APPLICATIONS;
196     ret = broadcastex( BSF_POSTMESSAGE|BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, 0, NULL );
197     ok(ret==1, "Returned: %d\n", ret);
198     ok(WaitForSingleObject(hevent, 0) != WAIT_OBJECT_0, "Synchronous message sent instead\n");
199     PulseEvent(hevent);
200 
201     recips = BSM_APPLICATIONS;
202     ret = broadcastex( BSF_SENDNOTIFYMESSAGE, &recips, WM_NULL, 100, BROADCAST_QUERY_DENY, NULL );
203     ok(ret==1, "Returned: %d\n", ret);
204     ok(WaitForSingleObject(hevent, 0) != WAIT_TIMEOUT, "Asynchronous message sent instead\n");
205     PulseEvent(hevent);
206 }
207 
208 START_TEST(broadcast)
209 {
210     if (!init_procs())
211         return;
212 
213     trace("Running BroadcastSystemMessageA tests\n");
214     test_parameters(BroadcastSystemMessageA, "BroadcastSystemMessageA");
215 
216     trace("Running BroadcastSystemMessageW tests\n");
217     test_parameters(BroadcastSystemMessageW, "BroadcastSystemMessageW");
218 
219     trace("Running BroadcastSystemMessageExA tests\n");
220     test_parametersEx(BroadcastSystemMessageExA);
221 
222     trace("Running BroadcastSystemMessageExW tests\n");
223     test_parametersEx(BroadcastSystemMessageExW);
224 }
225