2 * Unit tests for the pager control
4 * Copyright 2012 Alexandre Julliard
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.
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.
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
24 #include "wine/test.h"
27 #define NUM_MSG_SEQUENCES 1
28 #define PAGER_SEQ_INDEX 0
30 static HWND parent_wnd
, child1_wnd
, child2_wnd
;
31 static INT notify_format
;
32 static BOOL notify_query_received
;
33 static const CHAR test_a
[] = "test";
34 static const WCHAR test_w
[] = L
"test";
35 /* Double zero so that it's safe to cast it to WCHAR * */
36 static const CHAR te_a
[] = {'t', 'e', 0, 0};
37 static const CHAR large_a
[] =
38 "You should have received a copy of the GNU Lesser General Public License along with this ...";
39 static const WCHAR large_w
[] =
40 L
"You should have received a copy of the GNU Lesser General Public License along with this ...";
41 static const WCHAR large_truncated_65_w
[65] =
42 L
"You should have received a copy of the GNU Lesser General Public";
43 static const WCHAR large_truncated_80_w
[80] =
44 L
"You should have received a copy of the GNU Lesser General Public License along w";
45 static WCHAR buffer
[64];
47 /* Text field conversion test behavior flags. */
48 enum test_conversion_flags
51 DONT_CONVERT_SEND
= 0x02,
52 CONVERT_RECEIVE
= 0x04,
53 DONT_CONVERT_RECEIVE
= 0x08,
54 SEND_EMPTY_IF_NULL
= 0x10,
55 DONT_SEND_EMPTY_IF_NULL
= 0x20,
56 SET_NULL_IF_NO_MASK
= 0x40,
66 static struct notify_test_info
72 /* Whether parent received notification */
77 /* Text field conversion test behavior flag */
81 struct notify_test_send
83 /* Data sent to pager */
84 const WCHAR
*send_text
;
87 /* Data expected by parent of pager */
88 const void *expect_text
;
91 struct notify_test_receive
93 /* Data sent to pager */
94 const WCHAR
*send_text
;
97 /* Data for parent to write */
98 const CHAR
*write_pointer
;
99 const CHAR
*write_text
;
102 /* Data when message returned */
103 const void *return_text
;
107 struct generic_text_helper_para
121 static const struct notify_test_send test_convert_send_data
[] =
123 {test_w
, sizeof(test_w
), ARRAY_SIZE(buffer
), test_a
}
126 static const struct notify_test_send test_dont_convert_send_data
[] =
128 {test_w
, sizeof(test_w
), ARRAY_SIZE(buffer
), test_w
}
131 static const struct notify_test_receive test_convert_receive_data
[] =
133 {L
"", sizeof(L
""), ARRAY_SIZE(buffer
), NULL
, test_a
, sizeof(test_a
), -1, test_w
, ARRAY_SIZE(buffer
)},
134 {L
"", sizeof(L
""), ARRAY_SIZE(buffer
), test_a
, NULL
, 0, -1, test_w
, ARRAY_SIZE(buffer
)},
135 {NULL
, sizeof(L
""), ARRAY_SIZE(buffer
), test_a
, NULL
, 0, -1, NULL
, ARRAY_SIZE(buffer
)},
136 {L
"", sizeof(L
""), ARRAY_SIZE(buffer
), large_a
, NULL
, 0, -1, large_truncated_65_w
, ARRAY_SIZE(buffer
)},
137 {L
"", sizeof(L
""), ARRAY_SIZE(buffer
), "", 0, 0, 1, L
"", 1},
140 static const struct notify_test_receive test_dont_convert_receive_data
[] =
142 {L
"", sizeof(L
""), ARRAY_SIZE(buffer
), NULL
, test_a
, sizeof(test_a
), -1, test_a
, ARRAY_SIZE(buffer
)},
143 {L
"", sizeof(L
""), ARRAY_SIZE(buffer
), test_a
, NULL
, 0, -1, test_a
, ARRAY_SIZE(buffer
)},
146 static const struct notify_test_tooltip
148 /* Data for parent to write */
149 const CHAR
*write_sztext
;
150 INT write_sztext_size
;
151 const CHAR
*write_lpsztext
;
153 /* Data when message returned */
154 const WCHAR
*return_sztext
;
155 INT return_sztext_size
;
156 const WCHAR
*return_lpsztext
;
157 HMODULE return_hinst
;
158 /* Data expected by parent */
159 const CHAR
*expect_sztext
;
160 /* Data send to parent */
161 const WCHAR
*send_sztext
;
162 INT send_sztext_size
;
163 const WCHAR
*send_lpsztext
;
164 } test_tooltip_data
[] =
166 {NULL
, 0, NULL
, NULL
, L
"", -1, L
""},
167 {test_a
, sizeof(test_a
), NULL
, NULL
, test_w
, -1, test_w
},
168 {test_a
, sizeof(test_a
), test_a
, NULL
, test_w
, -1, test_w
},
169 {test_a
, sizeof(test_a
), (CHAR
*)1, (HMODULE
)0xdeadbeef, L
"", -1, (WCHAR
*)1, (HMODULE
)0xdeadbeef},
170 {test_a
, sizeof(test_a
), test_a
, (HMODULE
)0xdeadbeef, test_w
, -1, test_w
, (HMODULE
)0xdeadbeef},
171 {NULL
, 0, test_a
, NULL
, test_w
, -1, test_w
},
172 {test_a
, 2, test_a
, NULL
, test_w
, -1, test_w
},
173 {NULL
, 0, NULL
, NULL
, test_w
, -1, test_w
, NULL
, test_a
, test_w
, sizeof(test_w
)},
174 {NULL
, 0, NULL
, NULL
, L
"", -1, L
"", NULL
, "", NULL
, 0, test_w
},
175 {NULL
, 0, large_a
, NULL
, large_truncated_80_w
, sizeof(large_truncated_80_w
), large_w
}
178 static const struct notify_test_datetime_format
180 /* Data send to parent */
181 const WCHAR
*send_pszformat
;
182 /* Data expected by parent */
183 const CHAR
*expect_pszformat
;
184 /* Data for parent to write */
185 const CHAR
*write_szdisplay
;
186 INT write_szdisplay_size
;
187 const CHAR
*write_pszdisplay
;
188 /* Data when message returned */
189 const WCHAR
*return_szdisplay
;
190 INT return_szdisplay_size
;
191 const WCHAR
*return_pszdisplay
;
192 } test_datetime_format_data
[] =
195 {NULL
, NULL
, NULL
, 0, test_a
, L
"", -1, test_w
},
196 {NULL
, NULL
, test_a
, sizeof(test_a
), NULL
, test_w
, -1, test_w
},
197 {NULL
, NULL
, test_a
, 2, test_a
, (WCHAR
*)te_a
, -1, test_w
},
198 {NULL
, NULL
, NULL
, 0, large_a
, NULL
, 0, large_w
}
204 static BOOL (WINAPI
*pInitCommonControlsEx
)(const INITCOMMONCONTROLSEX
*);
205 static BOOL (WINAPI
*pSetWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
, DWORD_PTR
);
207 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
209 static const struct message set_child_seq
[] = {
210 { PGM_SETCHILD
, sent
},
211 { WM_WINDOWPOSCHANGING
, sent
},
212 { WM_NCCALCSIZE
, sent
|wparam
, TRUE
},
213 { WM_NOTIFY
, sent
|id
|parent
, 0, 0, PGN_CALCSIZE
},
214 { WM_WINDOWPOSCHANGED
, sent
},
215 { WM_WINDOWPOSCHANGING
, sent
|id
, 0, 0, CHILD1_ID
},
216 { WM_NCCALCSIZE
, sent
|wparam
|id
|optional
, TRUE
, 0, CHILD1_ID
},
217 { WM_CHILDACTIVATE
, sent
|id
, 0, 0, CHILD1_ID
},
218 { WM_WINDOWPOSCHANGED
, sent
|id
, 0, 0, CHILD1_ID
},
219 { WM_SIZE
, sent
|id
|defwinproc
|optional
, 0, 0, CHILD1_ID
},
223 /* This differs from the above message list only in the child window that is
224 * expected to receive the child messages. No message is sent to the old child.
225 * Also child 2 is hidden while child 1 is visible. The pager does not make the
226 * hidden child visible. */
227 static const struct message switch_child_seq
[] = {
228 { PGM_SETCHILD
, sent
},
229 { WM_WINDOWPOSCHANGING
, sent
},
230 { WM_NCCALCSIZE
, sent
|wparam
, TRUE
},
231 { WM_NOTIFY
, sent
|id
|parent
, 0, 0, PGN_CALCSIZE
},
232 { WM_WINDOWPOSCHANGED
, sent
},
233 { WM_WINDOWPOSCHANGING
, sent
|id
, 0, 0, CHILD2_ID
},
234 { WM_NCCALCSIZE
, sent
|wparam
|id
, TRUE
, 0, CHILD2_ID
},
235 { WM_CHILDACTIVATE
, sent
|id
, 0, 0, CHILD2_ID
},
236 { WM_WINDOWPOSCHANGED
, sent
|id
, 0, 0, CHILD2_ID
},
237 { WM_SIZE
, sent
|id
|defwinproc
, 0, 0, CHILD2_ID
},
241 static const struct message set_pos_seq
[] = {
242 { PGM_SETPOS
, sent
},
243 { WM_WINDOWPOSCHANGING
, sent
},
244 { WM_NCCALCSIZE
, sent
|wparam
, TRUE
},
245 { WM_NOTIFY
, sent
|id
|parent
, 0, 0, PGN_CALCSIZE
},
246 { WM_WINDOWPOSCHANGED
, sent
},
247 { WM_MOVE
, sent
|optional
},
248 /* The WM_SIZE handler sends WM_WINDOWPOSCHANGING, WM_CHILDACTIVATE
249 * and WM_WINDOWPOSCHANGED (which sends WM_MOVE) to the child.
250 * Another WM_WINDOWPOSCHANGING is sent afterwards.
252 * The 2nd WM_WINDOWPOSCHANGING is unconditional, but the comparison
253 * function is too simple to roll back an accepted message, so we have
254 * to mark the 2nd message optional. */
255 { WM_SIZE
, sent
|optional
},
256 { WM_WINDOWPOSCHANGING
, sent
|id
, 0, 0, CHILD1_ID
}, /* Actually optional. */
257 { WM_CHILDACTIVATE
, sent
|id
, 0, 0, CHILD1_ID
}, /* Actually optional. */
258 { WM_WINDOWPOSCHANGED
, sent
|id
|optional
, TRUE
, 0, CHILD1_ID
},
259 { WM_MOVE
, sent
|id
|optional
|defwinproc
, 0, 0, CHILD1_ID
},
260 { WM_WINDOWPOSCHANGING
, sent
|id
|optional
, 0, 0, CHILD1_ID
}, /* Actually not optional. */
261 { WM_CHILDACTIVATE
, sent
|id
|optional
, 0, 0, CHILD1_ID
}, /* Actually not optional. */
265 static const struct message set_pos_empty_seq
[] = {
266 { PGM_SETPOS
, sent
},
270 static CHAR
*heap_strdup(const CHAR
*str
)
272 int len
= lstrlenA(str
) + 1;
273 CHAR
*ret
= heap_alloc(len
* sizeof(CHAR
));
278 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
280 static LONG defwndproc_counter
= 0;
284 /* log system messages, except for painting */
285 if (message
< WM_USER
&&
286 message
!= WM_PAINT
&&
287 message
!= WM_ERASEBKGND
&&
288 message
!= WM_NCPAINT
&&
289 message
!= WM_NCHITTEST
&&
290 message
!= WM_GETTEXT
&&
291 message
!= WM_GETICON
&&
292 message
!= WM_DEVICECHANGE
)
294 msg
.message
= message
;
295 msg
.flags
= sent
|wparam
|lparam
|parent
;
296 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
299 if (message
== WM_NOTIFY
&& lParam
) msg
.id
= ((NMHDR
*)lParam
)->code
;
300 add_message(sequences
, PAGER_SEQ_INDEX
, &msg
);
303 if (message
== WM_NOTIFY
)
305 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
311 NMPGCALCSIZE
*nmpgcs
= (NMPGCALCSIZE
*)lParam
;
312 DWORD style
= GetWindowLongA(nmpgcs
->hdr
.hwndFrom
, GWL_STYLE
);
314 if (style
& PGS_HORZ
)
315 ok(nmpgcs
->dwFlag
== PGF_CALCWIDTH
, "Unexpected flags %#x.\n", nmpgcs
->dwFlag
);
317 ok(nmpgcs
->dwFlag
== PGF_CALCHEIGHT
, "Unexpected flags %#x.\n", nmpgcs
->dwFlag
);
325 defwndproc_counter
++;
326 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
327 defwndproc_counter
--;
332 static BOOL
register_parent_wnd_class(void)
337 cls
.lpfnWndProc
= parent_wnd_proc
;
340 cls
.hInstance
= GetModuleHandleA(NULL
);
342 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
343 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
344 cls
.lpszMenuName
= NULL
;
345 cls
.lpszClassName
= "Pager test parent class";
346 return RegisterClassA(&cls
);
349 static HWND
create_parent_window(void)
351 if (!register_parent_wnd_class())
354 return CreateWindowA("Pager test parent class", "Pager test parent window",
355 WS_OVERLAPPED
| WS_VISIBLE
,
356 0, 0, 200, 200, 0, NULL
, GetModuleHandleA(NULL
), NULL
);
359 static LRESULT WINAPI
pager_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
361 WNDPROC oldproc
= (WNDPROC
)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
362 struct message msg
= { 0 };
364 msg
.message
= message
;
365 msg
.flags
= sent
|wparam
|lparam
;
368 add_message(sequences
, PAGER_SEQ_INDEX
, &msg
);
369 return CallWindowProcA(oldproc
, hwnd
, message
, wParam
, lParam
);
372 static HWND
create_pager_control( DWORD style
)
378 GetClientRect( parent_wnd
, &rect
);
379 hwnd
= CreateWindowA( WC_PAGESCROLLERA
, "pager", WS_CHILD
| WS_BORDER
| WS_VISIBLE
| style
,
380 0, 0, 100, 100, parent_wnd
, 0, GetModuleHandleA(0), 0 );
381 oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)pager_subclass_proc
);
382 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)oldproc
);
386 static LRESULT WINAPI
child_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
388 static LONG defwndproc_counter
;
389 struct message msg
= { 0 };
392 msg
.message
= message
;
393 msg
.flags
= sent
| wparam
| lparam
;
394 if (defwndproc_counter
)
395 msg
.flags
|= defwinproc
;
399 if (hwnd
== child1_wnd
)
401 else if (hwnd
== child2_wnd
)
406 add_message(sequences
, PAGER_SEQ_INDEX
, &msg
);
408 defwndproc_counter
++;
409 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
410 defwndproc_counter
--;
415 static BOOL
register_child_wnd_class(void)
420 cls
.lpfnWndProc
= child_proc
;
423 cls
.hInstance
= GetModuleHandleA(NULL
);
425 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
426 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
427 cls
.lpszMenuName
= NULL
;
428 cls
.lpszClassName
= "Pager test child class";
429 return RegisterClassA(&cls
);
432 static void test_pager(void)
437 pager
= create_pager_control( PGS_HORZ
);
438 ok(pager
!= NULL
, "Fail to create pager\n");
440 register_child_wnd_class();
442 child1_wnd
= CreateWindowA( "Pager test child class", "button", WS_CHILD
| WS_BORDER
| WS_VISIBLE
, 0, 0, 300, 300,
443 pager
, 0, GetModuleHandleA(0), 0 );
444 child2_wnd
= CreateWindowA("Pager test child class", "button", WS_CHILD
| WS_BORDER
, 0, 0, 300, 300,
445 pager
, 0, GetModuleHandleA(0), 0);
447 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
448 SendMessageA( pager
, PGM_SETCHILD
, 0, (LPARAM
)child1_wnd
);
449 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_child_seq
, "set child", FALSE
);
450 GetWindowRect( pager
, &rect
);
451 ok( rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
452 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
454 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
455 SendMessageA(pager
, PGM_SETCHILD
, 0, (LPARAM
)child2_wnd
);
456 ok_sequence(sequences
, PAGER_SEQ_INDEX
, switch_child_seq
, "switch to invisible child", FALSE
);
457 GetWindowRect(pager
, &rect
);
458 ok(rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
459 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
460 ok(!IsWindowVisible(child2_wnd
), "Child window 2 is visible\n");
462 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
463 SendMessageA(pager
, PGM_SETCHILD
, 0, (LPARAM
)child1_wnd
);
464 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_child_seq
, "switch to visible child", FALSE
);
465 GetWindowRect(pager
, &rect
);
466 ok(rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
467 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
469 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
470 SendMessageA( pager
, PGM_SETPOS
, 0, 10 );
471 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_pos_seq
, "set pos", TRUE
);
472 GetWindowRect( pager
, &rect
);
473 ok( rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
474 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
476 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
477 SendMessageA( pager
, PGM_SETPOS
, 0, 10 );
478 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_pos_empty_seq
, "set pos empty", TRUE
);
480 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
481 SendMessageA( pager
, PGM_SETPOS
, 0, 9 );
482 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_pos_seq
, "set pos", TRUE
);
484 DestroyWindow( pager
);
486 /* Test if resizing works */
487 pager
= create_pager_control( CCS_NORESIZE
);
488 ok(pager
!= NULL
, "failed to create pager control\n");
490 GetWindowRect( pager
, &rect
);
491 MoveWindow( pager
, 0, 0, 200, 100, TRUE
);
492 GetWindowRect( pager
, &rect2
);
493 ok(rect2
.right
- rect2
.left
> rect
.right
- rect
.left
, "expected pager window to resize, %s\n",
494 wine_dbgstr_rect( &rect2
));
496 DestroyWindow( pager
);
498 pager
= create_pager_control( CCS_NORESIZE
| PGS_HORZ
);
499 ok(pager
!= NULL
, "failed to create pager control\n");
501 GetWindowRect( pager
, &rect
);
502 MoveWindow( pager
, 0, 0, 100, 200, TRUE
);
503 GetWindowRect( pager
, &rect2
);
504 ok(rect2
.bottom
- rect2
.top
> rect
.bottom
- rect
.top
, "expected pager window to resize, %s\n",
505 wine_dbgstr_rect( &rect2
));
507 DestroyWindow( pager
);
510 static LRESULT WINAPI
test_notifyformat_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
514 case WM_NOTIFYFORMAT
:
515 if (lParam
== NF_QUERY
)
517 notify_query_received
= TRUE
;
518 return notify_format
;
520 else if (lParam
== NF_REQUERY
)
521 return SendMessageA(GetParent(hwnd
), WM_NOTIFYFORMAT
, (WPARAM
)hwnd
, NF_QUERY
);
525 return notify_format
== NFR_UNICODE
? DefWindowProcW(hwnd
, message
, wParam
, lParam
)
526 : DefWindowProcA(hwnd
, message
, wParam
, lParam
);
530 static BOOL
register_notifyformat_class(void)
534 cls
.lpfnWndProc
= test_notifyformat_proc
;
535 cls
.hInstance
= GetModuleHandleW(NULL
);
536 cls
.lpszClassName
= L
"Pager notifyformat class";
537 return RegisterClassW(&cls
);
540 static void test_wm_notifyformat(void)
542 static const INT formats
[] = {NFR_UNICODE
, NFR_ANSI
};
543 HWND parent
, pager
, child
;
548 bret
= register_notifyformat_class();
549 ok(bret
, "Register test class failed, error 0x%08x\n", GetLastError());
551 for (i
= 0; i
< ARRAY_SIZE(formats
); i
++)
553 notify_format
= formats
[i
];
554 parent
= CreateWindowW(L
"Pager notifyformat class", L
"parent", WS_OVERLAPPED
, 0, 0, 100, 100, 0, 0, GetModuleHandleW(0), 0);
555 ok(parent
!= NULL
, "CreateWindow failed\n");
556 pager
= CreateWindowW(WC_PAGESCROLLERW
, L
"pager", WS_CHILD
, 0, 0, 100, 100, parent
, 0, GetModuleHandleW(0), 0);
557 ok(pager
!= NULL
, "CreateWindow failed\n");
558 child
= CreateWindowW(L
"Pager notifyformat class", L
"child", WS_CHILD
, 0, 0, 100, 100, pager
, 0, GetModuleHandleW(0), 0);
559 ok(child
!= NULL
, "CreateWindow failed\n");
560 SendMessageW(pager
, PGM_SETCHILD
, 0, (LPARAM
)child
);
563 notify_query_received
= FALSE
;
564 ret
= SendMessageW(pager
, WM_NOTIFYFORMAT
, (WPARAM
)parent
, NF_REQUERY
);
565 ok(ret
== notify_format
, "Expect %d, got %ld\n", notify_format
, ret
);
566 ok(notify_query_received
, "Didn't receive notify\n");
568 /* Send NF_QUERY directly to parent */
569 notify_query_received
= FALSE
;
570 ret
= SendMessageW(parent
, WM_NOTIFYFORMAT
, (WPARAM
)pager
, NF_QUERY
);
571 ok(ret
== notify_format
, "Expect %d, got %ld\n", notify_format
, ret
);
572 ok(notify_query_received
, "Didn't receive notify\n");
574 /* Pager send notifications to its parent regardless of wParam */
575 notify_query_received
= FALSE
;
576 ret
= SendMessageW(pager
, WM_NOTIFYFORMAT
, (WPARAM
)parent_wnd
, NF_REQUERY
);
577 ok(ret
== notify_format
, "Expect %d, got %ld\n", notify_format
, ret
);
578 ok(notify_query_received
, "Didn't receive notify\n");
580 /* Pager always wants Unicode notifications from children */
581 ret
= SendMessageW(child
, WM_NOTIFYFORMAT
, (WPARAM
)pager
, NF_REQUERY
);
582 ok(ret
== NFR_UNICODE
, "Expect %d, got %ld\n", NFR_UNICODE
, ret
);
583 ret
= SendMessageW(pager
, WM_NOTIFYFORMAT
, (WPARAM
)child
, NF_QUERY
);
584 ok(ret
== NFR_UNICODE
, "Expect %d, got %ld\n", NFR_UNICODE
, ret
);
586 DestroyWindow(parent
);
589 UnregisterClassW(L
"Pager notifyformat class", GetModuleHandleW(NULL
));
592 static void notify_generic_text_handler(CHAR
**text
, INT
*text_max
)
594 const struct notify_test_send
*send_data
;
595 const struct notify_test_receive
*receive_data
;
597 switch (notify_test_info
.test_id
)
600 case DONT_CONVERT_SEND
:
602 send_data
= (notify_test_info
.test_id
== CONVERT_SEND
? test_convert_send_data
: test_dont_convert_send_data
)
603 + notify_test_info
.sub_test_id
;
604 if (notify_test_info
.flags
& ZERO_SEND
)
605 ok(!*text
[0], "Code 0x%08x test 0x%08x sub test %d expect empty text, got %s\n",
606 notify_test_info
.unicode
, notify_test_info
.test_id
, notify_test_info
.sub_test_id
, *text
);
607 else if (notify_test_info
.flags
& CONVERT_SEND
)
608 ok(!lstrcmpA(send_data
->expect_text
, *text
), "Code 0x%08x test 0x%08x sub test %d expect %s, got %s\n",
609 notify_test_info
.unicode
, notify_test_info
.test_id
, notify_test_info
.sub_test_id
,
610 (CHAR
*)send_data
->expect_text
, *text
);
612 ok(!lstrcmpW((WCHAR
*)send_data
->expect_text
, (WCHAR
*)*text
),
613 "Code 0x%08x test 0x%08x sub test %d expect %s, got %s\n", notify_test_info
.unicode
,
614 notify_test_info
.test_id
, notify_test_info
.sub_test_id
, wine_dbgstr_w((WCHAR
*)send_data
->expect_text
),
615 wine_dbgstr_w((WCHAR
*)*text
));
617 ok(*text_max
== send_data
->send_text_max
, "Code 0x%08x test 0x%08x sub test %d expect %d, got %d\n",
618 notify_test_info
.unicode
, notify_test_info
.test_id
, notify_test_info
.sub_test_id
,
619 send_data
->send_text_max
, *text_max
);
622 case CONVERT_RECEIVE
:
623 case DONT_CONVERT_RECEIVE
:
625 receive_data
= (notify_test_info
.test_id
== CONVERT_RECEIVE
? test_convert_receive_data
: test_dont_convert_receive_data
)
626 + notify_test_info
.sub_test_id
;
628 ok(*text_max
== receive_data
->send_text_max
, "Code 0x%08x test 0x%08x sub test %d expect %d, got %d\n",
629 notify_test_info
.unicode
, notify_test_info
.test_id
, notify_test_info
.sub_test_id
,
630 receive_data
->send_text_max
, *text_max
);
632 if (receive_data
->write_text
)
633 memcpy(*text
, receive_data
->write_text
, receive_data
->write_text_size
);
634 /* 64bit Windows will try to free the text pointer even if it's application provided when handling
635 * HDN_GETDISPINFOW. Deliberate leak here. */
636 else if(notify_test_info
.unicode
== HDN_GETDISPINFOW
)
637 *text
= heap_strdup(receive_data
->write_pointer
);
639 *text
= (char *)receive_data
->write_pointer
;
640 if (text_max
&& receive_data
->write_text_max
!= -1) *text_max
= receive_data
->write_text_max
;
643 case SEND_EMPTY_IF_NULL
:
644 ok(!*text
[0], "Code 0x%08x test 0x%08x sub test %d expect empty text, got %s\n",
645 notify_test_info
.unicode
, notify_test_info
.test_id
, notify_test_info
.sub_test_id
, *text
);
647 case DONT_SEND_EMPTY_IF_NULL
:
648 ok(!*text
, "Code 0x%08x test 0x%08x sub test %d expect null text\n", notify_test_info
.unicode
,
649 notify_test_info
.test_id
, notify_test_info
.sub_test_id
);
654 static void notify_tooltip_handler(NMTTDISPINFOA
*nm
)
656 const struct notify_test_tooltip
*data
= test_tooltip_data
+ notify_test_info
.sub_test_id
;
657 ok(nm
->lpszText
== nm
->szText
, "Sub test %d expect %p, got %p\n", notify_test_info
.sub_test_id
, nm
->szText
,
659 if (data
->expect_sztext
)
660 ok(!lstrcmpA(data
->expect_sztext
, nm
->szText
), "Sub test %d expect %s, got %s\n", notify_test_info
.sub_test_id
,
661 data
->expect_sztext
, nm
->szText
);
662 if (data
->write_sztext
) memcpy(nm
->szText
, data
->write_sztext
, data
->write_sztext_size
);
663 if (data
->write_lpsztext
) nm
->lpszText
= (char *)data
->write_lpsztext
;
664 if (data
->write_hinst
) nm
->hinst
= data
->write_hinst
;
667 static void notify_datetime_handler(NMDATETIMEFORMATA
*nm
)
669 const struct notify_test_datetime_format
*data
= test_datetime_format_data
+ notify_test_info
.sub_test_id
;
670 if (data
->expect_pszformat
)
671 ok(!lstrcmpA(data
->expect_pszformat
, nm
->pszFormat
), "Sub test %d expect %s, got %s\n",
672 notify_test_info
.sub_test_id
, data
->expect_pszformat
, nm
->pszFormat
);
673 ok(nm
->pszDisplay
== nm
->szDisplay
, "Test %d expect %p, got %p\n", notify_test_info
.sub_test_id
, nm
->szDisplay
,
675 if (data
->write_szdisplay
) memcpy(nm
->szDisplay
, data
->write_szdisplay
, data
->write_szdisplay_size
);
676 if (data
->write_pszdisplay
) nm
->pszDisplay
= data
->write_pszdisplay
;
679 static LRESULT WINAPI
test_notify_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
685 NMHDR
*hdr
= (NMHDR
*)lParam
;
687 /* Not notifications we want to test */
688 if (!notify_test_info
.unicode
) break;
689 ok(!notify_test_info
.received
, "Extra notification received\n");
691 ok(wParam
== notify_test_info
.id_from
, "Expect %ld, got %ld\n", notify_test_info
.id_from
, wParam
);
692 ok(hdr
->code
== notify_test_info
.ansi
, "Expect 0x%08x, got 0x%08x\n", notify_test_info
.ansi
, hdr
->code
);
693 ok(hdr
->idFrom
== notify_test_info
.id_from
, "Expect %ld, got %ld\n", notify_test_info
.id_from
, wParam
);
694 ok(hdr
->hwndFrom
== notify_test_info
.hwnd_from
, "Expect %p, got %p\n", notify_test_info
.hwnd_from
, hdr
->hwndFrom
);
696 if (hdr
->code
!= notify_test_info
.ansi
)
698 skip("Notification code mismatch, skipping lParam check\n");
704 case CBEN_INSERTITEM
:
705 case CBEN_DELETEITEM
:
707 NMCOMBOBOXEXW
*nmcbe
= (NMCOMBOBOXEXW
*)hdr
;
708 notify_generic_text_handler((CHAR
**)&nmcbe
->ceItem
.pszText
, NULL
);
711 case CBEN_DRAGBEGINA
:
713 NMCBEDRAGBEGINA
*nmcbedb
= (NMCBEDRAGBEGINA
*)hdr
;
714 ok(!lstrcmpA(nmcbedb
->szText
, test_a
), "Expect %s, got %s\n", nmcbedb
->szText
, test_a
);
719 NMCBEENDEDITA
*nmcbeed
= (NMCBEENDEDITA
*)hdr
;
720 ok(!lstrcmpA(nmcbeed
->szText
, test_a
), "Expect %s, got %s\n", nmcbeed
->szText
, test_a
);
723 case CBEN_GETDISPINFOA
:
725 NMCOMBOBOXEXA
*nmcbe
= (NMCOMBOBOXEXA
*)hdr
;
726 notify_generic_text_handler(&nmcbe
->ceItem
.pszText
, &nmcbe
->ceItem
.cchTextMax
);
729 /* Date and Time Picker */
732 notify_datetime_handler((NMDATETIMEFORMATA
*)hdr
);
735 case DTN_FORMATQUERYA
:
737 NMDATETIMEFORMATQUERYA
*nmdtfq
= (NMDATETIMEFORMATQUERYA
*)hdr
;
738 notify_generic_text_handler((CHAR
**)&nmdtfq
->pszFormat
, NULL
);
743 NMDATETIMEWMKEYDOWNA
*nmdtkd
= (NMDATETIMEWMKEYDOWNA
*)hdr
;
744 notify_generic_text_handler((CHAR
**)&nmdtkd
->pszFormat
, NULL
);
747 case DTN_USERSTRINGA
:
749 NMDATETIMESTRINGA
*nmdts
= (NMDATETIMESTRINGA
*)hdr
;
750 notify_generic_text_handler((CHAR
**)&nmdts
->pszUserString
, NULL
);
756 case HDN_BEGINFILTEREDIT
:
757 case HDN_ENDFILTEREDIT
:
759 case HDN_FILTERCHANGE
:
760 case HDN_ITEMKEYDOWN
:
761 case HDN_ITEMSTATEICONCLICK
:
762 case HDN_OVERFLOWCLICK
:
764 NMHEADERW
*nmhd
= (NMHEADERW
*)hdr
;
765 ok(!lstrcmpW(nmhd
->pitem
->pszText
, test_w
), "Expect %s, got %s\n", wine_dbgstr_w(test_w
),
766 wine_dbgstr_w(nmhd
->pitem
->pszText
));
767 ok(!lstrcmpW(((HD_TEXTFILTERW
*)nmhd
->pitem
->pvFilter
)->pszText
, test_w
), "Expect %s, got %s\n",
768 wine_dbgstr_w(test_w
), wine_dbgstr_w(((HD_TEXTFILTERW
*)nmhd
->pitem
->pvFilter
)->pszText
));
771 case HDN_BEGINTRACKA
:
772 case HDN_DIVIDERDBLCLICKA
:
774 case HDN_ITEMCHANGEDA
:
775 case HDN_ITEMCHANGINGA
:
777 case HDN_ITEMDBLCLICKA
:
780 NMHEADERA
*nmhd
= (NMHEADERA
*)hdr
;
781 ok(!lstrcmpA(nmhd
->pitem
->pszText
, test_a
), "Expect %s, got %s\n", test_a
, nmhd
->pitem
->pszText
);
782 ok(!lstrcmpA(((HD_TEXTFILTERA
*)nmhd
->pitem
->pvFilter
)->pszText
, test_a
), "Expect %s, got %s\n", test_a
,
783 ((HD_TEXTFILTERA
*)nmhd
->pitem
->pvFilter
)->pszText
);
786 case HDN_GETDISPINFOA
:
788 NMHDDISPINFOA
*nmhddi
= (NMHDDISPINFOA
*)hdr
;
789 notify_generic_text_handler(&nmhddi
->pszText
, &nmhddi
->cchTextMax
);
793 case LVN_BEGINLABELEDITA
:
794 case LVN_ENDLABELEDITA
:
795 case LVN_GETDISPINFOA
:
796 case LVN_SETDISPINFOA
:
798 NMLVDISPINFOA
*nmlvdi
= (NMLVDISPINFOA
*)hdr
;
799 notify_generic_text_handler(&nmlvdi
->item
.pszText
, &nmlvdi
->item
.cchTextMax
);
802 case LVN_GETINFOTIPA
:
804 NMLVGETINFOTIPA
*nmlvgit
= (NMLVGETINFOTIPA
*)hdr
;
805 notify_generic_text_handler(&nmlvgit
->pszText
, &nmlvgit
->cchTextMax
);
808 case LVN_INCREMENTALSEARCHA
:
809 case LVN_ODFINDITEMA
:
811 NMLVFINDITEMA
*nmlvfi
= (NMLVFINDITEMA
*)hdr
;
812 notify_generic_text_handler((CHAR
**)&nmlvfi
->lvfi
.psz
, NULL
);
818 NMTBSAVE
*nmtbs
= (NMTBSAVE
*)hdr
;
819 notify_generic_text_handler((CHAR
**)&nmtbs
->tbButton
.iString
, NULL
);
824 NMTBRESTORE
*nmtbr
= (NMTBRESTORE
*)hdr
;
825 notify_generic_text_handler((CHAR
**)&nmtbr
->tbButton
.iString
, NULL
);
828 case TBN_GETBUTTONINFOA
:
830 NMTOOLBARA
*nmtb
= (NMTOOLBARA
*)hdr
;
831 notify_generic_text_handler(&nmtb
->pszText
, &nmtb
->cchText
);
834 case TBN_GETDISPINFOW
:
836 NMTBDISPINFOW
*nmtbdi
= (NMTBDISPINFOW
*)hdr
;
837 notify_generic_text_handler((CHAR
**)&nmtbdi
->pszText
, &nmtbdi
->cchText
);
840 case TBN_GETINFOTIPA
:
842 NMTBGETINFOTIPA
*nmtbgit
= (NMTBGETINFOTIPA
*)hdr
;
843 notify_generic_text_handler(&nmtbgit
->pszText
, &nmtbgit
->cchTextMax
);
847 case TTN_GETDISPINFOA
:
849 notify_tooltip_handler((NMTTDISPINFOA
*)hdr
);
853 case TVN_BEGINLABELEDITA
:
854 case TVN_ENDLABELEDITA
:
855 case TVN_GETDISPINFOA
:
856 case TVN_SETDISPINFOA
:
858 NMTVDISPINFOA
*nmtvdi
= (NMTVDISPINFOA
*)hdr
;
859 notify_generic_text_handler(&nmtvdi
->item
.pszText
, &nmtvdi
->item
.cchTextMax
);
862 case TVN_GETINFOTIPA
:
864 NMTVGETINFOTIPA
*nmtvgit
= (NMTVGETINFOTIPA
*)hdr
;
865 notify_generic_text_handler(&nmtvgit
->pszText
, &nmtvgit
->cchTextMax
);
868 case TVN_SINGLEEXPAND
:
870 case TVN_BEGINRDRAGA
:
871 case TVN_ITEMEXPANDEDA
:
872 case TVN_ITEMEXPANDINGA
:
873 case TVN_DELETEITEMA
:
874 case TVN_SELCHANGINGA
:
875 case TVN_SELCHANGEDA
:
877 NMTREEVIEWA
*nmtv
= (NMTREEVIEWA
*)hdr
;
878 if (notify_test_info
.handler_id
== TVITEM_NEW_HANDLER
)
879 notify_generic_text_handler((CHAR
**)&nmtv
->itemNew
.pszText
, &nmtv
->itemNew
.cchTextMax
);
881 notify_generic_text_handler((CHAR
**)&nmtv
->itemOld
.pszText
, &nmtv
->itemOld
.cchTextMax
);
886 ok(0, "Unexpected message 0x%08x\n", hdr
->code
);
888 notify_test_info
.received
= TRUE
;
889 ok(!lstrcmpA(test_a
, "test"), "test_a got modified\n");
890 ok(!lstrcmpW(test_w
, L
"test"), "test_w got modified\n");
893 case WM_NOTIFYFORMAT
:
894 if (lParam
== NF_QUERY
) return NFR_ANSI
;
897 return DefWindowProcA(hwnd
, message
, wParam
, lParam
);
900 static BOOL
register_test_notify_class(void)
904 cls
.lpfnWndProc
= test_notify_proc
;
905 cls
.hInstance
= GetModuleHandleA(NULL
);
906 cls
.lpszClassName
= "Pager notify class";
907 return RegisterClassA(&cls
);
910 static void send_notify(HWND pager
, UINT unicode
, UINT ansi
, LPARAM lParam
, BOOL code_change
)
912 NMHDR
*hdr
= (NMHDR
*)lParam
;
914 notify_test_info
.unicode
= unicode
;
915 notify_test_info
.id_from
= 1;
916 notify_test_info
.hwnd_from
= child1_wnd
;
917 notify_test_info
.ansi
= ansi
;
918 notify_test_info
.received
= FALSE
;
922 hdr
->hwndFrom
= child1_wnd
;
924 SendMessageW(pager
, WM_NOTIFY
, hdr
->idFrom
, lParam
);
925 ok(notify_test_info
.received
, "Expect notification received\n");
926 ok(hdr
->code
== code_change
? ansi
: unicode
, "Expect 0x%08x, got 0x%08x\n", hdr
->code
,
927 code_change
? ansi
: unicode
);
930 /* Send notify to test text field conversion. In parent proc notify_generic_text_handler() handles these messages */
931 static void test_notify_generic_text_helper(HWND pager
, const struct generic_text_helper_para
*para
)
933 const struct notify_test_send
*send_data
;
934 const struct notify_test_receive
*receive_data
;
938 notify_test_info
.flags
= para
->flags
;
939 notify_test_info
.handler_id
= para
->handler_id
;
941 if (para
->flags
& (CONVERT_SEND
| DONT_CONVERT_SEND
))
943 if (para
->flags
& CONVERT_SEND
)
945 notify_test_info
.test_id
= CONVERT_SEND
;
946 send_data
= test_convert_send_data
;
947 array_size
= ARRAY_SIZE(test_convert_send_data
);
951 notify_test_info
.test_id
= DONT_CONVERT_SEND
;
952 send_data
= test_dont_convert_send_data
;
953 array_size
= ARRAY_SIZE(test_dont_convert_send_data
);
956 for (i
= 0; i
< array_size
; i
++)
958 const struct notify_test_send
*data
= send_data
+ i
;
959 notify_test_info
.sub_test_id
= i
;
961 memset(para
->ptr
, 0, para
->size
);
962 if (para
->mask
) *para
->mask
= para
->required_mask
;
965 memcpy(buffer
, data
->send_text
, data
->send_text_size
);
966 *para
->text
= buffer
;
968 if (para
->text_max
) *para
->text_max
= data
->send_text_max
;
969 send_notify(pager
, para
->code_unicode
, para
->code_ansi
, (LPARAM
)para
->ptr
, TRUE
);
973 if (para
->flags
& (CONVERT_RECEIVE
| DONT_CONVERT_RECEIVE
))
975 if (para
->flags
& CONVERT_RECEIVE
)
977 notify_test_info
.test_id
= CONVERT_RECEIVE
;
978 receive_data
= test_convert_receive_data
;
979 array_size
= ARRAY_SIZE(test_convert_receive_data
);
983 notify_test_info
.test_id
= DONT_CONVERT_RECEIVE
;
984 receive_data
= test_dont_convert_receive_data
;
985 array_size
= ARRAY_SIZE(test_dont_convert_receive_data
);
988 for (i
= 0; i
< array_size
; i
++)
990 const struct notify_test_receive
*data
= receive_data
+ i
;
991 notify_test_info
.sub_test_id
= i
;
993 memset(para
->ptr
, 0, para
->size
);
994 if (para
->mask
) *para
->mask
= para
->required_mask
;
997 memcpy(buffer
, data
->send_text
, data
->send_text_size
);
998 *para
->text
= buffer
;
1000 if (para
->text_max
) *para
->text_max
= data
->send_text_max
;
1001 send_notify(pager
, para
->code_unicode
, para
->code_ansi
, (LPARAM
)para
->ptr
, TRUE
);
1002 if (data
->return_text
)
1004 if (para
->flags
& CONVERT_RECEIVE
)
1005 ok(!wcsncmp(data
->return_text
, *para
->text
, *para
->text_max
),
1006 "Code 0x%08x sub test %d expect %s, got %s\n", para
->code_unicode
, i
,
1007 wine_dbgstr_w((WCHAR
*)data
->return_text
), wine_dbgstr_w(*para
->text
));
1009 ok(!lstrcmpA(data
->return_text
, (CHAR
*)*para
->text
), "Code 0x%08x sub test %d expect %s, got %s\n",
1010 para
->code_unicode
, i
, (CHAR
*)data
->return_text
, (CHAR
*)*para
->text
);
1013 ok(data
->return_text_max
== *para
->text_max
, "Code 0x%08x sub test %d expect %d, got %d\n",
1014 para
->code_unicode
, i
, data
->return_text_max
, *para
->text_max
);
1018 /* Extra tests for other behavior flags that are not worth it to create their own test arrays */
1019 memset(para
->ptr
, 0, para
->size
);
1020 if (para
->mask
) *para
->mask
= para
->required_mask
;
1021 if (para
->text_max
) *para
->text_max
= 1;
1022 if (para
->flags
& SEND_EMPTY_IF_NULL
)
1023 notify_test_info
.test_id
= SEND_EMPTY_IF_NULL
;
1025 notify_test_info
.test_id
= DONT_SEND_EMPTY_IF_NULL
;
1026 send_notify(pager
, para
->code_unicode
, para
->code_ansi
, (LPARAM
)para
->ptr
, TRUE
);
1028 notify_test_info
.test_id
= SET_NULL_IF_NO_MASK
;
1029 memset(para
->ptr
, 0, para
->size
);
1030 memset(buffer
, 0, sizeof(buffer
));
1031 *para
->text
= buffer
;
1032 if (para
->text_max
) *para
->text_max
= ARRAY_SIZE(buffer
);
1033 send_notify(pager
, para
->code_unicode
, para
->code_ansi
, (LPARAM
)para
->ptr
, TRUE
);
1034 if(para
->flags
& SET_NULL_IF_NO_MASK
)
1035 ok(!*para
->text
, "Expect null text\n");
1038 static void test_wm_notify_comboboxex(HWND pager
)
1040 static NMCBEDRAGBEGINW nmcbedb
;
1041 static NMCBEENDEDITW nmcbeed
;
1043 /* CBEN_DRAGBEGIN */
1044 memset(&nmcbedb
, 0, sizeof(nmcbedb
));
1045 memcpy(nmcbedb
.szText
, test_w
, sizeof(test_w
));
1046 send_notify(pager
, CBEN_DRAGBEGINW
, CBEN_DRAGBEGINA
, (LPARAM
)&nmcbedb
, FALSE
);
1047 ok(!lstrcmpW(nmcbedb
.szText
, test_w
), "Expect %s, got %s\n", wine_dbgstr_w(test_w
), wine_dbgstr_w(nmcbedb
.szText
));
1050 memset(&nmcbeed
, 0, sizeof(nmcbeed
));
1051 memcpy(nmcbeed
.szText
, test_w
, sizeof(test_w
));
1052 send_notify(pager
, CBEN_ENDEDITW
, CBEN_ENDEDITA
, (LPARAM
)&nmcbeed
, FALSE
);
1053 ok(!lstrcmpW(nmcbeed
.szText
, test_w
), "Expect %s, got %s\n", wine_dbgstr_w(test_w
), wine_dbgstr_w(nmcbeed
.szText
));
1056 static void test_wm_notify_datetime(HWND pager
)
1058 const struct notify_test_datetime_format
*data
;
1059 NMDATETIMEFORMATW nmdtf
;
1062 for (i
= 0; i
< ARRAY_SIZE(test_datetime_format_data
); i
++)
1064 data
= test_datetime_format_data
+ i
;
1065 notify_test_info
.sub_test_id
= i
;
1067 memset(&nmdtf
, 0, sizeof(nmdtf
));
1068 if(data
->send_pszformat
) nmdtf
.pszFormat
= data
->send_pszformat
;
1069 nmdtf
.pszDisplay
= nmdtf
.szDisplay
;
1070 send_notify(pager
, DTN_FORMATW
, DTN_FORMATA
, (LPARAM
)&nmdtf
, TRUE
);
1071 if (data
->return_szdisplay
)
1072 ok(!lstrcmpW(nmdtf
.szDisplay
, data
->return_szdisplay
), "Sub test %d expect %s, got %s\n", i
,
1073 wine_dbgstr_w(data
->return_szdisplay
), wine_dbgstr_w(nmdtf
.szDisplay
));
1074 if (data
->return_pszdisplay
)
1075 ok(!lstrcmpW(nmdtf
.pszDisplay
, data
->return_pszdisplay
), "Sub test %d expect %s, got %s\n", i
,
1076 wine_dbgstr_w(data
->return_pszdisplay
), wine_dbgstr_w(nmdtf
.pszDisplay
));
1080 static void test_wm_notify_header(HWND pager
)
1082 NMHEADERW nmh
= {{0}};
1084 HD_TEXTFILTERW hdtf
= {0};
1086 hdi
.mask
= HDI_TEXT
| HDI_FILTER
;
1087 hdi
.pszText
= (WCHAR
*)test_w
;
1088 hdtf
.pszText
= (WCHAR
*)test_w
;
1090 nmh
.pitem
->pvFilter
= &hdtf
;
1091 send_notify(pager
, HDN_BEGINDRAG
, HDN_BEGINDRAG
, (LPARAM
)&nmh
, TRUE
);
1092 send_notify(pager
, HDN_ENDDRAG
, HDN_ENDDRAG
, (LPARAM
)&nmh
, TRUE
);
1093 send_notify(pager
, HDN_BEGINFILTEREDIT
, HDN_BEGINFILTEREDIT
, (LPARAM
)&nmh
, TRUE
);
1094 send_notify(pager
, HDN_ENDFILTEREDIT
, HDN_ENDFILTEREDIT
, (LPARAM
)&nmh
, TRUE
);
1095 send_notify(pager
, HDN_DROPDOWN
, HDN_DROPDOWN
, (LPARAM
)&nmh
, TRUE
);
1096 send_notify(pager
, HDN_FILTERCHANGE
, HDN_FILTERCHANGE
, (LPARAM
)&nmh
, TRUE
);
1097 send_notify(pager
, HDN_ITEMKEYDOWN
, HDN_ITEMKEYDOWN
, (LPARAM
)&nmh
, TRUE
);
1098 send_notify(pager
, HDN_ITEMSTATEICONCLICK
, HDN_ITEMSTATEICONCLICK
, (LPARAM
)&nmh
, TRUE
);
1099 send_notify(pager
, HDN_OVERFLOWCLICK
, HDN_OVERFLOWCLICK
, (LPARAM
)&nmh
, TRUE
);
1100 send_notify(pager
, HDN_BEGINTRACKW
, HDN_BEGINTRACKA
, (LPARAM
)&nmh
, TRUE
);
1101 send_notify(pager
, HDN_DIVIDERDBLCLICKW
, HDN_DIVIDERDBLCLICKA
, (LPARAM
)&nmh
, TRUE
);
1102 send_notify(pager
, HDN_ENDTRACKW
, HDN_ENDTRACKA
, (LPARAM
)&nmh
, TRUE
);
1103 send_notify(pager
, HDN_ITEMCHANGEDW
, HDN_ITEMCHANGEDA
, (LPARAM
)&nmh
, TRUE
);
1104 send_notify(pager
, HDN_ITEMCHANGINGW
, HDN_ITEMCHANGINGA
, (LPARAM
)&nmh
, TRUE
);
1105 send_notify(pager
, HDN_ITEMCLICKW
, HDN_ITEMCLICKA
, (LPARAM
)&nmh
, TRUE
);
1106 send_notify(pager
, HDN_ITEMDBLCLICKW
, HDN_ITEMDBLCLICKA
, (LPARAM
)&nmh
, TRUE
);
1107 send_notify(pager
, HDN_TRACKW
, HDN_TRACKA
, (LPARAM
)&nmh
, TRUE
);
1110 static void test_wm_notify_tooltip(HWND pager
)
1112 NMTTDISPINFOW nmttdi
;
1113 const struct notify_test_tooltip
*data
;
1116 for (i
= 0; i
< ARRAY_SIZE(test_tooltip_data
); i
++)
1118 data
= test_tooltip_data
+ i
;
1119 notify_test_info
.sub_test_id
= i
;
1121 memset(&nmttdi
, 0, sizeof(nmttdi
));
1122 if (data
->send_sztext
) memcpy(nmttdi
.szText
, data
->send_sztext
, data
->send_sztext_size
);
1123 if (data
->send_lpsztext
) nmttdi
.lpszText
= (WCHAR
*)data
->send_lpsztext
;
1124 send_notify(pager
, TTN_GETDISPINFOW
, TTN_GETDISPINFOA
, (LPARAM
)&nmttdi
, FALSE
);
1125 if (data
->return_sztext
)
1127 if (data
->return_sztext_size
== -1)
1128 ok(!lstrcmpW(nmttdi
.szText
, data
->return_sztext
), "Sub test %d expect %s, got %s\n", i
,
1129 wine_dbgstr_w(data
->return_sztext
), wine_dbgstr_w(nmttdi
.szText
));
1131 ok(!memcmp(nmttdi
.szText
, data
->return_sztext
, data
->return_sztext_size
), "Wrong szText content\n");
1133 if (data
->return_lpsztext
)
1135 if (IS_INTRESOURCE(data
->return_lpsztext
))
1136 ok(nmttdi
.lpszText
== data
->return_lpsztext
, "Sub test %d expect %s, got %s\n", i
,
1137 wine_dbgstr_w(data
->return_lpsztext
), wine_dbgstr_w(nmttdi
.lpszText
));
1139 ok(!lstrcmpW(nmttdi
.lpszText
, data
->return_lpsztext
), "Test %d expect %s, got %s\n", i
,
1140 wine_dbgstr_w(data
->return_lpsztext
), wine_dbgstr_w(nmttdi
.lpszText
));
1142 if (data
->return_hinst
)
1143 ok(nmttdi
.hinst
== data
->return_hinst
, "Sub test %d expect %p, got %p\n", i
, data
->return_hinst
,
1148 static void test_wm_notify(void)
1150 static const CHAR
*class = "Pager notify class";
1153 static NMCOMBOBOXEXW nmcbe
;
1154 /* Date and Time Picker */
1155 static NMDATETIMEFORMATQUERYW nmdtfq
;
1156 static NMDATETIMEWMKEYDOWNW nmdtkd
;
1157 static NMDATETIMESTRINGW nmdts
;
1159 static NMHDDISPINFOW nmhddi
;
1161 static NMLVDISPINFOW nmlvdi
;
1162 static NMLVGETINFOTIPW nmlvgit
;
1163 static NMLVFINDITEMW nmlvfi
;
1165 static NMTBRESTORE nmtbr
;
1166 static NMTBSAVE nmtbs
;
1167 static NMTOOLBARW nmtb
;
1168 static NMTBDISPINFOW nmtbdi
;
1169 static NMTBGETINFOTIPW nmtbgit
;
1171 static NMTVDISPINFOW nmtvdi
;
1172 static NMTVGETINFOTIPW nmtvgit
;
1173 static NMTREEVIEWW nmtv
;
1174 static const struct generic_text_helper_para paras
[] =
1177 {&nmcbe
, sizeof(nmcbe
), &nmcbe
.ceItem
.mask
, CBEIF_TEXT
, &nmcbe
.ceItem
.pszText
, &nmcbe
.ceItem
.cchTextMax
,
1178 CBEN_INSERTITEM
, CBEN_INSERTITEM
, DONT_CONVERT_SEND
| DONT_CONVERT_RECEIVE
},
1179 {&nmcbe
, sizeof(nmcbe
), &nmcbe
.ceItem
.mask
, CBEIF_TEXT
, &nmcbe
.ceItem
.pszText
, &nmcbe
.ceItem
.cchTextMax
,
1180 CBEN_DELETEITEM
, CBEN_DELETEITEM
, DONT_CONVERT_SEND
| DONT_CONVERT_RECEIVE
},
1181 {&nmcbe
, sizeof(nmcbe
), &nmcbe
.ceItem
.mask
, CBEIF_TEXT
, &nmcbe
.ceItem
.pszText
, &nmcbe
.ceItem
.cchTextMax
,
1182 CBEN_GETDISPINFOW
, CBEN_GETDISPINFOA
, ZERO_SEND
| SET_NULL_IF_NO_MASK
| DONT_CONVERT_SEND
| CONVERT_RECEIVE
},
1183 /* Date and Time Picker */
1184 {&nmdtfq
, sizeof(nmdtfq
), NULL
, 0, (WCHAR
**)&nmdtfq
.pszFormat
, NULL
, DTN_FORMATQUERYW
, DTN_FORMATQUERYA
,
1186 {&nmdtkd
, sizeof(nmdtkd
), NULL
, 0, (WCHAR
**)&nmdtkd
.pszFormat
, NULL
, DTN_WMKEYDOWNW
, DTN_WMKEYDOWNA
,
1188 {&nmdts
, sizeof(nmdts
), NULL
, 0, (WCHAR
**)&nmdts
.pszUserString
, NULL
, DTN_USERSTRINGW
, DTN_USERSTRINGA
,
1191 {&nmhddi
, sizeof(nmhddi
), &nmhddi
.mask
, HDI_TEXT
, &nmhddi
.pszText
, &nmhddi
.cchTextMax
, HDN_GETDISPINFOW
,
1192 HDN_GETDISPINFOA
, SEND_EMPTY_IF_NULL
| CONVERT_SEND
| CONVERT_RECEIVE
},
1194 {&nmlvfi
, sizeof(nmlvfi
), &nmlvfi
.lvfi
.flags
, LVFI_STRING
, (WCHAR
**)&nmlvfi
.lvfi
.psz
, NULL
,
1195 LVN_INCREMENTALSEARCHW
, LVN_INCREMENTALSEARCHA
, CONVERT_SEND
},
1196 {&nmlvfi
, sizeof(nmlvfi
), &nmlvfi
.lvfi
.flags
, LVFI_SUBSTRING
, (WCHAR
**)&nmlvfi
.lvfi
.psz
, NULL
, LVN_ODFINDITEMW
,
1197 LVN_ODFINDITEMA
, CONVERT_SEND
},
1198 {&nmlvdi
, sizeof(nmlvdi
), &nmlvdi
.item
.mask
, LVIF_TEXT
, &nmlvdi
.item
.pszText
, &nmlvdi
.item
.cchTextMax
,
1199 LVN_BEGINLABELEDITW
, LVN_BEGINLABELEDITA
, SET_NULL_IF_NO_MASK
| CONVERT_SEND
| CONVERT_RECEIVE
},
1200 {&nmlvdi
, sizeof(nmlvdi
), &nmlvdi
.item
.mask
, LVIF_TEXT
, &nmlvdi
.item
.pszText
, &nmlvdi
.item
.cchTextMax
,
1201 LVN_ENDLABELEDITW
, LVN_ENDLABELEDITA
, SET_NULL_IF_NO_MASK
| CONVERT_SEND
| CONVERT_RECEIVE
},
1202 {&nmlvdi
, sizeof(nmlvdi
), &nmlvdi
.item
.mask
, LVIF_TEXT
, &nmlvdi
.item
.pszText
, &nmlvdi
.item
.cchTextMax
,
1203 LVN_GETDISPINFOW
, LVN_GETDISPINFOA
, DONT_CONVERT_SEND
| CONVERT_RECEIVE
},
1204 {&nmlvdi
, sizeof(nmlvdi
), &nmlvdi
.item
.mask
, LVIF_TEXT
, &nmlvdi
.item
.pszText
, &nmlvdi
.item
.cchTextMax
,
1205 LVN_SETDISPINFOW
, LVN_SETDISPINFOA
, SET_NULL_IF_NO_MASK
| CONVERT_SEND
| CONVERT_RECEIVE
},
1206 {&nmlvgit
, sizeof(nmlvgit
), NULL
, 0, &nmlvgit
.pszText
, &nmlvgit
.cchTextMax
, LVN_GETINFOTIPW
, LVN_GETINFOTIPA
,
1207 CONVERT_SEND
| CONVERT_RECEIVE
},
1209 {&nmtbs
, sizeof(nmtbs
), NULL
, 0, (WCHAR
**)&nmtbs
.tbButton
.iString
, NULL
, TBN_SAVE
, TBN_SAVE
,
1210 DONT_CONVERT_SEND
| DONT_CONVERT_RECEIVE
},
1211 {&nmtbr
, sizeof(nmtbr
), NULL
, 0, (WCHAR
**)&nmtbr
.tbButton
.iString
, NULL
, TBN_RESTORE
, TBN_RESTORE
,
1212 DONT_CONVERT_SEND
| DONT_CONVERT_RECEIVE
},
1213 {&nmtbdi
, sizeof(nmtbdi
), &nmtbdi
.dwMask
, TBNF_TEXT
, &nmtbdi
.pszText
, &nmtbdi
.cchText
, TBN_GETDISPINFOW
,
1214 TBN_GETDISPINFOW
, DONT_CONVERT_SEND
| DONT_CONVERT_RECEIVE
},
1215 {&nmtb
, sizeof(nmtb
), NULL
, 0, &nmtb
.pszText
, &nmtb
.cchText
, TBN_GETBUTTONINFOW
, TBN_GETBUTTONINFOA
,
1216 SEND_EMPTY_IF_NULL
| CONVERT_SEND
| CONVERT_RECEIVE
},
1217 {&nmtbgit
, sizeof(nmtbgit
), NULL
, 0, &nmtbgit
.pszText
, &nmtbgit
.cchTextMax
, TBN_GETINFOTIPW
, TBN_GETINFOTIPA
,
1218 DONT_CONVERT_SEND
| CONVERT_RECEIVE
},
1220 {&nmtvdi
, sizeof(nmtvdi
), &nmtvdi
.item
.mask
, TVIF_TEXT
, &nmtvdi
.item
.pszText
, &nmtvdi
.item
.cchTextMax
,
1221 TVN_BEGINLABELEDITW
, TVN_BEGINLABELEDITA
, SET_NULL_IF_NO_MASK
| CONVERT_SEND
| CONVERT_RECEIVE
},
1222 {&nmtvdi
, sizeof(nmtvdi
), &nmtvdi
.item
.mask
, TVIF_TEXT
, &nmtvdi
.item
.pszText
, &nmtvdi
.item
.cchTextMax
,
1223 TVN_ENDLABELEDITW
, TVN_ENDLABELEDITA
, SET_NULL_IF_NO_MASK
| CONVERT_SEND
| CONVERT_RECEIVE
},
1224 {&nmtvdi
, sizeof(nmtvdi
), &nmtvdi
.item
.mask
, TVIF_TEXT
, &nmtvdi
.item
.pszText
, &nmtvdi
.item
.cchTextMax
,
1225 TVN_GETDISPINFOW
, TVN_GETDISPINFOA
, ZERO_SEND
| DONT_CONVERT_SEND
| CONVERT_RECEIVE
},
1226 {&nmtvdi
, sizeof(nmtvdi
), &nmtvdi
.item
.mask
, TVIF_TEXT
, &nmtvdi
.item
.pszText
, &nmtvdi
.item
.cchTextMax
,
1227 TVN_SETDISPINFOW
, TVN_SETDISPINFOA
, SET_NULL_IF_NO_MASK
| CONVERT_SEND
| CONVERT_RECEIVE
},
1228 {&nmtvgit
, sizeof(nmtvgit
), NULL
, 0, &nmtvgit
.pszText
, &nmtvgit
.cchTextMax
, TVN_GETINFOTIPW
, TVN_GETINFOTIPA
,
1229 DONT_CONVERT_SEND
| CONVERT_RECEIVE
},
1230 {&nmtv
, sizeof(nmtv
), &nmtv
.itemNew
.mask
, TVIF_TEXT
, &nmtv
.itemNew
.pszText
, &nmtv
.itemNew
.cchTextMax
,
1231 TVN_SINGLEEXPAND
, TVN_SINGLEEXPAND
, DONT_CONVERT_SEND
| DONT_CONVERT_RECEIVE
, TVITEM_NEW_HANDLER
},
1232 {&nmtv
, sizeof(nmtv
), &nmtv
.itemOld
.mask
, TVIF_TEXT
, &nmtv
.itemOld
.pszText
, &nmtv
.itemOld
.cchTextMax
,
1233 TVN_SINGLEEXPAND
, TVN_SINGLEEXPAND
, DONT_CONVERT_SEND
| DONT_CONVERT_RECEIVE
, TVITEM_OLD_HANDLER
},
1234 {&nmtv
, sizeof(nmtv
), &nmtv
.itemNew
.mask
, TVIF_TEXT
, &nmtv
.itemNew
.pszText
, &nmtv
.itemNew
.cchTextMax
,
1235 TVN_BEGINDRAGW
, TVN_BEGINDRAGA
, CONVERT_SEND
, TVITEM_NEW_HANDLER
},
1236 {&nmtv
, sizeof(nmtv
), &nmtv
.itemOld
.mask
, TVIF_TEXT
, &nmtv
.itemOld
.pszText
, &nmtv
.itemOld
.cchTextMax
,
1237 TVN_BEGINDRAGW
, TVN_BEGINDRAGA
, DONT_CONVERT_SEND
, TVITEM_OLD_HANDLER
},
1238 {&nmtv
, sizeof(nmtv
), &nmtv
.itemNew
.mask
, TVIF_TEXT
, &nmtv
.itemNew
.pszText
, &nmtv
.itemNew
.cchTextMax
,
1239 TVN_BEGINRDRAGW
, TVN_BEGINRDRAGA
, CONVERT_SEND
, TVITEM_NEW_HANDLER
},
1240 {&nmtv
, sizeof(nmtv
), &nmtv
.itemOld
.mask
, TVIF_TEXT
, &nmtv
.itemOld
.pszText
, &nmtv
.itemOld
.cchTextMax
,
1241 TVN_BEGINRDRAGW
, TVN_BEGINRDRAGA
, DONT_CONVERT_SEND
, TVITEM_OLD_HANDLER
},
1242 {&nmtv
, sizeof(nmtv
), &nmtv
.itemNew
.mask
, TVIF_TEXT
, &nmtv
.itemNew
.pszText
, &nmtv
.itemNew
.cchTextMax
,
1243 TVN_ITEMEXPANDEDW
, TVN_ITEMEXPANDEDA
, CONVERT_SEND
, TVITEM_NEW_HANDLER
},
1244 {&nmtv
, sizeof(nmtv
), &nmtv
.itemOld
.mask
, TVIF_TEXT
, &nmtv
.itemOld
.pszText
, &nmtv
.itemOld
.cchTextMax
,
1245 TVN_ITEMEXPANDEDW
, TVN_ITEMEXPANDEDA
, DONT_CONVERT_SEND
, TVITEM_OLD_HANDLER
},
1246 {&nmtv
, sizeof(nmtv
), &nmtv
.itemNew
.mask
, TVIF_TEXT
, &nmtv
.itemNew
.pszText
, &nmtv
.itemNew
.cchTextMax
,
1247 TVN_ITEMEXPANDINGW
, TVN_ITEMEXPANDINGA
, CONVERT_SEND
, TVITEM_NEW_HANDLER
},
1248 {&nmtv
, sizeof(nmtv
), &nmtv
.itemOld
.mask
, TVIF_TEXT
, &nmtv
.itemOld
.pszText
, &nmtv
.itemOld
.cchTextMax
,
1249 TVN_ITEMEXPANDINGW
, TVN_ITEMEXPANDINGA
, DONT_CONVERT_SEND
, TVITEM_OLD_HANDLER
},
1250 {&nmtv
, sizeof(nmtv
), &nmtv
.itemNew
.mask
, TVIF_TEXT
, &nmtv
.itemNew
.pszText
, &nmtv
.itemNew
.cchTextMax
,
1251 TVN_DELETEITEMW
, TVN_DELETEITEMA
, DONT_CONVERT_SEND
, TVITEM_NEW_HANDLER
},
1252 {&nmtv
, sizeof(nmtv
), &nmtv
.itemOld
.mask
, TVIF_TEXT
, &nmtv
.itemOld
.pszText
, &nmtv
.itemOld
.cchTextMax
,
1253 TVN_DELETEITEMW
, TVN_DELETEITEMA
, CONVERT_SEND
, TVITEM_OLD_HANDLER
},
1254 {&nmtv
, sizeof(nmtv
), &nmtv
.itemNew
.mask
, TVIF_TEXT
, &nmtv
.itemNew
.pszText
, &nmtv
.itemNew
.cchTextMax
,
1255 TVN_SELCHANGINGW
, TVN_SELCHANGINGA
, CONVERT_SEND
, TVITEM_NEW_HANDLER
},
1256 {&nmtv
, sizeof(nmtv
), &nmtv
.itemOld
.mask
, TVIF_TEXT
, &nmtv
.itemOld
.pszText
, &nmtv
.itemOld
.cchTextMax
,
1257 TVN_SELCHANGINGW
, TVN_SELCHANGINGA
, CONVERT_SEND
, TVITEM_OLD_HANDLER
},
1258 {&nmtv
, sizeof(nmtv
), &nmtv
.itemNew
.mask
, TVIF_TEXT
, &nmtv
.itemNew
.pszText
, &nmtv
.itemNew
.cchTextMax
,
1259 TVN_SELCHANGEDW
, TVN_SELCHANGEDA
, CONVERT_SEND
, TVITEM_NEW_HANDLER
},
1260 {&nmtv
, sizeof(nmtv
), &nmtv
.itemOld
.mask
, TVIF_TEXT
, &nmtv
.itemOld
.pszText
, &nmtv
.itemOld
.cchTextMax
,
1261 TVN_SELCHANGEDW
, TVN_SELCHANGEDA
, CONVERT_SEND
, TVITEM_OLD_HANDLER
}
1266 bret
= register_test_notify_class();
1267 ok(bret
, "Register test class failed, error 0x%08x\n", GetLastError());
1269 parent
= CreateWindowA(class, "parent", WS_OVERLAPPED
, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), 0);
1270 ok(parent
!= NULL
, "CreateWindow failed\n");
1271 pager
= CreateWindowA(WC_PAGESCROLLERA
, "pager", WS_CHILD
, 0, 0, 100, 100, parent
, 0, GetModuleHandleA(0), 0);
1272 ok(pager
!= NULL
, "CreateWindow failed\n");
1273 child1_wnd
= CreateWindowA(class, "child", WS_CHILD
, 0, 0, 100, 100, pager
, (HMENU
)1, GetModuleHandleA(0), 0);
1274 ok(child1_wnd
!= NULL
, "CreateWindow failed\n");
1275 SendMessageW(pager
, PGM_SETCHILD
, 0, (LPARAM
)child1_wnd
);
1277 for (i
= 0; i
< ARRAY_SIZE(paras
); i
++)
1278 test_notify_generic_text_helper(pager
, paras
+ i
);
1280 /* Tests for those that can't be covered by generic text test helper */
1281 test_wm_notify_comboboxex(pager
);
1282 test_wm_notify_datetime(pager
);
1283 test_wm_notify_header(pager
);
1284 test_wm_notify_tooltip(pager
);
1286 DestroyWindow(parent
);
1287 UnregisterClassA(class, GetModuleHandleA(NULL
));
1290 static void init_functions(void)
1292 HMODULE mod
= LoadLibraryA("comctl32.dll");
1294 #define X(f) p##f = (void*)GetProcAddress(mod, #f);
1295 X(InitCommonControlsEx
);
1298 pSetWindowSubclass
= (void*)GetProcAddress(mod
, (LPSTR
)410);
1303 INITCOMMONCONTROLSEX iccex
;
1307 iccex
.dwSize
= sizeof(iccex
);
1308 iccex
.dwICC
= ICC_PAGESCROLLER_CLASS
;
1309 pInitCommonControlsEx(&iccex
);
1311 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
1313 parent_wnd
= create_parent_window();
1314 ok(parent_wnd
!= NULL
, "Failed to create parent window!\n");
1317 test_wm_notifyformat();
1320 DestroyWindow(parent_wnd
);