1 /* Unit tests for the syslink control.
3 * Copyright 2011 Francois Gouget for CodeWeavers
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.
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.
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
22 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
23 #define NUM_MSG_SEQUENCE 2
24 #define PARENT_SEQ_INDEX 0
25 #define SYSLINK_SEQ_INDEX 1
27 static HWND hWndParent
;
29 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCE
];
31 static const struct message empty_wnd_seq
[] = {
35 static const struct message parent_create_syslink_wnd_seq
[] = {
36 { WM_GETFONT
, sent
|optional
}, /* Only on XP */
37 { WM_QUERYUISTATE
, sent
|optional
},
38 { WM_CTLCOLORSTATIC
, sent
},
39 { WM_NOTIFY
, sent
|wparam
, 0},
40 { WM_PARENTNOTIFY
, sent
|wparam
, WM_CREATE
},
44 static const struct message visible_syslink_wnd_seq
[] = {
45 { WM_STYLECHANGING
, sent
|wparam
, GWL_STYLE
},
46 { WM_STYLECHANGED
, sent
|wparam
, GWL_STYLE
},
51 static const struct message parent_visible_syslink_wnd_seq
[] = {
52 { WM_CTLCOLORSTATIC
, sent
},
53 { WM_NOTIFY
, sent
|wparam
, 0},
57 /* Try to make sure pending X events have been processed before continuing */
58 static void flush_events(void)
62 int min_timeout
= 100;
63 DWORD time
= GetTickCount() + diff
;
67 if (MsgWaitForMultipleObjects( 0, NULL
, FALSE
, min_timeout
, QS_ALLINPUT
) == WAIT_TIMEOUT
) break;
68 while (PeekMessageA( &msg
, 0, 0, 0, PM_REMOVE
)) DispatchMessageA( &msg
);
69 diff
= time
- GetTickCount();
73 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
75 static LONG defwndproc_counter
= 0;
79 /* log system messages, except for painting */
80 if (message
< WM_USER
&&
81 message
!= WM_PAINT
&&
82 message
!= WM_ERASEBKGND
&&
83 message
!= WM_NCPAINT
&&
84 message
!= WM_NCHITTEST
&&
85 message
!= WM_GETTEXT
&&
86 message
!= WM_GETICON
&&
87 message
!= WM_DEVICECHANGE
)
89 msg
.message
= message
;
90 msg
.flags
= sent
|wparam
|lparam
;
91 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
94 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
98 ret
= DefWindowProcW(hwnd
, message
, wParam
, lParam
);
104 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};
106 static BOOL
register_parent_wnd_class(void)
111 cls
.lpfnWndProc
= parent_wnd_proc
;
114 cls
.hInstance
= GetModuleHandleW(NULL
);
116 cls
.hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
117 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
118 cls
.lpszMenuName
= NULL
;
119 cls
.lpszClassName
= parentClassW
;
120 return RegisterClassW(&cls
);
123 static HWND
create_parent_window(void)
125 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};
126 if (!register_parent_wnd_class())
129 return CreateWindowExW(0, parentClassW
, titleW
,
130 WS_CAPTION
| WS_SYSMENU
| WS_MINIMIZEBOX
|
131 WS_MAXIMIZEBOX
| WS_VISIBLE
,
132 0, 0, 200, 100, GetDesktopWindow(),
133 NULL
, GetModuleHandleW(NULL
), NULL
);
136 static WNDPROC syslink_oldproc
;
138 static LRESULT WINAPI
syslink_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
140 static LONG defwndproc_counter
= 0;
141 struct message msg
= { 0 };
144 msg
.message
= message
;
145 msg
.flags
= sent
|wparam
|lparam
;
146 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
149 add_message(sequences
, SYSLINK_SEQ_INDEX
, &msg
);
151 defwndproc_counter
++;
152 ret
= CallWindowProcW(syslink_oldproc
, hwnd
, message
, wParam
, lParam
);
153 defwndproc_counter
--;
158 static HWND
create_syslink(DWORD style
, HWND parent
)
161 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};
163 /* Only Unicode will do here */
164 hWndSysLink
= CreateWindowExW(0, WC_LINK
, linkW
,
165 style
, 0, 0, 150, 50,
166 parent
, NULL
, GetModuleHandleW(NULL
), NULL
);
167 if (!hWndSysLink
) return NULL
;
169 if (GetWindowLongPtrW(hWndSysLink
, GWLP_USERDATA
))
170 /* On Windows XP SysLink takes GWLP_USERDATA for itself! */
171 trace("SysLink makes use of GWLP_USERDATA\n");
173 syslink_oldproc
= (WNDPROC
)SetWindowLongPtrW(hWndSysLink
, GWLP_WNDPROC
, (LONG_PTR
)syslink_subclass_proc
);
178 static void test_create_syslink(void)
183 /* Create an invisible SysLink control */
184 flush_sequences(sequences
, NUM_MSG_SEQUENCE
);
185 hWndSysLink
= create_syslink(WS_CHILD
| WS_TABSTOP
, hWndParent
);
186 ok(hWndSysLink
!= NULL
, "Expected non NULL value (le %u)\n", GetLastError());
188 ok_sequence(sequences
, SYSLINK_SEQ_INDEX
, empty_wnd_seq
, "create SysLink", FALSE
);
189 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_create_syslink_wnd_seq
, "create SysLink (parent)", TRUE
);
191 /* Make the SysLink control visible */
192 flush_sequences(sequences
, NUM_MSG_SEQUENCE
);
193 oldstyle
= GetWindowLongA(hWndSysLink
, GWL_STYLE
);
194 SetWindowLongA(hWndSysLink
, GWL_STYLE
, oldstyle
| WS_VISIBLE
);
195 RedrawWindow(hWndSysLink
, NULL
, NULL
, RDW_INVALIDATE
);
197 ok_sequence(sequences
, SYSLINK_SEQ_INDEX
, visible_syslink_wnd_seq
, "visible SysLink", TRUE
);
198 ok_sequence(sequences
, PARENT_SEQ_INDEX
, parent_visible_syslink_wnd_seq
, "visible SysLink (parent)", TRUE
);
200 DestroyWindow(hWndSysLink
);
203 static void test_LM_GETIDEALHEIGHT(void)
208 hwnd
= create_syslink(WS_CHILD
| WS_TABSTOP
| WS_VISIBLE
, hWndParent
);
209 ok(hwnd
!= NULL
, "Failed to create SysLink window.\n");
211 ret
= SendMessageA(hwnd
, LM_GETIDEALHEIGHT
, 0, 0);
212 ok(ret
> 0, "Unexpected ideal height, %d.\n", ret
);
217 static void test_LM_GETIDEALSIZE(void)
223 hwnd
= create_syslink(WS_CHILD
| WS_TABSTOP
| WS_VISIBLE
, hWndParent
);
224 ok(hwnd
!= NULL
, "Failed to create SysLink window.\n");
226 memset(&sz
, 0, sizeof(sz
));
227 ret
= SendMessageA(hwnd
, LM_GETIDEALSIZE
, 0, (LPARAM
)&sz
);
228 ok(ret
> 0, "Unexpected return value, %d.\n", ret
);
230 win_skip("LM_GETIDEALSIZE is not supported.\n");
233 ok(sz
.cx
> 5, "Unexpected ideal width, %d.\n", sz
.cx
);
234 ok(sz
.cy
== ret
, "Unexpected ideal height, %d.\n", sz
.cy
);
242 ULONG_PTR ctx_cookie
;
247 if (!load_v6_module(&ctx_cookie
, &hCtx
))
250 /* LoadLibrary is needed. This file has no reference to functions in comctl32 */
251 hComctl32
= LoadLibraryA("comctl32.dll");
252 ok(hComctl32
!= NULL
, "Failed to load comctl32.dll.\n");
254 /* Move the cursor off the parent window */
255 GetCursorPos(&orig_pos
);
256 SetCursorPos(400, 400);
258 init_msg_sequences(sequences
, NUM_MSG_SEQUENCE
);
260 /* Create parent window */
261 hWndParent
= create_parent_window();
262 ok(hWndParent
!= NULL
, "Failed to create parent Window!\n");
265 test_create_syslink();
266 test_LM_GETIDEALHEIGHT();
267 test_LM_GETIDEALSIZE();
269 DestroyWindow(hWndParent
);
270 unload_v6_module(ctx_cookie
, hCtx
);
271 SetCursorPos(orig_pos
.x
, orig_pos
.y
);