[COMCTL32_WINETEST] Sync with Wine Staging 2.9. CORE-13362
[reactos.git] / rostests / winetests / comctl32 / syslink.c
1 /* Unit tests for the syslink control.
2 *
3 * Copyright 2011 Francois Gouget for CodeWeavers
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include <wine/test.h>
21
22 //#include <windows.h>
23 #include <wingdi.h>
24 #include <winuser.h>
25 #include <commctrl.h>
26
27 #include "v6util.h"
28 #include "msg.h"
29
30 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
31 #define NUM_MSG_SEQUENCE 2
32 #define PARENT_SEQ_INDEX 0
33 #define SYSLINK_SEQ_INDEX 1
34
35 static HWND hWndParent;
36
37 static struct msg_sequence *sequences[NUM_MSG_SEQUENCE];
38
39 static const struct message empty_wnd_seq[] = {
40 {0}
41 };
42
43 static const struct message parent_create_syslink_wnd_seq[] = {
44 { WM_GETFONT, sent|optional}, /* Only on XP */
45 { WM_QUERYUISTATE, sent|optional},
46 { WM_CTLCOLORSTATIC, sent},
47 { WM_NOTIFY, sent|wparam, 0},
48 { WM_PARENTNOTIFY, sent|wparam, WM_CREATE},
49 {0}
50 };
51
52 static const struct message visible_syslink_wnd_seq[] = {
53 { WM_STYLECHANGING, sent|wparam, GWL_STYLE},
54 { WM_STYLECHANGED, sent|wparam, GWL_STYLE},
55 { WM_PAINT, sent},
56 {0}
57 };
58
59 static const struct message parent_visible_syslink_wnd_seq[] = {
60 { WM_CTLCOLORSTATIC, sent},
61 { WM_NOTIFY, sent|wparam, 0},
62 {0}
63 };
64
65 /* Try to make sure pending X events have been processed before continuing */
66 static void flush_events(void)
67 {
68 MSG msg;
69 int diff = 200;
70 int min_timeout = 100;
71 DWORD time = GetTickCount() + diff;
72
73 while (diff > 0)
74 {
75 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
76 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
77 diff = time - GetTickCount();
78 }
79 }
80
81 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
82 {
83 static LONG defwndproc_counter = 0;
84 LRESULT ret;
85 struct message msg;
86
87 /* log system messages, except for painting */
88 if (message < WM_USER &&
89 message != WM_PAINT &&
90 message != WM_ERASEBKGND &&
91 message != WM_NCPAINT &&
92 message != WM_NCHITTEST &&
93 message != WM_GETTEXT &&
94 message != WM_GETICON &&
95 message != WM_DEVICECHANGE)
96 {
97 msg.message = message;
98 msg.flags = sent|wparam|lparam;
99 if (defwndproc_counter) msg.flags |= defwinproc;
100 msg.wParam = wParam;
101 msg.lParam = lParam;
102 add_message(sequences, PARENT_SEQ_INDEX, &msg);
103 }
104
105 defwndproc_counter++;
106 ret = DefWindowProcW(hwnd, message, wParam, lParam);
107 defwndproc_counter--;
108
109 return ret;
110 }
111
112 static const WCHAR parentClassW[] = {'S','y','s','l','i','n','k',' ','t','e','s','t',' ','p','a','r','e','n','t',' ','c','l','a','s','s',0};
113
114 static BOOL register_parent_wnd_class(void)
115 {
116 WNDCLASSW cls;
117
118 cls.style = 0;
119 cls.lpfnWndProc = parent_wnd_proc;
120 cls.cbClsExtra = 0;
121 cls.cbWndExtra = 0;
122 cls.hInstance = GetModuleHandleW(NULL);
123 cls.hIcon = 0;
124 cls.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
125 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
126 cls.lpszMenuName = NULL;
127 cls.lpszClassName = parentClassW;
128 return RegisterClassW(&cls);
129 }
130
131 static HWND create_parent_window(void)
132 {
133 static const WCHAR titleW[] = {'S','y','s','l','i','n','k',' ','t','e','s','t',' ','p','a','r','e','n','t',' ','w','i','n','d','o','w',0};
134 if (!register_parent_wnd_class())
135 return NULL;
136
137 return CreateWindowExW(0, parentClassW, titleW,
138 WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
139 WS_MAXIMIZEBOX | WS_VISIBLE,
140 0, 0, 200, 100, GetDesktopWindow(),
141 NULL, GetModuleHandleW(NULL), NULL);
142 }
143
144 static WNDPROC syslink_oldproc;
145
146 static LRESULT WINAPI syslink_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
147 {
148 static LONG defwndproc_counter = 0;
149 struct message msg = { 0 };
150 LRESULT ret;
151
152 msg.message = message;
153 msg.flags = sent|wparam|lparam;
154 if (defwndproc_counter) msg.flags |= defwinproc;
155 msg.wParam = wParam;
156 msg.lParam = lParam;
157 add_message(sequences, SYSLINK_SEQ_INDEX, &msg);
158
159 defwndproc_counter++;
160 ret = CallWindowProcW(syslink_oldproc, hwnd, message, wParam, lParam);
161 defwndproc_counter--;
162
163 return ret;
164 }
165
166 static HWND create_syslink(DWORD style, HWND parent)
167 {
168 HWND hWndSysLink;
169 static const WCHAR linkW[] = {'H','e','a','d',' ','<','a',' ','h','r','e','f','=','"','l','i','n','k','1','"','>','N','a','m','e','1','<','/','a','>',' ','M','i','d','d','l','e',' ','<','a',' ','h','r','e','f','=','"','l','i','n','k','2','"','>','N','a','m','e','2','<','/','a','>',' ','T','a','i','l',0};
170
171 /* Only Unicode will do here */
172 hWndSysLink = CreateWindowExW(0, WC_LINK, linkW,
173 style, 0, 0, 150, 50,
174 parent, NULL, GetModuleHandleW(NULL), NULL);
175 if (!hWndSysLink) return NULL;
176
177 if (GetWindowLongPtrW(hWndSysLink, GWLP_USERDATA))
178 /* On Windows XP SysLink takes GWLP_USERDATA for itself! */
179 trace("SysLink makes use of GWLP_USERDATA\n");
180
181 syslink_oldproc = (WNDPROC)SetWindowLongPtrW(hWndSysLink, GWLP_WNDPROC, (LONG_PTR)syslink_subclass_proc);
182
183 return hWndSysLink;
184 }
185
186
187 START_TEST(syslink)
188 {
189 ULONG_PTR ctx_cookie;
190 HANDLE hCtx;
191 HMODULE hComctl32;
192 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
193 INITCOMMONCONTROLSEX iccex;
194 BOOL rc;
195 HWND hWndSysLink;
196 LONG oldstyle;
197 POINT orig_pos;
198
199 if (!load_v6_module(&ctx_cookie, &hCtx))
200 return;
201
202 /* LoadLibrary is needed. This file has no reference to functions in comctl32 */
203 hComctl32 = LoadLibraryA("comctl32.dll");
204 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
205 if (!pInitCommonControlsEx)
206 {
207 win_skip("InitCommonControlsEx() is missing. Skipping the tests\n");
208 return;
209 }
210 iccex.dwSize = sizeof(iccex);
211 iccex.dwICC = ICC_LINK_CLASS;
212 rc = pInitCommonControlsEx(&iccex);
213 ok(rc, "InitCommonControlsEx failed (le %u)\n", GetLastError());
214 if (!rc)
215 {
216 skip("Could not register ICC_LINK_CLASS\n");
217 return;
218 }
219
220 /* Move the cursor off the parent window */
221 GetCursorPos(&orig_pos);
222 SetCursorPos(400, 400);
223
224 init_msg_sequences(sequences, NUM_MSG_SEQUENCE);
225
226 /* Create parent window */
227 hWndParent = create_parent_window();
228 ok(hWndParent != NULL, "Failed to create parent Window!\n");
229 if (!hWndParent)
230 {
231 skip("Parent window not present\n");
232 return;
233 }
234 flush_events();
235
236 /* Create an invisible SysLink control */
237 flush_sequences(sequences, NUM_MSG_SEQUENCE);
238 hWndSysLink = create_syslink(WS_CHILD | WS_TABSTOP, hWndParent);
239 ok(hWndSysLink != NULL, "Expected non NULL value (le %u)\n", GetLastError());
240 if (!hWndSysLink)
241 {
242 skip("SysLink control not present?\n");
243 return;
244 }
245 flush_events();
246 ok_sequence(sequences, SYSLINK_SEQ_INDEX, empty_wnd_seq, "create SysLink", FALSE);
247 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_create_syslink_wnd_seq, "create SysLink (parent)", TRUE);
248
249 /* Make the SysLink control visible */
250 flush_sequences(sequences, NUM_MSG_SEQUENCE);
251 oldstyle = GetWindowLongA(hWndSysLink, GWL_STYLE);
252 SetWindowLongA(hWndSysLink, GWL_STYLE, oldstyle | WS_VISIBLE);
253 RedrawWindow(hWndSysLink, NULL, NULL, RDW_INVALIDATE);
254 flush_events();
255 ok_sequence(sequences, SYSLINK_SEQ_INDEX, visible_syslink_wnd_seq, "visible SysLink", TRUE);
256 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_visible_syslink_wnd_seq, "visible SysLink (parent)", TRUE);
257
258 DestroyWindow(hWndSysLink);
259 DestroyWindow(hWndParent);
260 unload_v6_module(ctx_cookie, hCtx);
261 SetCursorPos(orig_pos.x, orig_pos.y);
262 }