0e523b9b080df549db1ec8d5b44b4d8162e0e9fb
[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 LRESULT ret;
150 struct message msg;
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 msg.id = 0;
158 add_message(sequences, SYSLINK_SEQ_INDEX, &msg);
159
160 defwndproc_counter++;
161 ret = CallWindowProcW(syslink_oldproc, hwnd, message, wParam, lParam);
162 defwndproc_counter--;
163
164 return ret;
165 }
166
167 static HWND create_syslink(DWORD style, HWND parent)
168 {
169 HWND hWndSysLink;
170 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};
171
172 /* Only Unicode will do here */
173 hWndSysLink = CreateWindowExW(0, WC_LINK, linkW,
174 style, 0, 0, 150, 50,
175 parent, NULL, GetModuleHandleW(NULL), NULL);
176 if (!hWndSysLink) return NULL;
177
178 if (GetWindowLongPtrW(hWndSysLink, GWLP_USERDATA))
179 /* On Windows XP SysLink takes GWLP_USERDATA for itself! */
180 trace("SysLink makes use of GWLP_USERDATA\n");
181
182 syslink_oldproc = (WNDPROC)SetWindowLongPtrW(hWndSysLink, GWLP_WNDPROC, (LONG_PTR)syslink_subclass_proc);
183
184 return hWndSysLink;
185 }
186
187
188 START_TEST(syslink)
189 {
190 ULONG_PTR ctx_cookie;
191 HANDLE hCtx;
192 HMODULE hComctl32;
193 BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
194 INITCOMMONCONTROLSEX iccex;
195 BOOL rc;
196 HWND hWndSysLink;
197 LONG oldstyle;
198 POINT orig_pos;
199
200 if (!load_v6_module(&ctx_cookie, &hCtx))
201 return;
202
203 /* LoadLibrary is needed. This file has no reference to functions in comctl32 */
204 hComctl32 = LoadLibraryA("comctl32.dll");
205 pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
206 if (!pInitCommonControlsEx)
207 {
208 win_skip("InitCommonControlsEx() is missing. Skipping the tests\n");
209 return;
210 }
211 iccex.dwSize = sizeof(iccex);
212 iccex.dwICC = ICC_LINK_CLASS;
213 rc = pInitCommonControlsEx(&iccex);
214 ok(rc, "InitCommonControlsEx failed (le %u)\n", GetLastError());
215 if (!rc)
216 {
217 skip("Could not register ICC_LINK_CLASS\n");
218 return;
219 }
220
221 /* Move the cursor off the parent window */
222 GetCursorPos(&orig_pos);
223 SetCursorPos(400, 400);
224
225 init_msg_sequences(sequences, NUM_MSG_SEQUENCE);
226
227 /* Create parent window */
228 hWndParent = create_parent_window();
229 ok(hWndParent != NULL, "Failed to create parent Window!\n");
230 if (!hWndParent)
231 {
232 skip("Parent window not present\n");
233 return;
234 }
235 flush_events();
236
237 /* Create an invisible SysLink control */
238 flush_sequences(sequences, NUM_MSG_SEQUENCE);
239 hWndSysLink = create_syslink(WS_CHILD | WS_TABSTOP, hWndParent);
240 ok(hWndSysLink != NULL, "Expected non NULL value (le %u)\n", GetLastError());
241 if (!hWndSysLink)
242 {
243 skip("SysLink control not present?\n");
244 return;
245 }
246 flush_events();
247 ok_sequence(sequences, SYSLINK_SEQ_INDEX, empty_wnd_seq, "create SysLink", FALSE);
248 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_create_syslink_wnd_seq, "create SysLink (parent)", TRUE);
249
250 /* Make the SysLink control visible */
251 flush_sequences(sequences, NUM_MSG_SEQUENCE);
252 oldstyle = GetWindowLongA(hWndSysLink, GWL_STYLE);
253 SetWindowLongA(hWndSysLink, GWL_STYLE, oldstyle | WS_VISIBLE);
254 RedrawWindow(hWndSysLink, NULL, NULL, RDW_INVALIDATE);
255 flush_events();
256 ok_sequence(sequences, SYSLINK_SEQ_INDEX, visible_syslink_wnd_seq, "visible SysLink", TRUE);
257 ok_sequence(sequences, PARENT_SEQ_INDEX, parent_visible_syslink_wnd_seq, "visible SysLink (parent)", TRUE);
258
259 DestroyWindow(hWndSysLink);
260 DestroyWindow(hWndParent);
261 unload_v6_module(ctx_cookie, hCtx);
262 SetCursorPos(orig_pos.x, orig_pos.y);
263 }