1 /*
2  * Unit tests for the pager control
3  *
4  * Copyright 2012 Alexandre Julliard
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 #include <windows.h>
22 #include <commctrl.h>
23 
24 #include "wine/test.h"
25 #include "msg.h"
26 
27 #define NUM_MSG_SEQUENCES   1
28 #define PAGER_SEQ_INDEX     0
29 
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];
46 
47 /* Text field conversion test behavior flags. */
48 enum test_conversion_flags
49 {
50     CONVERT_SEND = 0x01,
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,
57     ZERO_SEND = 0x80
58 };
59 
60 enum handler_ids
61 {
62     TVITEM_NEW_HANDLER,
63     TVITEM_OLD_HANDLER
64 };
65 
66 static struct notify_test_info
67 {
68     UINT unicode;
69     UINT ansi;
70     UINT_PTR id_from;
71     HWND hwnd_from;
72     /* Whether parent received notification */
73     BOOL received;
74     UINT test_id;
75     UINT sub_test_id;
76     UINT handler_id;
77     /* Text field conversion test behavior flag */
78     DWORD flags;
79 } notify_test_info;
80 
81 struct notify_test_send
82 {
83     /* Data sent to pager */
84     const WCHAR *send_text;
85     INT send_text_size;
86     INT send_text_max;
87     /* Data expected by parent of pager */
88     const void *expect_text;
89 };
90 
91 struct notify_test_receive
92 {
93     /* Data sent to pager */
94     const WCHAR *send_text;
95     INT send_text_size;
96     INT send_text_max;
97     /* Data for parent to write */
98     const CHAR *write_pointer;
99     const CHAR *write_text;
100     INT write_text_size;
101     INT write_text_max;
102     /* Data when message returned */
103     const void *return_text;
104     INT return_text_max;
105 };
106 
107 struct generic_text_helper_para
108 {
109     void *ptr;
110     size_t size;
111     UINT *mask;
112     UINT required_mask;
113     WCHAR **text;
114     INT *text_max;
115     UINT code_unicode;
116     UINT code_ansi;
117     DWORD flags;
118     UINT handler_id;
119 };
120 
121 static const struct notify_test_send test_convert_send_data[] =
122 {
123     {test_w, sizeof(test_w), ARRAY_SIZE(buffer), test_a}
124 };
125 
126 static const struct notify_test_send test_dont_convert_send_data[] =
127 {
128     {test_w, sizeof(test_w), ARRAY_SIZE(buffer), test_w}
129 };
130 
131 static const struct notify_test_receive test_convert_receive_data[] =
132 {
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},
138 };
139 
140 static const struct notify_test_receive test_dont_convert_receive_data[] =
141 {
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)},
144 };
145 
146 static const struct notify_test_tooltip
147 {
148     /* Data for parent to write */
149     const CHAR *write_sztext;
150     INT write_sztext_size;
151     const CHAR *write_lpsztext;
152     HMODULE write_hinst;
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[] =
165 {
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}
176 };
177 
178 static const struct notify_test_datetime_format
179 {
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[] =
193 {
194     {test_w, test_a},
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}
199 };
200 
201 #define CHILD1_ID 1
202 #define CHILD2_ID 2
203 
204 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
205 static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
206 
207 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
208 
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 },
220     { 0 }
221 };
222 
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 },
238     { 0 }
239 };
240 
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.
251      *
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. */
262     { 0 }
263 };
264 
265 static const struct message set_pos_empty_seq[] = {
266     { PGM_SETPOS, sent },
267     { 0 }
268 };
269 
270 static CHAR *heap_strdup(const CHAR *str)
271 {
272     int len = lstrlenA(str) + 1;
273     CHAR *ret = heap_alloc(len * sizeof(CHAR));
274     lstrcpyA(ret, str);
275     return ret;
276 }
277 
278 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
279 {
280     static LONG defwndproc_counter = 0;
281     LRESULT ret;
282     struct message msg;
283 
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)
293     {
294         msg.message = message;
295         msg.flags = sent|wparam|lparam|parent;
296         if (defwndproc_counter) msg.flags |= defwinproc;
297         msg.wParam = wParam;
298         msg.lParam = lParam;
299         if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
300         add_message(sequences, PAGER_SEQ_INDEX, &msg);
301     }
302 
303     if (message == WM_NOTIFY)
304     {
305         NMHDR *nmhdr = (NMHDR *)lParam;
306 
307         switch (nmhdr->code)
308         {
309             case PGN_CALCSIZE:
310             {
311                 NMPGCALCSIZE *nmpgcs = (NMPGCALCSIZE *)lParam;
312                 DWORD style = GetWindowLongA(nmpgcs->hdr.hwndFrom, GWL_STYLE);
313 
314                 if (style & PGS_HORZ)
315                     ok(nmpgcs->dwFlag == PGF_CALCWIDTH, "Unexpected flags %#x.\n", nmpgcs->dwFlag);
316                 else
317                     ok(nmpgcs->dwFlag == PGF_CALCHEIGHT, "Unexpected flags %#x.\n", nmpgcs->dwFlag);
318                 break;
319             }
320             default:
321                 ;
322         }
323     }
324 
325     defwndproc_counter++;
326     ret = DefWindowProcA(hwnd, message, wParam, lParam);
327     defwndproc_counter--;
328 
329     return ret;
330 }
331 
332 static BOOL register_parent_wnd_class(void)
333 {
334     WNDCLASSA cls;
335 
336     cls.style = 0;
337     cls.lpfnWndProc = parent_wnd_proc;
338     cls.cbClsExtra = 0;
339     cls.cbWndExtra = 0;
340     cls.hInstance = GetModuleHandleA(NULL);
341     cls.hIcon = 0;
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);
347 }
348 
349 static HWND create_parent_window(void)
350 {
351     if (!register_parent_wnd_class())
352         return NULL;
353 
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 );
357 }
358 
359 static LRESULT WINAPI pager_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
360 {
361     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
362     struct message msg = { 0 };
363 
364     msg.message = message;
365     msg.flags = sent|wparam|lparam;
366     msg.wParam = wParam;
367     msg.lParam = lParam;
368     add_message(sequences, PAGER_SEQ_INDEX, &msg);
369     return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
370 }
371 
372 static HWND create_pager_control( DWORD style )
373 {
374     WNDPROC oldproc;
375     HWND hwnd;
376     RECT rect;
377 
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);
383     return hwnd;
384 }
385 
386 static LRESULT WINAPI child_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
387 {
388     static LONG defwndproc_counter;
389     struct message msg = { 0 };
390     LRESULT ret;
391 
392     msg.message = message;
393     msg.flags = sent | wparam | lparam;
394     if (defwndproc_counter)
395         msg.flags |= defwinproc;
396     msg.wParam = wParam;
397     msg.lParam = lParam;
398 
399     if (hwnd == child1_wnd)
400         msg.id = CHILD1_ID;
401     else if (hwnd == child2_wnd)
402         msg.id = CHILD2_ID;
403     else
404         msg.id = 0;
405 
406     add_message(sequences, PAGER_SEQ_INDEX, &msg);
407 
408     defwndproc_counter++;
409     ret = DefWindowProcA(hwnd, message, wParam, lParam);
410     defwndproc_counter--;
411 
412     return ret;
413 }
414 
415 static BOOL register_child_wnd_class(void)
416 {
417     WNDCLASSA cls;
418 
419     cls.style = 0;
420     cls.lpfnWndProc = child_proc;
421     cls.cbClsExtra = 0;
422     cls.cbWndExtra = 0;
423     cls.hInstance = GetModuleHandleA(NULL);
424     cls.hIcon = 0;
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);
430 }
431 
432 static void test_pager(void)
433 {
434     HWND pager;
435     RECT rect, rect2;
436 
437     pager = create_pager_control( PGS_HORZ );
438     ok(pager != NULL, "Fail to create pager\n");
439 
440     register_child_wnd_class();
441 
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);
446 
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 );
453 
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");
461 
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);
468 
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 );
475 
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);
479 
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);
483 
484     DestroyWindow( pager );
485 
486     /* Test if resizing works */
487     pager = create_pager_control( CCS_NORESIZE );
488     ok(pager != NULL, "failed to create pager control\n");
489 
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 ));
495 
496     DestroyWindow( pager );
497 
498     pager = create_pager_control( CCS_NORESIZE | PGS_HORZ );
499     ok(pager != NULL, "failed to create pager control\n");
500 
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 ));
506 
507     DestroyWindow( pager );
508 }
509 
510 static LRESULT WINAPI test_notifyformat_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
511 {
512     switch (message)
513     {
514     case WM_NOTIFYFORMAT:
515         if (lParam == NF_QUERY)
516         {
517             notify_query_received = TRUE;
518             return notify_format;
519         }
520         else if (lParam == NF_REQUERY)
521             return SendMessageA(GetParent(hwnd), WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
522         else
523             return 0;
524     default:
525         return notify_format == NFR_UNICODE ? DefWindowProcW(hwnd, message, wParam, lParam)
526                                             : DefWindowProcA(hwnd, message, wParam, lParam);
527     }
528 }
529 
530 static BOOL register_notifyformat_class(void)
531 {
532     static const WCHAR class_w[] = {'P', 'a', 'g', 'e', 'r', ' ', 'n', 'o', 't', 'i', 'f', 'y', 'f',
533                                    'o', 'r', 'm', 'a', 't', ' ', 'c', 'l', 'a', 's', 's', 0};
534     WNDCLASSW cls = {0};
535 
536     cls.lpfnWndProc = test_notifyformat_proc;
537     cls.hInstance = GetModuleHandleW(NULL);
538     cls.lpszClassName = class_w;
539     return RegisterClassW(&cls);
540 }
541 
542 static void test_wm_notifyformat(void)
543 {
544     static const WCHAR class_w[] = {'P', 'a', 'g', 'e', 'r', ' ', 'n', 'o', 't', 'i', 'f', 'y', 'f',
545                                     'o', 'r', 'm', 'a', 't', ' ', 'c', 'l', 'a', 's', 's', 0};
546     static const WCHAR parent_w[] = {'p', 'a', 'r', 'e', 'n', 't', 0};
547     static const WCHAR pager_w[] = {'p', 'a', 'g', 'e', 'r', 0};
548     static const WCHAR child_w[] = {'c', 'h', 'i', 'l', 'd', 0};
549     static const INT formats[] = {NFR_UNICODE, NFR_ANSI};
550     HWND parent, pager, child;
551     LRESULT ret;
552     BOOL bret;
553     INT i;
554 
555     bret = register_notifyformat_class();
556     ok(bret, "Register test class failed, error 0x%08x\n", GetLastError());
557 
558     for (i = 0; i < ARRAY_SIZE(formats); i++)
559     {
560         notify_format = formats[i];
561         parent = CreateWindowW(class_w, parent_w, WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, GetModuleHandleW(0), 0);
562         ok(parent != NULL, "CreateWindow failed\n");
563         pager = CreateWindowW(WC_PAGESCROLLERW, pager_w, WS_CHILD, 0, 0, 100, 100, parent, 0, GetModuleHandleW(0), 0);
564         ok(pager != NULL, "CreateWindow failed\n");
565         child = CreateWindowW(class_w, child_w, WS_CHILD, 0, 0, 100, 100, pager, 0, GetModuleHandleW(0), 0);
566         ok(child != NULL, "CreateWindow failed\n");
567         SendMessageW(pager, PGM_SETCHILD, 0, (LPARAM)child);
568 
569         /* Test parent */
570         notify_query_received = FALSE;
571         ret = SendMessageW(pager, WM_NOTIFYFORMAT, (WPARAM)parent, NF_REQUERY);
572         ok(ret == notify_format, "Expect %d, got %ld\n", notify_format, ret);
573         ok(notify_query_received, "Didn't receive notify\n");
574 
575         /* Send NF_QUERY directly to parent */
576         notify_query_received = FALSE;
577         ret = SendMessageW(parent, WM_NOTIFYFORMAT, (WPARAM)pager, NF_QUERY);
578         ok(ret == notify_format, "Expect %d, got %ld\n", notify_format, ret);
579         ok(notify_query_received, "Didn't receive notify\n");
580 
581         /* Pager send notifications to its parent regardless of wParam */
582         notify_query_received = FALSE;
583         ret = SendMessageW(pager, WM_NOTIFYFORMAT, (WPARAM)parent_wnd, NF_REQUERY);
584         ok(ret == notify_format, "Expect %d, got %ld\n", notify_format, ret);
585         ok(notify_query_received, "Didn't receive notify\n");
586 
587         /* Pager always wants Unicode notifications from children */
588         ret = SendMessageW(child, WM_NOTIFYFORMAT, (WPARAM)pager, NF_REQUERY);
589         ok(ret == NFR_UNICODE, "Expect %d, got %ld\n", NFR_UNICODE, ret);
590         ret = SendMessageW(pager, WM_NOTIFYFORMAT, (WPARAM)child, NF_QUERY);
591         ok(ret == NFR_UNICODE, "Expect %d, got %ld\n", NFR_UNICODE, ret);
592 
593         DestroyWindow(parent);
594     }
595 
596     UnregisterClassW(class_w, GetModuleHandleW(NULL));
597 }
598 
599 static void notify_generic_text_handler(CHAR **text, INT *text_max)
600 {
601     const struct notify_test_send *send_data;
602     const struct notify_test_receive *receive_data;
603 
604     switch (notify_test_info.test_id)
605     {
606     case CONVERT_SEND:
607     case DONT_CONVERT_SEND:
608     {
609         send_data = (notify_test_info.test_id == CONVERT_SEND ? test_convert_send_data : test_dont_convert_send_data)
610                     + notify_test_info.sub_test_id;
611         if (notify_test_info.flags & ZERO_SEND)
612             ok(!*text[0], "Code 0x%08x test 0x%08x sub test %d expect empty text, got %s\n",
613                notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, *text);
614         else if (notify_test_info.flags & CONVERT_SEND)
615             ok(!lstrcmpA(send_data->expect_text, *text), "Code 0x%08x test 0x%08x sub test %d expect %s, got %s\n",
616                notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id,
617                (CHAR *)send_data->expect_text, *text);
618         else
619             ok(!lstrcmpW((WCHAR *)send_data->expect_text, (WCHAR *)*text),
620                "Code 0x%08x test 0x%08x sub test %d expect %s, got %s\n", notify_test_info.unicode,
621                notify_test_info.test_id, notify_test_info.sub_test_id, wine_dbgstr_w((WCHAR *)send_data->expect_text),
622                wine_dbgstr_w((WCHAR *)*text));
623         if (text_max)
624             ok(*text_max == send_data->send_text_max, "Code 0x%08x test 0x%08x sub test %d expect %d, got %d\n",
625                notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id,
626                send_data->send_text_max, *text_max);
627         break;
628     }
629     case CONVERT_RECEIVE:
630     case DONT_CONVERT_RECEIVE:
631     {
632         receive_data = (notify_test_info.test_id == CONVERT_RECEIVE ? test_convert_receive_data : test_dont_convert_receive_data)
633                        + notify_test_info.sub_test_id;
634         if (text_max)
635             ok(*text_max == receive_data->send_text_max, "Code 0x%08x test 0x%08x sub test %d expect %d, got %d\n",
636                notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id,
637                receive_data->send_text_max, *text_max);
638 
639         if (receive_data->write_text)
640             memcpy(*text, receive_data->write_text, receive_data->write_text_size);
641         /* 64bit Windows will try to free the text pointer even if it's application provided when handling
642          * HDN_GETDISPINFOW. Deliberate leak here. */
643         else if(notify_test_info.unicode == HDN_GETDISPINFOW)
644             *text = heap_strdup(receive_data->write_pointer);
645         else
646             *text = (char *)receive_data->write_pointer;
647         if (text_max && receive_data->write_text_max != -1) *text_max = receive_data->write_text_max;
648         break;
649     }
650     case SEND_EMPTY_IF_NULL:
651         ok(!*text[0], "Code 0x%08x test 0x%08x sub test %d expect empty text, got %s\n",
652            notify_test_info.unicode, notify_test_info.test_id, notify_test_info.sub_test_id, *text);
653         break;
654     case DONT_SEND_EMPTY_IF_NULL:
655         ok(!*text, "Code 0x%08x test 0x%08x sub test %d expect null text\n", notify_test_info.unicode,
656            notify_test_info.test_id, notify_test_info.sub_test_id);
657         break;
658     }
659 }
660 
661 static void notify_tooltip_handler(NMTTDISPINFOA *nm)
662 {
663     const struct notify_test_tooltip *data = test_tooltip_data + notify_test_info.sub_test_id;
664     ok(nm->lpszText == nm->szText, "Sub test %d expect %p, got %p\n", notify_test_info.sub_test_id, nm->szText,
665        nm->lpszText);
666     if (data->expect_sztext)
667         ok(!lstrcmpA(data->expect_sztext, nm->szText), "Sub test %d expect %s, got %s\n", notify_test_info.sub_test_id,
668            data->expect_sztext, nm->szText);
669     if (data->write_sztext) memcpy(nm->szText, data->write_sztext, data->write_sztext_size);
670     if (data->write_lpsztext) nm->lpszText = (char *)data->write_lpsztext;
671     if (data->write_hinst) nm->hinst = data->write_hinst;
672 }
673 
674 static void notify_datetime_handler(NMDATETIMEFORMATA *nm)
675 {
676     const struct notify_test_datetime_format *data = test_datetime_format_data + notify_test_info.sub_test_id;
677     if (data->expect_pszformat)
678         ok(!lstrcmpA(data->expect_pszformat, nm->pszFormat), "Sub test %d expect %s, got %s\n",
679            notify_test_info.sub_test_id, data->expect_pszformat, nm->pszFormat);
680     ok(nm->pszDisplay == nm->szDisplay, "Test %d expect %p, got %p\n", notify_test_info.sub_test_id, nm->szDisplay,
681        nm->pszDisplay);
682     if (data->write_szdisplay) memcpy(nm->szDisplay, data->write_szdisplay, data->write_szdisplay_size);
683     if (data->write_pszdisplay) nm->pszDisplay = data->write_pszdisplay;
684 }
685 
686 static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
687 {
688     static const WCHAR test[] = {'t', 'e', 's', 't', 0};
689     switch (message)
690     {
691     case WM_NOTIFY:
692     {
693         NMHDR *hdr = (NMHDR *)lParam;
694 
695         /* Not notifications we want to test */
696         if (!notify_test_info.unicode) break;
697         ok(!notify_test_info.received, "Extra notification received\n");
698 
699         ok(wParam == notify_test_info.id_from, "Expect %ld, got %ld\n", notify_test_info.id_from, wParam);
700         ok(hdr->code == notify_test_info.ansi, "Expect 0x%08x, got 0x%08x\n", notify_test_info.ansi, hdr->code);
701         ok(hdr->idFrom == notify_test_info.id_from, "Expect %ld, got %ld\n", notify_test_info.id_from, wParam);
702         ok(hdr->hwndFrom == notify_test_info.hwnd_from, "Expect %p, got %p\n", notify_test_info.hwnd_from, hdr->hwndFrom);
703 
704         if (hdr->code != notify_test_info.ansi)
705         {
706             skip("Notification code mismatch, skipping lParam check\n");
707             return 0;
708         }
709         switch (hdr->code)
710         {
711         /* ComboBoxEx */
712         case CBEN_INSERTITEM:
713         case CBEN_DELETEITEM:
714         {
715             NMCOMBOBOXEXW *nmcbe = (NMCOMBOBOXEXW *)hdr;
716             notify_generic_text_handler((CHAR **)&nmcbe->ceItem.pszText, NULL);
717             break;
718         }
719         case CBEN_DRAGBEGINA:
720         {
721             NMCBEDRAGBEGINA *nmcbedb = (NMCBEDRAGBEGINA *)hdr;
722             ok(!lstrcmpA(nmcbedb->szText, test_a), "Expect %s, got %s\n", nmcbedb->szText, test_a);
723             break;
724         }
725         case CBEN_ENDEDITA:
726         {
727             NMCBEENDEDITA *nmcbeed = (NMCBEENDEDITA *)hdr;
728             ok(!lstrcmpA(nmcbeed->szText, test_a), "Expect %s, got %s\n", nmcbeed->szText, test_a);
729             break;
730         }
731         case CBEN_GETDISPINFOA:
732         {
733             NMCOMBOBOXEXA *nmcbe = (NMCOMBOBOXEXA *)hdr;
734             notify_generic_text_handler(&nmcbe->ceItem.pszText, &nmcbe->ceItem.cchTextMax);
735             break;
736         }
737         /* Date and Time Picker */
738         case DTN_FORMATA:
739         {
740             notify_datetime_handler((NMDATETIMEFORMATA *)hdr);
741             break;
742         }
743         case DTN_FORMATQUERYA:
744         {
745             NMDATETIMEFORMATQUERYA *nmdtfq = (NMDATETIMEFORMATQUERYA *)hdr;
746             notify_generic_text_handler((CHAR **)&nmdtfq->pszFormat, NULL);
747             break;
748         }
749         case DTN_WMKEYDOWNA:
750         {
751             NMDATETIMEWMKEYDOWNA *nmdtkd = (NMDATETIMEWMKEYDOWNA *)hdr;
752             notify_generic_text_handler((CHAR **)&nmdtkd->pszFormat, NULL);
753             break;
754         }
755         case DTN_USERSTRINGA:
756         {
757             NMDATETIMESTRINGA *nmdts = (NMDATETIMESTRINGA *)hdr;
758             notify_generic_text_handler((CHAR **)&nmdts->pszUserString, NULL);
759             break;
760         }
761         /* Header */
762         case HDN_BEGINDRAG:
763         case HDN_ENDDRAG:
764         case HDN_BEGINFILTEREDIT:
765         case HDN_ENDFILTEREDIT:
766         case HDN_DROPDOWN:
767         case HDN_FILTERCHANGE:
768         case HDN_ITEMKEYDOWN:
769         case HDN_ITEMSTATEICONCLICK:
770         case HDN_OVERFLOWCLICK:
771         {
772             NMHEADERW *nmhd = (NMHEADERW *)hdr;
773             ok(!lstrcmpW(nmhd->pitem->pszText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w),
774                wine_dbgstr_w(nmhd->pitem->pszText));
775             ok(!lstrcmpW(((HD_TEXTFILTERW *)nmhd->pitem->pvFilter)->pszText, test_w), "Expect %s, got %s\n",
776                wine_dbgstr_w(test_w), wine_dbgstr_w(((HD_TEXTFILTERW *)nmhd->pitem->pvFilter)->pszText));
777             break;
778         }
779         case HDN_BEGINTRACKA:
780         case HDN_DIVIDERDBLCLICKA:
781         case HDN_ENDTRACKA:
782         case HDN_ITEMCHANGEDA:
783         case HDN_ITEMCHANGINGA:
784         case HDN_ITEMCLICKA:
785         case HDN_ITEMDBLCLICKA:
786         case HDN_TRACKA:
787         {
788             NMHEADERA *nmhd = (NMHEADERA *)hdr;
789             ok(!lstrcmpA(nmhd->pitem->pszText, test_a), "Expect %s, got %s\n", test_a, nmhd->pitem->pszText);
790             ok(!lstrcmpA(((HD_TEXTFILTERA *)nmhd->pitem->pvFilter)->pszText, test_a), "Expect %s, got %s\n", test_a,
791                ((HD_TEXTFILTERA *)nmhd->pitem->pvFilter)->pszText);
792             break;
793         }
794         case HDN_GETDISPINFOA:
795         {
796             NMHDDISPINFOA *nmhddi = (NMHDDISPINFOA *)hdr;
797             notify_generic_text_handler(&nmhddi->pszText, &nmhddi->cchTextMax);
798             break;
799         }
800         /* List View */
801         case LVN_BEGINLABELEDITA:
802         case LVN_ENDLABELEDITA:
803         case LVN_GETDISPINFOA:
804         case LVN_SETDISPINFOA:
805         {
806             NMLVDISPINFOA *nmlvdi = (NMLVDISPINFOA *)hdr;
807             notify_generic_text_handler(&nmlvdi->item.pszText, &nmlvdi->item.cchTextMax);
808             break;
809         }
810         case LVN_GETINFOTIPA:
811         {
812             NMLVGETINFOTIPA *nmlvgit = (NMLVGETINFOTIPA *)hdr;
813             notify_generic_text_handler(&nmlvgit->pszText, &nmlvgit->cchTextMax);
814             break;
815         }
816         case LVN_INCREMENTALSEARCHA:
817         case LVN_ODFINDITEMA:
818         {
819             NMLVFINDITEMA *nmlvfi = (NMLVFINDITEMA *)hdr;
820             notify_generic_text_handler((CHAR **)&nmlvfi->lvfi.psz, NULL);
821             break;
822         }
823         /* Toolbar */
824         case TBN_SAVE:
825         {
826             NMTBSAVE *nmtbs = (NMTBSAVE *)hdr;
827             notify_generic_text_handler((CHAR **)&nmtbs->tbButton.iString, NULL);
828             break;
829         }
830         case TBN_RESTORE:
831         {
832             NMTBRESTORE *nmtbr = (NMTBRESTORE *)hdr;
833             notify_generic_text_handler((CHAR **)&nmtbr->tbButton.iString, NULL);
834             break;
835         }
836         case TBN_GETBUTTONINFOA:
837         {
838             NMTOOLBARA *nmtb = (NMTOOLBARA *)hdr;
839             notify_generic_text_handler(&nmtb->pszText, &nmtb->cchText);
840             break;
841         }
842         case TBN_GETDISPINFOW:
843         {
844             NMTBDISPINFOW *nmtbdi = (NMTBDISPINFOW *)hdr;
845             notify_generic_text_handler((CHAR **)&nmtbdi->pszText, &nmtbdi->cchText);
846             break;
847         }
848         case TBN_GETINFOTIPA:
849         {
850             NMTBGETINFOTIPA *nmtbgit = (NMTBGETINFOTIPA *)hdr;
851             notify_generic_text_handler(&nmtbgit->pszText, &nmtbgit->cchTextMax);
852             break;
853         }
854         /* Tooltip */
855         case TTN_GETDISPINFOA:
856         {
857             notify_tooltip_handler((NMTTDISPINFOA *)hdr);
858             break;
859         }
860         /* Tree View */
861         case TVN_BEGINLABELEDITA:
862         case TVN_ENDLABELEDITA:
863         case TVN_GETDISPINFOA:
864         case TVN_SETDISPINFOA:
865         {
866             NMTVDISPINFOA *nmtvdi = (NMTVDISPINFOA *)hdr;
867             notify_generic_text_handler(&nmtvdi->item.pszText, &nmtvdi->item.cchTextMax);
868             break;
869         }
870         case TVN_GETINFOTIPA:
871         {
872             NMTVGETINFOTIPA *nmtvgit = (NMTVGETINFOTIPA *)hdr;
873             notify_generic_text_handler(&nmtvgit->pszText, &nmtvgit->cchTextMax);
874             break;
875         }
876         case TVN_SINGLEEXPAND:
877         case TVN_BEGINDRAGA:
878         case TVN_BEGINRDRAGA:
879         case TVN_ITEMEXPANDEDA:
880         case TVN_ITEMEXPANDINGA:
881         case TVN_DELETEITEMA:
882         case TVN_SELCHANGINGA:
883         case TVN_SELCHANGEDA:
884         {
885             NMTREEVIEWA *nmtv = (NMTREEVIEWA *)hdr;
886             if (notify_test_info.handler_id == TVITEM_NEW_HANDLER)
887                 notify_generic_text_handler((CHAR **)&nmtv->itemNew.pszText, &nmtv->itemNew.cchTextMax);
888             else
889                 notify_generic_text_handler((CHAR **)&nmtv->itemOld.pszText, &nmtv->itemOld.cchTextMax);
890             break;
891         }
892 
893         default:
894             ok(0, "Unexpected message 0x%08x\n", hdr->code);
895         }
896         notify_test_info.received = TRUE;
897         ok(!lstrcmpA(test_a, "test"), "test_a got modified\n");
898         ok(!lstrcmpW(test_w, test), "test_w got modified\n");
899         return 0;
900     }
901     case WM_NOTIFYFORMAT:
902         if (lParam == NF_QUERY) return NFR_ANSI;
903         break;
904     }
905     return DefWindowProcA(hwnd, message, wParam, lParam);
906 }
907 
908 static BOOL register_test_notify_class(void)
909 {
910     WNDCLASSA cls = {0};
911 
912     cls.lpfnWndProc = test_notify_proc;
913     cls.hInstance = GetModuleHandleA(NULL);
914     cls.lpszClassName = "Pager notify class";
915     return RegisterClassA(&cls);
916 }
917 
918 static void send_notify(HWND pager, UINT unicode, UINT ansi, LPARAM lParam, BOOL code_change)
919 {
920     NMHDR *hdr = (NMHDR *)lParam;
921 
922     notify_test_info.unicode = unicode;
923     notify_test_info.id_from = 1;
924     notify_test_info.hwnd_from = child1_wnd;
925     notify_test_info.ansi = ansi;
926     notify_test_info.received = FALSE;
927 
928     hdr->code = unicode;
929     hdr->idFrom = 1;
930     hdr->hwndFrom = child1_wnd;
931 
932     SendMessageW(pager, WM_NOTIFY, hdr->idFrom, lParam);
933     ok(notify_test_info.received, "Expect notification received\n");
934     ok(hdr->code == code_change ? ansi : unicode, "Expect 0x%08x, got 0x%08x\n", hdr->code,
935        code_change ? ansi : unicode);
936 }
937 
938 /* Send notify to test text field conversion. In parent proc notify_generic_text_handler() handles these messages */
939 static void test_notify_generic_text_helper(HWND pager, const struct generic_text_helper_para *para)
940 {
941     const struct notify_test_send *send_data;
942     const struct notify_test_receive *receive_data;
943     INT array_size;
944     INT i;
945 
946     notify_test_info.flags = para->flags;
947     notify_test_info.handler_id = para->handler_id;
948 
949     if (para->flags & (CONVERT_SEND | DONT_CONVERT_SEND))
950     {
951         if (para->flags & CONVERT_SEND)
952         {
953             notify_test_info.test_id = CONVERT_SEND;
954             send_data = test_convert_send_data;
955             array_size = ARRAY_SIZE(test_convert_send_data);
956         }
957         else
958         {
959             notify_test_info.test_id = DONT_CONVERT_SEND;
960             send_data = test_dont_convert_send_data;
961             array_size = ARRAY_SIZE(test_dont_convert_send_data);
962         }
963 
964         for (i = 0; i < array_size; i++)
965         {
966             const struct notify_test_send *data = send_data + i;
967             notify_test_info.sub_test_id = i;
968 
969             memset(para->ptr, 0, para->size);
970             if (para->mask) *para->mask = para->required_mask;
971             if (data->send_text)
972             {
973                 memcpy(buffer, data->send_text, data->send_text_size);
974                 *para->text = buffer;
975             }
976             if (para->text_max) *para->text_max = data->send_text_max;
977             send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE);
978         }
979     }
980 
981     if (para->flags & (CONVERT_RECEIVE | DONT_CONVERT_RECEIVE))
982     {
983         if (para->flags & CONVERT_RECEIVE)
984         {
985             notify_test_info.test_id = CONVERT_RECEIVE;
986             receive_data = test_convert_receive_data;
987             array_size = ARRAY_SIZE(test_convert_receive_data);
988         }
989         else
990         {
991             notify_test_info.test_id = DONT_CONVERT_RECEIVE;
992             receive_data = test_dont_convert_receive_data;
993             array_size = ARRAY_SIZE(test_dont_convert_receive_data);
994         }
995 
996         for (i = 0; i < array_size; i++)
997         {
998             const struct notify_test_receive *data = receive_data + i;
999             notify_test_info.sub_test_id = i;
1000 
1001             memset(para->ptr, 0, para->size);
1002             if (para->mask) *para->mask = para->required_mask;
1003             if (data->send_text)
1004             {
1005                 memcpy(buffer, data->send_text, data->send_text_size);
1006                 *para->text = buffer;
1007             }
1008             if (para->text_max) *para->text_max = data->send_text_max;
1009             send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE);
1010             if (data->return_text)
1011             {
1012                 if (para->flags & CONVERT_RECEIVE)
1013                     ok(!wcsncmp(data->return_text, *para->text, *para->text_max),
1014                        "Code 0x%08x sub test %d expect %s, got %s\n", para->code_unicode, i,
1015                        wine_dbgstr_w((WCHAR *)data->return_text), wine_dbgstr_w(*para->text));
1016                 else
1017                     ok(!lstrcmpA(data->return_text, (CHAR *)*para->text), "Code 0x%08x sub test %d expect %s, got %s\n",
1018                        para->code_unicode, i, (CHAR *)data->return_text, (CHAR *)*para->text);
1019             }
1020             if (para->text_max)
1021                 ok(data->return_text_max == *para->text_max, "Code 0x%08x sub test %d expect %d, got %d\n",
1022                    para->code_unicode, i, data->return_text_max, *para->text_max);
1023         }
1024     }
1025 
1026     /* Extra tests for other behavior flags that are not worth it to create their own test arrays */
1027     memset(para->ptr, 0, para->size);
1028     if (para->mask) *para->mask = para->required_mask;
1029     if (para->text_max) *para->text_max = 1;
1030     if (para->flags & SEND_EMPTY_IF_NULL)
1031         notify_test_info.test_id = SEND_EMPTY_IF_NULL;
1032     else
1033         notify_test_info.test_id = DONT_SEND_EMPTY_IF_NULL;
1034     send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE);
1035 
1036     notify_test_info.test_id = SET_NULL_IF_NO_MASK;
1037     memset(para->ptr, 0, para->size);
1038     memset(buffer, 0, sizeof(buffer));
1039     *para->text = buffer;
1040     if (para->text_max) *para->text_max = ARRAY_SIZE(buffer);
1041     send_notify(pager, para->code_unicode, para->code_ansi, (LPARAM)para->ptr, TRUE);
1042     if(para->flags & SET_NULL_IF_NO_MASK)
1043         ok(!*para->text, "Expect null text\n");
1044 }
1045 
1046 static void test_wm_notify_comboboxex(HWND pager)
1047 {
1048     static NMCBEDRAGBEGINW nmcbedb;
1049     static NMCBEENDEDITW nmcbeed;
1050 
1051     /* CBEN_DRAGBEGIN */
1052     memset(&nmcbedb, 0, sizeof(nmcbedb));
1053     memcpy(nmcbedb.szText, test_w, sizeof(test_w));
1054     send_notify(pager, CBEN_DRAGBEGINW, CBEN_DRAGBEGINA, (LPARAM)&nmcbedb, FALSE);
1055     ok(!lstrcmpW(nmcbedb.szText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w), wine_dbgstr_w(nmcbedb.szText));
1056 
1057     /* CBEN_ENDEDIT */
1058     memset(&nmcbeed, 0, sizeof(nmcbeed));
1059     memcpy(nmcbeed.szText, test_w, sizeof(test_w));
1060     send_notify(pager, CBEN_ENDEDITW, CBEN_ENDEDITA, (LPARAM)&nmcbeed, FALSE);
1061     ok(!lstrcmpW(nmcbeed.szText, test_w), "Expect %s, got %s\n", wine_dbgstr_w(test_w), wine_dbgstr_w(nmcbeed.szText));
1062 }
1063 
1064 static void test_wm_notify_datetime(HWND pager)
1065 {
1066     const struct notify_test_datetime_format *data;
1067     NMDATETIMEFORMATW nmdtf;
1068     INT i;
1069 
1070     for (i = 0; i < ARRAY_SIZE(test_datetime_format_data); i++)
1071     {
1072         data = test_datetime_format_data + i;
1073         notify_test_info.sub_test_id = i;
1074 
1075         memset(&nmdtf, 0, sizeof(nmdtf));
1076         if(data->send_pszformat) nmdtf.pszFormat = data->send_pszformat;
1077         nmdtf.pszDisplay = nmdtf.szDisplay;
1078         send_notify(pager, DTN_FORMATW, DTN_FORMATA, (LPARAM)&nmdtf, TRUE);
1079         if (data->return_szdisplay)
1080             ok(!lstrcmpW(nmdtf.szDisplay, data->return_szdisplay), "Sub test %d expect %s, got %s\n", i,
1081                wine_dbgstr_w(data->return_szdisplay), wine_dbgstr_w(nmdtf.szDisplay));
1082         if (data->return_pszdisplay)
1083             ok(!lstrcmpW(nmdtf.pszDisplay, data->return_pszdisplay), "Sub test %d expect %s, got %s\n", i,
1084                wine_dbgstr_w(data->return_pszdisplay), wine_dbgstr_w(nmdtf.pszDisplay));
1085     }
1086 }
1087 
1088 static void test_wm_notify_header(HWND pager)
1089 {
1090     NMHEADERW nmh = {{0}};
1091     HDITEMW hdi = {0};
1092     HD_TEXTFILTERW hdtf = {0};
1093 
1094     hdi.mask = HDI_TEXT | HDI_FILTER;
1095     hdi.pszText = (WCHAR *)test_w;
1096     hdtf.pszText = (WCHAR *)test_w;
1097     nmh.pitem = &hdi;
1098     nmh.pitem->pvFilter = &hdtf;
1099     send_notify(pager, HDN_BEGINDRAG, HDN_BEGINDRAG, (LPARAM)&nmh, TRUE);
1100     send_notify(pager, HDN_ENDDRAG, HDN_ENDDRAG, (LPARAM)&nmh, TRUE);
1101     send_notify(pager, HDN_BEGINFILTEREDIT, HDN_BEGINFILTEREDIT, (LPARAM)&nmh, TRUE);
1102     send_notify(pager, HDN_ENDFILTEREDIT, HDN_ENDFILTEREDIT, (LPARAM)&nmh, TRUE);
1103     send_notify(pager, HDN_DROPDOWN, HDN_DROPDOWN, (LPARAM)&nmh, TRUE);
1104     send_notify(pager, HDN_FILTERCHANGE, HDN_FILTERCHANGE, (LPARAM)&nmh, TRUE);
1105     send_notify(pager, HDN_ITEMKEYDOWN, HDN_ITEMKEYDOWN, (LPARAM)&nmh, TRUE);
1106     send_notify(pager, HDN_ITEMSTATEICONCLICK, HDN_ITEMSTATEICONCLICK, (LPARAM)&nmh, TRUE);
1107     send_notify(pager, HDN_OVERFLOWCLICK, HDN_OVERFLOWCLICK, (LPARAM)&nmh, TRUE);
1108     send_notify(pager, HDN_BEGINTRACKW, HDN_BEGINTRACKA, (LPARAM)&nmh, TRUE);
1109     send_notify(pager, HDN_DIVIDERDBLCLICKW, HDN_DIVIDERDBLCLICKA, (LPARAM)&nmh, TRUE);
1110     send_notify(pager, HDN_ENDTRACKW, HDN_ENDTRACKA, (LPARAM)&nmh, TRUE);
1111     send_notify(pager, HDN_ITEMCHANGEDW, HDN_ITEMCHANGEDA, (LPARAM)&nmh, TRUE);
1112     send_notify(pager, HDN_ITEMCHANGINGW, HDN_ITEMCHANGINGA, (LPARAM)&nmh, TRUE);
1113     send_notify(pager, HDN_ITEMCLICKW, HDN_ITEMCLICKA, (LPARAM)&nmh, TRUE);
1114     send_notify(pager, HDN_ITEMDBLCLICKW, HDN_ITEMDBLCLICKA, (LPARAM)&nmh, TRUE);
1115     send_notify(pager, HDN_TRACKW, HDN_TRACKA, (LPARAM)&nmh, TRUE);
1116 }
1117 
1118 static void test_wm_notify_tooltip(HWND pager)
1119 {
1120     NMTTDISPINFOW nmttdi;
1121     const struct notify_test_tooltip *data;
1122     INT i;
1123 
1124     for (i = 0; i < ARRAY_SIZE(test_tooltip_data); i++)
1125     {
1126         data = test_tooltip_data + i;
1127         notify_test_info.sub_test_id = i;
1128 
1129         memset(&nmttdi, 0, sizeof(nmttdi));
1130         if (data->send_sztext) memcpy(nmttdi.szText, data->send_sztext, data->send_sztext_size);
1131         if (data->send_lpsztext) nmttdi.lpszText = (WCHAR *)data->send_lpsztext;
1132         send_notify(pager, TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE);
1133         if (data->return_sztext)
1134         {
1135             if (data->return_sztext_size == -1)
1136                 ok(!lstrcmpW(nmttdi.szText, data->return_sztext), "Sub test %d expect %s, got %s\n", i,
1137                    wine_dbgstr_w(data->return_sztext), wine_dbgstr_w(nmttdi.szText));
1138             else
1139                 ok(!memcmp(nmttdi.szText, data->return_sztext, data->return_sztext_size), "Wrong szText content\n");
1140         }
1141         if (data->return_lpsztext)
1142         {
1143             if (IS_INTRESOURCE(data->return_lpsztext))
1144                 ok(nmttdi.lpszText == data->return_lpsztext, "Sub test %d expect %s, got %s\n", i,
1145                    wine_dbgstr_w(data->return_lpsztext), wine_dbgstr_w(nmttdi.lpszText));
1146             else
1147                 ok(!lstrcmpW(nmttdi.lpszText, data->return_lpsztext), "Test %d expect %s, got %s\n", i,
1148                    wine_dbgstr_w(data->return_lpsztext), wine_dbgstr_w(nmttdi.lpszText));
1149         }
1150         if (data->return_hinst)
1151             ok(nmttdi.hinst == data->return_hinst, "Sub test %d expect %p, got %p\n", i, data->return_hinst,
1152                nmttdi.hinst);
1153     }
1154 }
1155 
1156 static void test_wm_notify(void)
1157 {
1158     static const CHAR *class = "Pager notify class";
1159     HWND parent, pager;
1160     /* Combo Box Ex */
1161     static NMCOMBOBOXEXW nmcbe;
1162     /* Date and Time Picker */
1163     static NMDATETIMEFORMATQUERYW nmdtfq;
1164     static NMDATETIMEWMKEYDOWNW nmdtkd;
1165     static NMDATETIMESTRINGW nmdts;
1166     /* Header */
1167     static NMHDDISPINFOW nmhddi;
1168     /* List View */
1169     static NMLVDISPINFOW nmlvdi;
1170     static NMLVGETINFOTIPW nmlvgit;
1171     static NMLVFINDITEMW nmlvfi;
1172     /* Tool Bar */
1173     static NMTBRESTORE nmtbr;
1174     static NMTBSAVE nmtbs;
1175     static NMTOOLBARW nmtb;
1176     static NMTBDISPINFOW nmtbdi;
1177     static NMTBGETINFOTIPW nmtbgit;
1178     /* Tree View */
1179     static NMTVDISPINFOW nmtvdi;
1180     static NMTVGETINFOTIPW nmtvgit;
1181     static NMTREEVIEWW nmtv;
1182     static const struct generic_text_helper_para paras[] =
1183     {
1184         /* Combo Box Ex */
1185         {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax,
1186          CBEN_INSERTITEM, CBEN_INSERTITEM, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE},
1187         {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax,
1188          CBEN_DELETEITEM, CBEN_DELETEITEM, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE},
1189         {&nmcbe, sizeof(nmcbe), &nmcbe.ceItem.mask, CBEIF_TEXT, &nmcbe.ceItem.pszText, &nmcbe.ceItem.cchTextMax,
1190          CBEN_GETDISPINFOW, CBEN_GETDISPINFOA, ZERO_SEND | SET_NULL_IF_NO_MASK | DONT_CONVERT_SEND | CONVERT_RECEIVE},
1191         /* Date and Time Picker */
1192         {&nmdtfq, sizeof(nmdtfq), NULL, 0, (WCHAR **)&nmdtfq.pszFormat, NULL, DTN_FORMATQUERYW, DTN_FORMATQUERYA,
1193          CONVERT_SEND},
1194         {&nmdtkd, sizeof(nmdtkd), NULL, 0, (WCHAR **)&nmdtkd.pszFormat, NULL, DTN_WMKEYDOWNW, DTN_WMKEYDOWNA,
1195          CONVERT_SEND},
1196         {&nmdts, sizeof(nmdts), NULL, 0, (WCHAR **)&nmdts.pszUserString, NULL, DTN_USERSTRINGW, DTN_USERSTRINGA,
1197          CONVERT_SEND},
1198         /* Header */
1199         {&nmhddi, sizeof(nmhddi), &nmhddi.mask, HDI_TEXT, &nmhddi.pszText, &nmhddi.cchTextMax, HDN_GETDISPINFOW,
1200          HDN_GETDISPINFOA, SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE},
1201         /* List View */
1202         {&nmlvfi, sizeof(nmlvfi), &nmlvfi.lvfi.flags, LVFI_STRING, (WCHAR **)&nmlvfi.lvfi.psz, NULL,
1203          LVN_INCREMENTALSEARCHW, LVN_INCREMENTALSEARCHA, CONVERT_SEND},
1204         {&nmlvfi, sizeof(nmlvfi), &nmlvfi.lvfi.flags, LVFI_SUBSTRING, (WCHAR **)&nmlvfi.lvfi.psz, NULL, LVN_ODFINDITEMW,
1205          LVN_ODFINDITEMA, CONVERT_SEND},
1206         {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax,
1207          LVN_BEGINLABELEDITW, LVN_BEGINLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE},
1208         {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax,
1209          LVN_ENDLABELEDITW, LVN_ENDLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE},
1210         {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax,
1211          LVN_GETDISPINFOW, LVN_GETDISPINFOA, DONT_CONVERT_SEND | CONVERT_RECEIVE},
1212         {&nmlvdi, sizeof(nmlvdi), &nmlvdi.item.mask, LVIF_TEXT, &nmlvdi.item.pszText, &nmlvdi.item.cchTextMax,
1213          LVN_SETDISPINFOW, LVN_SETDISPINFOA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE},
1214         {&nmlvgit, sizeof(nmlvgit), NULL, 0, &nmlvgit.pszText, &nmlvgit.cchTextMax, LVN_GETINFOTIPW, LVN_GETINFOTIPA,
1215          CONVERT_SEND | CONVERT_RECEIVE},
1216         /* Tool Bar */
1217         {&nmtbs, sizeof(nmtbs), NULL, 0, (WCHAR **)&nmtbs.tbButton.iString, NULL, TBN_SAVE, TBN_SAVE,
1218          DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE},
1219         {&nmtbr, sizeof(nmtbr), NULL, 0, (WCHAR **)&nmtbr.tbButton.iString, NULL, TBN_RESTORE, TBN_RESTORE,
1220          DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE},
1221         {&nmtbdi, sizeof(nmtbdi), &nmtbdi.dwMask, TBNF_TEXT, &nmtbdi.pszText, &nmtbdi.cchText, TBN_GETDISPINFOW,
1222          TBN_GETDISPINFOW, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE},
1223         {&nmtb, sizeof(nmtb), NULL, 0, &nmtb.pszText, &nmtb.cchText, TBN_GETBUTTONINFOW, TBN_GETBUTTONINFOA,
1224          SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE},
1225         {&nmtbgit, sizeof(nmtbgit), NULL, 0, &nmtbgit.pszText, &nmtbgit.cchTextMax, TBN_GETINFOTIPW, TBN_GETINFOTIPA,
1226          DONT_CONVERT_SEND | CONVERT_RECEIVE},
1227         /* Tree View */
1228         {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax,
1229          TVN_BEGINLABELEDITW, TVN_BEGINLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE},
1230         {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax,
1231          TVN_ENDLABELEDITW, TVN_ENDLABELEDITA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE},
1232         {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax,
1233          TVN_GETDISPINFOW, TVN_GETDISPINFOA, ZERO_SEND | DONT_CONVERT_SEND| CONVERT_RECEIVE},
1234         {&nmtvdi, sizeof(nmtvdi), &nmtvdi.item.mask, TVIF_TEXT, &nmtvdi.item.pszText, &nmtvdi.item.cchTextMax,
1235          TVN_SETDISPINFOW, TVN_SETDISPINFOA, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE},
1236         {&nmtvgit, sizeof(nmtvgit), NULL, 0, &nmtvgit.pszText, &nmtvgit.cchTextMax, TVN_GETINFOTIPW, TVN_GETINFOTIPA,
1237          DONT_CONVERT_SEND | CONVERT_RECEIVE},
1238         {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax,
1239          TVN_SINGLEEXPAND, TVN_SINGLEEXPAND, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE, TVITEM_NEW_HANDLER},
1240         {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax,
1241          TVN_SINGLEEXPAND, TVN_SINGLEEXPAND, DONT_CONVERT_SEND | DONT_CONVERT_RECEIVE, TVITEM_OLD_HANDLER},
1242         {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax,
1243          TVN_BEGINDRAGW, TVN_BEGINDRAGA, CONVERT_SEND, TVITEM_NEW_HANDLER},
1244         {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax,
1245          TVN_BEGINDRAGW, TVN_BEGINDRAGA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER},
1246         {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax,
1247          TVN_BEGINRDRAGW, TVN_BEGINRDRAGA, CONVERT_SEND, TVITEM_NEW_HANDLER},
1248         {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax,
1249          TVN_BEGINRDRAGW, TVN_BEGINRDRAGA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER},
1250         {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax,
1251          TVN_ITEMEXPANDEDW, TVN_ITEMEXPANDEDA, CONVERT_SEND, TVITEM_NEW_HANDLER},
1252         {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax,
1253          TVN_ITEMEXPANDEDW, TVN_ITEMEXPANDEDA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER},
1254         {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax,
1255          TVN_ITEMEXPANDINGW, TVN_ITEMEXPANDINGA, CONVERT_SEND, TVITEM_NEW_HANDLER},
1256         {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax,
1257          TVN_ITEMEXPANDINGW, TVN_ITEMEXPANDINGA, DONT_CONVERT_SEND, TVITEM_OLD_HANDLER},
1258         {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax,
1259          TVN_DELETEITEMW, TVN_DELETEITEMA, DONT_CONVERT_SEND, TVITEM_NEW_HANDLER},
1260         {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax,
1261          TVN_DELETEITEMW, TVN_DELETEITEMA, CONVERT_SEND, TVITEM_OLD_HANDLER},
1262         {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax,
1263          TVN_SELCHANGINGW, TVN_SELCHANGINGA, CONVERT_SEND, TVITEM_NEW_HANDLER},
1264         {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax,
1265          TVN_SELCHANGINGW, TVN_SELCHANGINGA, CONVERT_SEND, TVITEM_OLD_HANDLER},
1266         {&nmtv, sizeof(nmtv), &nmtv.itemNew.mask, TVIF_TEXT, &nmtv.itemNew.pszText, &nmtv.itemNew.cchTextMax,
1267          TVN_SELCHANGEDW, TVN_SELCHANGEDA, CONVERT_SEND, TVITEM_NEW_HANDLER},
1268         {&nmtv, sizeof(nmtv), &nmtv.itemOld.mask, TVIF_TEXT, &nmtv.itemOld.pszText, &nmtv.itemOld.cchTextMax,
1269          TVN_SELCHANGEDW, TVN_SELCHANGEDA, CONVERT_SEND, TVITEM_OLD_HANDLER}
1270     };
1271     BOOL bret;
1272     INT i;
1273 
1274     bret = register_test_notify_class();
1275     ok(bret, "Register test class failed, error 0x%08x\n", GetLastError());
1276 
1277     parent = CreateWindowA(class, "parent", WS_OVERLAPPED, 0, 0, 100, 100, 0, 0, GetModuleHandleA(0), 0);
1278     ok(parent != NULL, "CreateWindow failed\n");
1279     pager = CreateWindowA(WC_PAGESCROLLERA, "pager", WS_CHILD, 0, 0, 100, 100, parent, 0, GetModuleHandleA(0), 0);
1280     ok(pager != NULL, "CreateWindow failed\n");
1281     child1_wnd = CreateWindowA(class, "child", WS_CHILD, 0, 0, 100, 100, pager, (HMENU)1, GetModuleHandleA(0), 0);
1282     ok(child1_wnd != NULL, "CreateWindow failed\n");
1283     SendMessageW(pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd);
1284 
1285     for (i = 0; i < ARRAY_SIZE(paras); i++)
1286         test_notify_generic_text_helper(pager, paras + i);
1287 
1288     /* Tests for those that can't be covered by generic text test helper */
1289     test_wm_notify_comboboxex(pager);
1290     test_wm_notify_datetime(pager);
1291     test_wm_notify_header(pager);
1292     test_wm_notify_tooltip(pager);
1293 
1294     DestroyWindow(parent);
1295     UnregisterClassA(class, GetModuleHandleA(NULL));
1296 }
1297 
1298 static void init_functions(void)
1299 {
1300     HMODULE mod = LoadLibraryA("comctl32.dll");
1301 
1302 #define X(f) p##f = (void*)GetProcAddress(mod, #f);
1303     X(InitCommonControlsEx);
1304 #undef X
1305 
1306     pSetWindowSubclass = (void*)GetProcAddress(mod, (LPSTR)410);
1307 }
1308 
1309 START_TEST(pager)
1310 {
1311     INITCOMMONCONTROLSEX iccex;
1312 
1313     init_functions();
1314 
1315     iccex.dwSize = sizeof(iccex);
1316     iccex.dwICC = ICC_PAGESCROLLER_CLASS;
1317     pInitCommonControlsEx(&iccex);
1318 
1319     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1320 
1321     parent_wnd = create_parent_window();
1322     ok(parent_wnd != NULL, "Failed to create parent window!\n");
1323 
1324     test_pager();
1325     test_wm_notifyformat();
1326     test_wm_notify();
1327 
1328     DestroyWindow(parent_wnd);
1329 }
1330