1 /* Unit test suite for header control.
3 * Copyright 2005 Vijay Kiran Kamuju
4 * Copyright 2007 Shanren Zhou
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
26 #include "wine/test.h"
29 typedef struct tagEXPECTEDNOTIFY
36 typedef LRESULT (*CUSTOMDRAWPROC
)(int n
, NMCUSTOMDRAW
*nm
);
38 static CUSTOMDRAWPROC g_CustomDrawProc
;
39 static int g_CustomDrawCount
;
40 static DRAWITEMSTRUCT g_DrawItem
;
41 static BOOL g_DrawItemReceived
;
43 static EXPECTEDNOTIFY expectedNotify
[10];
44 static INT nExpectedNotify
= 0;
45 static INT nReceivedNotify
= 0;
46 static INT unexpectedNotify
[10];
47 static INT nUnexpectedNotify
= 0;
49 static HWND hHeaderParentWnd
;
50 static HWND hWndHeader
;
53 #define compare(val, exp, fmt) ok((val) == (exp), #val " value: " fmt ", expected: " fmt "\n", (val), (exp))
55 #define expect(expected, got) ok(expected == got, "expected %d, got %d\n", expected,got)
57 #define NUM_MSG_SEQUENCES 2
58 #define PARENT_SEQ_INDEX 0
59 #define HEADER_SEQ_INDEX 1
61 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
63 static const struct message create_parent_wnd_seq
[] = {
64 { WM_GETMINMAXINFO
, sent
},
65 { WM_NCCREATE
, sent
},
66 { WM_NCCALCSIZE
, sent
|wparam
, 0 },
71 static const struct message add_header_to_parent_seq_interactive
[] = {
72 { WM_NOTIFYFORMAT
, sent
|lparam
, 0, NF_QUERY
},
73 { WM_QUERYUISTATE
, sent
},
74 { WM_PARENTNOTIFY
, sent
|wparam
, 1 },
75 { WM_SHOWWINDOW
, sent
|wparam
, 1 },
76 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
77 { WM_WINDOWPOSCHANGING
, sent
|wparam
, 0 },
78 { WM_ACTIVATEAPP
, sent
|wparam
, 1 },
79 { WM_NCACTIVATE
, sent
|wparam
, 1 },
80 { WM_ACTIVATE
, sent
|wparam
, 1 },
81 { WM_IME_SETCONTEXT
, sent
|defwinproc
|wparam
, 1 },
82 { WM_IME_NOTIFY
, sent
|defwinproc
|wparam
, 2 },
83 { WM_SETFOCUS
, sent
|defwinproc
|wparam
, 0 },
84 { WM_WINDOWPOSCHANGED
, sent
|wparam
, 0 },
85 { WM_SIZE
, sent
|wparam
, 0 },
86 { WM_MOVE
, sent
|wparam
, 0 },
90 static const struct message add_header_to_parent_seq
[] = {
91 { WM_NOTIFYFORMAT
, sent
|lparam
, 0, NF_QUERY
},
92 { WM_QUERYUISTATE
, sent
},
93 { WM_PARENTNOTIFY
, sent
},
97 static const struct message insertItem_seq
[] = {
98 { HDM_INSERTITEM
, sent
|wparam
, 0 },
99 { HDM_INSERTITEM
, sent
|wparam
, 1 },
100 { HDM_INSERTITEM
, sent
|wparam
, 2 },
101 { HDM_INSERTITEM
, sent
|wparam
, 3 },
105 static const struct message getItem_seq
[] = {
106 { HDM_GETITEM
, sent
|wparam
, 3 },
107 { HDM_GETITEM
, sent
|wparam
, 0 },
112 static const struct message deleteItem_getItemCount_seq
[] = {
113 { HDM_DELETEITEM
, sent
|wparam
, 3 },
114 { HDM_GETITEMCOUNT
, sent
},
115 { HDM_DELETEITEM
, sent
|wparam
, 3 },
116 { HDM_GETITEMCOUNT
, sent
},
117 { HDM_DELETEITEM
, sent
|wparam
, 2 },
118 { HDM_GETITEMCOUNT
, sent
},
122 static const struct message orderArray_seq
[] = {
123 { HDM_GETITEMCOUNT
, sent
},
124 { HDM_SETORDERARRAY
, sent
|wparam
, 2 },
125 { HDM_GETORDERARRAY
, sent
|wparam
, 2 },
129 static const struct message setItem_seq
[] = {
130 { HDM_SETITEM
, sent
|wparam
, 0 },
131 { HDM_SETITEM
, sent
|wparam
, 1 },
135 static const struct message getItemRect_seq
[] = {
136 { HDM_GETITEMRECT
, sent
|wparam
, 1 },
137 { HDM_GETITEMRECT
, sent
|wparam
, 0 },
138 { HDM_GETITEMRECT
, sent
|wparam
, 10 },
142 static const struct message layout_seq
[] = {
143 { HDM_LAYOUT
, sent
},
147 static const struct message orderToIndex_seq
[] = {
148 { HDM_ORDERTOINDEX
, sent
|wparam
, 1 },
152 static const struct message hittest_seq
[] = {
153 { HDM_HITTEST
, sent
},
154 { HDM_HITTEST
, sent
},
155 { HDM_HITTEST
, sent
},
159 static const struct message setHotDivider_seq_interactive
[] = {
160 { HDM_SETHOTDIVIDER
, sent
|wparam
, TRUE
},
161 { WM_PAINT
, sent
|defwinproc
},
162 { WM_NCPAINT
, sent
|defwinproc
},
163 { WM_ERASEBKGND
, sent
|defwinproc
},
164 { HDM_SETHOTDIVIDER
, sent
|wparam
|lparam
, FALSE
, 100 },
165 { WM_PAINT
, sent
|defwinproc
},
166 { HDM_SETHOTDIVIDER
, sent
|wparam
|lparam
, FALSE
, 1},
167 { WM_PAINT
, sent
|defwinproc
},
171 static const struct message setHotDivider_seq_noninteractive
[] = {
172 { HDM_SETHOTDIVIDER
, sent
|wparam
, TRUE
},
173 { HDM_SETHOTDIVIDER
, sent
|wparam
|lparam
, FALSE
, 100 },
174 { HDM_SETHOTDIVIDER
, sent
|wparam
|lparam
, FALSE
, 1},
178 static const struct message imageMessages_seq
[] = {
179 { HDM_SETIMAGELIST
, sent
},
180 { HDM_GETIMAGELIST
, sent
},
181 { HDM_CREATEDRAGIMAGE
, sent
},
185 static const struct message filterMessages_seq_interactive
[] = {
186 { HDM_SETFILTERCHANGETIMEOUT
, sent
|wparam
|lparam
, 1, 100 },
187 { HDM_CLEARFILTER
, sent
|wparam
|lparam
, 0, 1 },
188 { HDM_EDITFILTER
, sent
|wparam
|lparam
, 1, 0 },
189 { WM_PARENTNOTIFY
, sent
|wparam
|defwinproc
, WM_CREATE
},
190 { WM_CTLCOLOREDIT
, sent
|defwinproc
},
191 { WM_COMMAND
, sent
|defwinproc
},
195 static const struct message filterMessages_seq_noninteractive
[] = {
196 { HDM_SETFILTERCHANGETIMEOUT
, sent
|wparam
|lparam
, 1, 100 },
197 { HDM_CLEARFILTER
, sent
|wparam
|lparam
, 0, 1 },
198 { HDM_EDITFILTER
, sent
|wparam
|lparam
, 1, 0 },
199 { WM_PARENTNOTIFY
, sent
|wparam
|defwinproc
, WM_CREATE
},
200 { WM_COMMAND
, sent
|defwinproc
},
204 static const struct message unicodeformatMessages_seq
[] = {
205 { HDM_SETUNICODEFORMAT
, sent
|wparam
, TRUE
},
206 { HDM_GETUNICODEFORMAT
, sent
},
210 static const struct message bitmapmarginMessages_seq
[] = {
211 { HDM_GETBITMAPMARGIN
, sent
},
216 static void expect_notify(INT iCode
, BOOL fUnicode
, HDITEMA
*lpItem
)
218 assert(nExpectedNotify
< 10);
219 expectedNotify
[nExpectedNotify
].iCode
= iCode
;
220 expectedNotify
[nExpectedNotify
].fUnicode
= fUnicode
;
221 expectedNotify
[nExpectedNotify
].hdItem
= *lpItem
;
225 static void dont_expect_notify(INT iCode
)
227 assert(nUnexpectedNotify
< 10);
228 unexpectedNotify
[nUnexpectedNotify
++] = iCode
;
231 static BOOL
notifies_received(void)
233 BOOL fRet
= (nExpectedNotify
== nReceivedNotify
);
234 nExpectedNotify
= nReceivedNotify
= 0;
235 nUnexpectedNotify
= 0;
239 static LONG
addItem(HWND hdex
, int idx
, LPSTR text
)
242 hdItem
.mask
= HDI_TEXT
| HDI_WIDTH
;
244 hdItem
.pszText
= text
;
245 hdItem
.cchTextMax
= 0;
246 return (LONG
)SendMessage(hdex
, HDM_INSERTITEMA
, (WPARAM
)idx
, (LPARAM
)&hdItem
);
249 static LONG
setItem(HWND hdex
, int idx
, LPSTR text
, BOOL fCheckNotifies
)
253 hdexItem
.mask
= HDI_TEXT
;
254 hdexItem
.pszText
= text
;
255 hdexItem
.cchTextMax
= 0;
258 expect_notify(HDN_ITEMCHANGINGA
, FALSE
, &hdexItem
);
259 expect_notify(HDN_ITEMCHANGEDA
, FALSE
, &hdexItem
);
261 ret
= (LONG
)SendMessage(hdex
, HDM_SETITEMA
, (WPARAM
)idx
, (LPARAM
)&hdexItem
);
263 ok(notifies_received(), "setItem(): not all expected notifies were received\n");
267 static LONG
setItemUnicodeNotify(HWND hdex
, int idx
, LPSTR text
, LPWSTR wText
)
272 hdexItem
.mask
= HDI_TEXT
;
273 hdexItem
.pszText
= text
;
274 hdexItem
.cchTextMax
= 0;
276 hdexNotify
.mask
= HDI_TEXT
;
277 hdexNotify
.pszText
= wText
;
279 expect_notify(HDN_ITEMCHANGINGW
, TRUE
, (HDITEMA
*)&hdexNotify
);
280 expect_notify(HDN_ITEMCHANGEDW
, TRUE
, (HDITEMA
*)&hdexNotify
);
281 ret
= (LONG
)SendMessage(hdex
, HDM_SETITEMA
, (WPARAM
)idx
, (LPARAM
)&hdexItem
);
282 ok(notifies_received(), "setItemUnicodeNotify(): not all expected notifies were received\n");
286 static LONG
delItem(HWND hdex
, int idx
)
288 return (LONG
)SendMessage(hdex
, HDM_DELETEITEM
, (WPARAM
)idx
, 0);
291 static LONG
getItemCount(HWND hdex
)
293 return (LONG
)SendMessage(hdex
, HDM_GETITEMCOUNT
, 0, 0);
296 static LONG
getItem(HWND hdex
, int idx
, LPSTR textBuffer
)
299 hdItem
.mask
= HDI_TEXT
;
300 hdItem
.pszText
= textBuffer
;
301 hdItem
.cchTextMax
= MAX_CHARS
;
302 return (LONG
)SendMessage(hdex
, HDM_GETITEMA
, (WPARAM
)idx
, (LPARAM
)&hdItem
);
305 static void addReadDelItem(HWND hdex
, HDITEMA
*phdiCreate
, int maskRead
, HDITEMA
*phdiRead
)
307 ok(SendMessage(hdex
, HDM_INSERTITEMA
, (WPARAM
)0, (LPARAM
)phdiCreate
)!=-1, "Adding item failed\n");
308 ZeroMemory(phdiRead
, sizeof(HDITEMA
));
309 phdiRead
->mask
= maskRead
;
310 ok(SendMessage(hdex
, HDM_GETITEMA
, (WPARAM
)0, (LPARAM
)phdiRead
)!=0, "Getting item data failed\n");
311 ok(SendMessage(hdex
, HDM_DELETEITEM
, (WPARAM
)0, (LPARAM
)0)!=0, "Deleting item failed\n");
314 static HWND
create_header_control (void)
321 handle
= CreateWindowEx(0, WC_HEADER
, NULL
,
322 WS_CHILD
|WS_BORDER
|WS_VISIBLE
|HDS_BUTTONS
|HDS_HORZ
,
324 hHeaderParentWnd
, NULL
, NULL
, NULL
);
327 if (winetest_interactive
)
328 ShowWindow (hHeaderParentWnd
, SW_SHOW
);
330 GetClientRect(hHeaderParentWnd
,&rectwin
);
331 hlayout
.prc
= &rectwin
;
332 hlayout
.pwpos
= &winpos
;
333 SendMessageA(handle
,HDM_LAYOUT
,0,(LPARAM
) &hlayout
);
334 SetWindowPos(handle
, winpos
.hwndInsertAfter
, winpos
.x
, winpos
.y
,
335 winpos
.cx
, winpos
.cy
, 0);
340 static void compare_items(INT iCode
, HDITEMA
*hdi1
, HDITEMA
*hdi2
, BOOL fUnicode
)
342 ok(hdi1
->mask
== hdi2
->mask
, "Notify %d mask mismatch (%08x != %08x)\n", iCode
, hdi1
->mask
, hdi2
->mask
);
343 if (hdi1
->mask
& HDI_WIDTH
)
345 ok(hdi1
->cxy
== hdi2
->cxy
, "Notify %d cxy mismatch (%08x != %08x)\n", iCode
, hdi1
->cxy
, hdi2
->cxy
);
347 if (hdi1
->mask
& HDI_TEXT
)
349 if (hdi1
->pszText
== LPSTR_TEXTCALLBACKA
)
351 ok(hdi1
->pszText
== LPSTR_TEXTCALLBACKA
, "Notify %d - only one item is LPSTR_TEXTCALLBACK\n", iCode
);
358 WideCharToMultiByte(CP_ACP
, 0, (LPCWSTR
)hdi1
->pszText
, -1, buf1
, 260, NULL
, NULL
);
359 WideCharToMultiByte(CP_ACP
, 0, (LPCWSTR
)hdi2
->pszText
, -1, buf2
, 260, NULL
, NULL
);
360 ok(lstrcmpW((LPWSTR
)hdi1
->pszText
, (LPWSTR
)hdi2
->pszText
)==0,
361 "Notify %d text mismatch (L\"%s\" vs L\"%s\")\n",
366 ok(strcmp(hdi1
->pszText
, hdi2
->pszText
)==0,
367 "Notify %d text mismatch (\"%s\" vs \"%s\")\n",
368 iCode
, hdi1
->pszText
, hdi2
->pszText
);
373 static char pszFirstItem
[] = "First Item";
374 static char pszSecondItem
[] = "Second Item";
375 static char pszThirdItem
[] = "Third Item";
376 static char pszFourthItem
[] = "Fourth Item";
377 static char pszReplaceItem
[] = "Replace Item";
378 static char pszOutOfRangeItem
[] = "Out Of Range Item";
380 static char *str_items
[] =
381 {pszFirstItem
, pszSecondItem
, pszThirdItem
, pszFourthItem
, pszReplaceItem
, pszOutOfRangeItem
};
383 static char pszUniTestA
[] = "TST";
384 static WCHAR pszUniTestW
[] = {'T','S','T',0};
387 #define TEST_GET_ITEM(i,c)\
388 { res = getItem(hWndHeader, i, buffer);\
389 ok(res != 0, "Getting item[%d] using valid index failed unexpectedly (%d)\n", i, res);\
390 ok(strcmp(str_items[c], buffer) == 0, "Getting item[%d] returned \"%s\" expecting \"%s\"\n", i, buffer, str_items[c]);\
393 #define TEST_GET_ITEMCOUNT(i)\
394 { res = getItemCount(hWndHeader);\
395 ok(res == i, "Got Item Count as %d\n", res);\
403 static LRESULT WINAPI
header_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
405 struct subclass_info
*info
= (struct subclass_info
*)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
406 static long defwndproc_counter
= 0;
410 trace("header: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
411 msg
.message
= message
;
412 msg
.flags
= sent
|wparam
|lparam
;
413 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
416 add_message(sequences
, HEADER_SEQ_INDEX
, &msg
);
418 defwndproc_counter
++;
419 ret
= CallWindowProcA(info
->oldproc
, hwnd
, message
, wParam
, lParam
);
420 defwndproc_counter
--;
425 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
427 static long defwndproc_counter
= 0;
431 /* do not log painting messages */
432 if (message
!= WM_PAINT
&&
433 message
!= WM_ERASEBKGND
&&
434 message
!= WM_NCPAINT
&&
435 message
!= WM_NCHITTEST
&&
436 message
!= WM_GETTEXT
&&
437 message
!= WM_GETICON
&&
438 message
!= WM_DEVICECHANGE
)
441 trace("parent: %p, %04x, %08lx, %08lx\n", hwnd
, message
, wParam
, lParam
);
443 msg
.message
= message
;
444 msg
.flags
= sent
|wparam
|lparam
;
445 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
448 add_message(sequences
, PARENT_SEQ_INDEX
, &msg
);
451 defwndproc_counter
++;
452 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
453 defwndproc_counter
--;
458 static BOOL
register_parent_wnd_class(void)
463 cls
.lpfnWndProc
= parent_wnd_proc
;
466 cls
.hInstance
= GetModuleHandleA(NULL
);
468 cls
.hCursor
= LoadCursorA(0, (LPSTR
)IDC_ARROW
);
469 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
470 cls
.lpszMenuName
= NULL
;
471 cls
.lpszClassName
= "Header test parent class";
472 return RegisterClassA(&cls
);
475 static HWND
create_custom_parent_window(void)
477 if (!register_parent_wnd_class())
480 return CreateWindowExA(0, "Header test parent class", "Header Message Sequence Testing",
481 WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT
, CW_USEDEFAULT
,
482 672+2*GetSystemMetrics(SM_CXSIZEFRAME
),
483 226+GetSystemMetrics(SM_CYCAPTION
)+2*GetSystemMetrics(SM_CYSIZEFRAME
),
484 NULL
, NULL
, GetModuleHandleA(NULL
), 0);
487 static HWND
create_custom_header_control(HWND hParent
, BOOL preloadHeaderItems
)
489 struct subclass_info
*info
;
496 static char firstHeaderItem
[] = "Name";
497 static char secondHeaderItem
[] = "Size";
498 static char *items
[] = {secondHeaderItem
, firstHeaderItem
};
500 hdItem
.mask
= HDI_TEXT
| HDI_WIDTH
| HDI_FORMAT
;
501 hdItem
.fmt
= HDF_LEFT
;
503 hdItem
.cchTextMax
= 260;
506 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
507 info
= HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info
));
511 childHandle
= CreateWindowEx(0, WC_HEADER
, NULL
,
512 WS_CHILD
|WS_BORDER
|WS_VISIBLE
|HDS_BUTTONS
|HDS_HORZ
,
514 hParent
, NULL
, NULL
, NULL
);
516 if (preloadHeaderItems
)
518 for ( loopcnt
= 0 ; loopcnt
< 2 ; loopcnt
++ )
520 hdItem
.pszText
= items
[loopcnt
];
521 retVal
= SendMessage(childHandle
, HDM_INSERTITEM
, loopcnt
, (LPARAM
) &hdItem
);
522 ok(retVal
== loopcnt
, "Adding item %d failed with return value %d\n", ( loopcnt
+ 1 ), retVal
);
526 if (winetest_interactive
)
527 ShowWindow (hParent
, SW_SHOW
);
529 GetClientRect(hParent
,&rectwin
);
530 hlayout
.prc
= &rectwin
;
531 hlayout
.pwpos
= &winpos
;
532 SendMessageA(childHandle
,HDM_LAYOUT
,0,(LPARAM
) &hlayout
);
533 SetWindowPos(childHandle
, winpos
.hwndInsertAfter
, winpos
.x
, winpos
.y
,
534 winpos
.cx
, winpos
.cy
, 0);
536 info
->oldproc
= (WNDPROC
)SetWindowLongPtrA(childHandle
, GWLP_WNDPROC
,
537 (LONG_PTR
)header_subclass_proc
);
538 SetWindowLongPtrA(childHandle
, GWLP_USERDATA
, (LONG_PTR
)info
);
542 static void check_auto_format(void)
546 static CHAR text
[] = "Test";
547 ZeroMemory(&hdiCreate
, sizeof(HDITEMA
));
549 /* Windows implicitly sets some format bits in INSERTITEM */
551 /* HDF_STRING is automatically set and cleared for no text */
552 hdiCreate
.mask
= HDI_TEXT
|HDI_WIDTH
|HDI_FORMAT
;
553 hdiCreate
.pszText
= text
;
555 hdiCreate
.fmt
=HDF_CENTER
;
556 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_FORMAT
, &hdiRead
);
557 ok(hdiRead
.fmt
== (HDF_STRING
|HDF_CENTER
), "HDF_STRING not set automatically (fmt=%x)\n", hdiRead
.fmt
);
559 hdiCreate
.mask
= HDI_WIDTH
|HDI_FORMAT
;
560 hdiCreate
.pszText
= text
;
561 hdiCreate
.fmt
= HDF_CENTER
|HDF_STRING
;
562 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_FORMAT
, &hdiRead
);
563 ok(hdiRead
.fmt
== (HDF_CENTER
), "HDF_STRING should be automatically cleared (fmt=%x)\n", hdiRead
.fmt
);
565 /* HDF_BITMAP is automatically set and cleared for a NULL bitmap or no bitmap */
566 hdiCreate
.mask
= HDI_BITMAP
|HDI_WIDTH
|HDI_FORMAT
;
567 hdiCreate
.hbm
= CreateBitmap(16, 16, 1, 8, NULL
);
568 hdiCreate
.fmt
= HDF_CENTER
;
569 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_FORMAT
, &hdiRead
);
570 ok(hdiRead
.fmt
== (HDF_BITMAP
|HDF_CENTER
), "HDF_BITMAP not set automatically (fmt=%x)\n", hdiRead
.fmt
);
571 DeleteObject(hdiCreate
.hbm
);
573 hdiCreate
.hbm
= NULL
;
574 hdiCreate
.fmt
= HDF_CENTER
|HDF_BITMAP
;
575 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_FORMAT
, &hdiRead
);
576 ok(hdiRead
.fmt
== HDF_CENTER
, "HDF_BITMAP not cleared automatically for NULL bitmap (fmt=%x)\n", hdiRead
.fmt
);
578 hdiCreate
.mask
= HDI_WIDTH
|HDI_FORMAT
;
579 hdiCreate
.fmt
= HDF_CENTER
|HDF_BITMAP
;
580 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_FORMAT
, &hdiRead
);
581 ok(hdiRead
.fmt
== HDF_CENTER
, "HDF_BITMAP not cleared automatically for no bitmap (fmt=%x)\n", hdiRead
.fmt
);
583 /* HDF_IMAGE is automatically set but not cleared */
584 hdiCreate
.mask
= HDI_IMAGE
|HDI_WIDTH
|HDI_FORMAT
;
585 hdiCreate
.iImage
= 17;
586 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_FORMAT
, &hdiRead
);
587 ok(hdiRead
.fmt
== (HDF_IMAGE
|HDF_CENTER
), "HDF_IMAGE not set automatically (fmt=%x)\n", hdiRead
.fmt
);
589 hdiCreate
.mask
= HDI_WIDTH
|HDI_FORMAT
;
590 hdiCreate
.fmt
= HDF_CENTER
|HDF_IMAGE
;
591 hdiCreate
.iImage
= 0;
592 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_FORMAT
, &hdiRead
);
593 ok(hdiRead
.fmt
== (HDF_CENTER
|HDF_IMAGE
), "HDF_IMAGE shouldn't be cleared automatically (fmt=%x)\n", hdiRead
.fmt
);
596 static void check_auto_fields(void)
600 static CHAR text
[] = "Test";
603 /* Windows stores the format, width, lparam even if they are not in the item's mask */
604 ZeroMemory(&hdiCreate
, sizeof(HDITEMA
));
605 hdiCreate
.mask
= HDI_TEXT
;
607 hdiCreate
.pszText
= text
;
608 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_WIDTH
, &hdiRead
);
609 TEST_GET_ITEMCOUNT(6);
610 ok(hdiRead
.cxy
== hdiCreate
.cxy
, "cxy should be automatically set\n");
612 ZeroMemory(&hdiCreate
, sizeof(HDITEMA
));
613 hdiCreate
.mask
= HDI_TEXT
;
614 hdiCreate
.pszText
= text
;
615 hdiCreate
.lParam
= 0x12345678;
616 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_LPARAM
, &hdiRead
);
617 TEST_GET_ITEMCOUNT(6);
618 ok(hdiRead
.lParam
== hdiCreate
.lParam
, "lParam should be automatically set\n");
620 ZeroMemory(&hdiCreate
, sizeof(HDITEMA
));
621 hdiCreate
.mask
= HDI_TEXT
;
622 hdiCreate
.pszText
= text
;
623 hdiCreate
.fmt
= HDF_STRING
|HDF_CENTER
;
624 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_FORMAT
, &hdiRead
);
625 TEST_GET_ITEMCOUNT(6);
626 ok(hdiRead
.fmt
== hdiCreate
.fmt
, "fmt should be automatically set\n");
628 /* others fields are not set */
629 ZeroMemory(&hdiCreate
, sizeof(HDITEMA
));
630 hdiCreate
.mask
= HDI_TEXT
;
631 hdiCreate
.pszText
= text
;
632 hdiCreate
.hbm
= CreateBitmap(16, 16, 1, 8, NULL
);
633 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_BITMAP
, &hdiRead
);
634 TEST_GET_ITEMCOUNT(6);
635 ok(hdiRead
.hbm
== NULL
, "hbm should not be automatically set\n");
636 DeleteObject(hdiCreate
.hbm
);
638 ZeroMemory(&hdiCreate
, sizeof(HDITEMA
));
639 hdiCreate
.mask
= HDI_IMAGE
;
640 hdiCreate
.iImage
= 17;
641 hdiCreate
.pszText
= text
;
642 addReadDelItem(hWndHeader
, &hdiCreate
, HDI_TEXT
, &hdiRead
);
643 TEST_GET_ITEMCOUNT(6);
644 ok(hdiRead
.pszText
==NULL
, "pszText shouldn't be automatically set\n");
646 /* field from comctl >4.0 not tested as the system probably won't touch them */
649 static void check_mask(void)
652 static CHAR text
[] = "ABC";
655 /* don't create items if the mask is zero */
656 ZeroMemory(&hdi
, sizeof(hdi
));
663 hdi
.cchTextMax
= 260;
664 ret
= SendMessage(hWndHeader
, HDM_INSERTITEM
, (WPARAM
)0, (LPARAM
)&hdi
);
665 ok(ret
== -1, "Creating an item with a zero mask should have failed\n");
666 if (ret
!= -1) SendMessage(hWndHeader
, HDM_DELETEITEM
, (WPARAM
)0, (LPARAM
)0);
668 /* with a non-zero mask creation will succeed */
669 ZeroMemory(&hdi
, sizeof(hdi
));
670 hdi
.mask
= HDI_LPARAM
;
671 ret
= SendMessage(hWndHeader
, HDM_INSERTITEM
, (WPARAM
)0, (LPARAM
)&hdi
);
672 ok(ret
!= -1, "Adding item with non-zero mask failed\n");
674 SendMessage(hWndHeader
, HDM_DELETEITEM
, (WPARAM
)0, (LPARAM
)0);
676 /* in SETITEM if the mask contains a unknown bit, it is ignored */
677 ZeroMemory(&hdi
, sizeof(hdi
));
678 hdi
.mask
= 0x08000000 | HDI_LPARAM
| HDI_IMAGE
;
681 ret
= SendMessage(hWndHeader
, HDM_INSERTITEM
, (WPARAM
)0, (LPARAM
)&hdi
);
682 ok(ret
!= -1, "Adding item failed\n");
687 ZeroMemory(&hdi
, sizeof(hdi
));
688 hdi
.mask
= HDI_LPARAM
| HDI_IMAGE
;
689 SendMessage(hWndHeader
, HDM_GETITEM
, (WPARAM
)0, (LPARAM
)&hdi
);
690 ok(hdi
.lParam
== 133, "comctl32 4.0 field not set\n");
691 ok(hdi
.iImage
== 17, "comctl32 >4.0 field not set\n");
693 /* but in GETITEM if an unknown bit is set, comctl32 uses only version 4.0 fields */
694 ZeroMemory(&hdi
, sizeof(hdi
));
695 hdi
.mask
= 0x08000000 | HDI_LPARAM
| HDI_IMAGE
;
696 SendMessage(hWndHeader
, HDM_GETITEM
, (WPARAM
)0, (LPARAM
)&hdi
);
697 ok(hdi
.lParam
== 133, "comctl32 4.0 field not read\n");
698 ok(hdi
.iImage
== 0, "comctl32 >4.0 field shouldn't be read\n");
700 SendMessage(hWndHeader
, HDM_DELETEITEM
, (WPARAM
)0, (LPARAM
)0);
704 static void test_header_control (void)
707 static char buffer
[MAX_CHARS
];
710 hWndHeader
= create_header_control ();
712 for (i
= 3; i
>= 0; i
--)
714 TEST_GET_ITEMCOUNT(3-i
);
715 res
= addItem(hWndHeader
, 0, str_items
[i
]);
716 ok(res
== 0, "Adding simple item failed (%d)\n", res
);
719 TEST_GET_ITEMCOUNT(4);
720 res
= addItem(hWndHeader
, 99, str_items
[i
+1]);
721 ok(res
!= -1, "Adding Out of Range item should fail with -1 got (%d)\n", res
);
722 TEST_GET_ITEMCOUNT(5);
723 res
= addItem(hWndHeader
, 5, str_items
[i
+1]);
724 ok(res
!= -1, "Adding Out of Range item should fail with -1 got (%d)\n", res
);
725 TEST_GET_ITEMCOUNT(6);
727 for (i
= 0; i
< 4; i
++) { TEST_GET_ITEM(i
,i
); TEST_GET_ITEMCOUNT(6); }
729 res
=getItem(hWndHeader
, 99, buffer
);
730 ok(res
== 0, "Getting Out of Range item should fail with 0 (%d), got %s\n", res
,buffer
);
731 res
=getItem(hWndHeader
, 5, buffer
);
732 ok(res
== 1, "Getting Out of Range item should fail with 1 (%d), got %s\n", res
,buffer
);
733 res
=getItem(hWndHeader
, -2, buffer
);
734 ok(res
== 0, "Getting Out of Range item should fail with 0 (%d), got %s\n", res
,buffer
);
736 if (winetest_interactive
)
738 UpdateWindow(hHeaderParentWnd
);
739 UpdateWindow(hWndHeader
);
742 TEST_GET_ITEMCOUNT(6);
743 res
=setItem(hWndHeader
, 99, str_items
[5], FALSE
);
744 ok(res
== 0, "Setting Out of Range item should fail with 0 (%d)\n", res
);
745 res
=setItem(hWndHeader
, 5, str_items
[5], TRUE
);
746 ok(res
== 1, "Setting Out of Range item should fail with 1 (%d)\n", res
);
747 res
=setItem(hWndHeader
, -2, str_items
[5], FALSE
);
748 ok(res
== 0, "Setting Out of Range item should fail with 0 (%d)\n", res
);
749 TEST_GET_ITEMCOUNT(6);
751 for (i
= 0; i
< 4; i
++)
753 res
= setItem(hWndHeader
, i
, str_items
[4], TRUE
);
754 ok(res
!= 0, "Setting %d item failed (%d)\n", i
+1, res
);
756 TEST_GET_ITEMCOUNT(6);
759 SendMessageA(hWndHeader
, HDM_SETUNICODEFORMAT
, (WPARAM
)TRUE
, 0);
760 setItemUnicodeNotify(hWndHeader
, 3, pszUniTestA
, pszUniTestW
);
761 SendMessageA(hWndHeader
, WM_NOTIFYFORMAT
, (WPARAM
)hHeaderParentWnd
, (LPARAM
)NF_REQUERY
);
762 setItem(hWndHeader
, 3, str_items
[4], TRUE
);
764 dont_expect_notify(HDN_GETDISPINFOA
);
765 dont_expect_notify(HDN_GETDISPINFOW
);
766 addItem(hWndHeader
, 0, LPSTR_TEXTCALLBACKA
);
767 setItem(hWndHeader
, 0, str_items
[4], TRUE
);
768 /* unexpected notifies cleared by notifies_received in setItem */
769 dont_expect_notify(HDN_GETDISPINFOA
);
770 dont_expect_notify(HDN_GETDISPINFOW
);
771 setItem(hWndHeader
, 0, LPSTR_TEXTCALLBACKA
, TRUE
);
772 /* unexpected notifies cleared by notifies_received in setItem */
773 delItem(hWndHeader
, 0);
776 TEST_GET_ITEMCOUNT(6);
778 TEST_GET_ITEMCOUNT(6);
780 TEST_GET_ITEMCOUNT(6);
782 res
= delItem(hWndHeader
, 5);
783 ok(res
== 1, "Deleting Out of Range item should fail with 1 (%d)\n", res
);
784 res
= delItem(hWndHeader
, -2);
785 ok(res
== 0, "Deleting Out of Range item should fail with 0 (%d)\n", res
);
786 TEST_GET_ITEMCOUNT(5);
788 res
= delItem(hWndHeader
, 3);
789 ok(res
!= 0, "Deleting using out of range index failed (%d)\n", res
);
790 TEST_GET_ITEMCOUNT(4);
791 res
= delItem(hWndHeader
, 0);
792 ok(res
!= 0, "Deleting using out of range index failed (%d)\n", res
);
793 TEST_GET_ITEMCOUNT(3);
794 res
= delItem(hWndHeader
, 0);
795 ok(res
!= 0, "Deleting using out of range index failed (%d)\n", res
);
796 TEST_GET_ITEMCOUNT(2);
797 res
= delItem(hWndHeader
, 0);
798 ok(res
!= 0, "Deleting using out of range index failed (%d)\n", res
);
799 TEST_GET_ITEMCOUNT(1);
801 DestroyWindow(hWndHeader
);
804 static void test_hdm_getitemrect(HWND hParent
)
811 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
812 hChild
= create_custom_header_control(hParent
, TRUE
);
813 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
814 "adder header control to parent", TRUE
);
816 retVal
= SendMessage(hChild
, HDM_GETITEMRECT
, 1, (LPARAM
) &rect
);
817 ok(retVal
== TRUE
, "Getting item rect should TRUE, got %d\n", retVal
);
818 /* check bounding rectangle information of 2nd header item */
819 expect(80, rect
.left
);
821 expect(160, rect
.right
);
824 expect(18, rect
.bottom
);
826 retVal
= SendMessage(hChild
, HDM_GETITEMRECT
, 0, (LPARAM
) &rect
);
828 ok(retVal
== TRUE
, "Getting item rect should TRUE, got %d\n", retVal
);
829 /* check bounding rectangle information of 1st header item */
830 expect(0, rect
.left
);
833 expect(80, rect
.right
);
836 expect(18, rect
.bottom
);
838 retVal
= SendMessage(hChild
, HDM_GETITEMRECT
, 10, (LPARAM
) &rect
);
839 ok(retVal
== 0, "Getting rect of nonexistent item should return 0, got %d\n", retVal
);
841 ok_sequence(sequences
, HEADER_SEQ_INDEX
, getItemRect_seq
, "getItemRect sequence testing", FALSE
);
842 DestroyWindow(hChild
);
845 static void test_hdm_layout(HWND hParent
)
852 hdLayout
.prc
= &rect
;
853 hdLayout
.pwpos
= &windowPos
;
855 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
856 hChild
= create_custom_header_control(hParent
, TRUE
);
857 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
858 "adder header control to parent", TRUE
);
860 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
861 retVal
= SendMessage(hChild
, HDM_LAYOUT
, 0, (LPARAM
) &hdLayout
);
862 expect(TRUE
, retVal
);
864 ok_sequence(sequences
, HEADER_SEQ_INDEX
, layout_seq
, "layout sequence testing", FALSE
);
866 DestroyWindow(hChild
);
869 static void test_hdm_ordertoindex(HWND hParent
)
874 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
875 hChild
= create_custom_header_control(hParent
, TRUE
);
876 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
877 "adder header control to parent", TRUE
);
879 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
880 retVal
= SendMessage(hChild
, HDM_ORDERTOINDEX
, 1, 0);
883 ok_sequence(sequences
, HEADER_SEQ_INDEX
, orderToIndex_seq
, "orderToIndex sequence testing", FALSE
);
884 DestroyWindow(hChild
);
887 static void test_hdm_hittest(HWND hParent
)
892 HDHITTESTINFO hdHitTestInfo
;
893 const int firstItemRightBoundary
= 80;
894 const int secondItemRightBoundary
= 160;
895 const int bottomBoundary
= 18;
897 pt
.x
= firstItemRightBoundary
- 1;
898 pt
.y
= bottomBoundary
- 1;
899 hdHitTestInfo
.pt
= pt
;
902 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
903 hChild
= create_custom_header_control(hParent
, TRUE
);
904 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
905 "adder header control to parent", TRUE
);
907 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
908 retVal
= SendMessage(hChild
, HDM_HITTEST
, 0, (LPARAM
) &hdHitTestInfo
);
912 expect(0, hdHitTestInfo
.iItem
);
915 pt
.x
= secondItemRightBoundary
- 1;
916 pt
.y
= bottomBoundary
- 1;
917 hdHitTestInfo
.pt
= pt
;
918 retVal
= SendMessage(hChild
, HDM_HITTEST
, 1, (LPARAM
) &hdHitTestInfo
);
923 expect(1, hdHitTestInfo
.iItem
);
925 pt
.x
= secondItemRightBoundary
;
926 pt
.y
= bottomBoundary
+ 1;
927 hdHitTestInfo
.pt
= pt
;
930 retVal
= SendMessage(hChild
, HDM_HITTEST
, 0, (LPARAM
) &hdHitTestInfo
);
934 ok_sequence(sequences
, HEADER_SEQ_INDEX
, hittest_seq
, "hittest sequence testing", FALSE
);
936 DestroyWindow(hChild
);
939 static void test_hdm_sethotdivider(HWND hParent
)
943 /* low word: x coordinate = 5
944 * high word: y coordinate = 5
947 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
948 hChild
= create_custom_header_control(hParent
, TRUE
);
949 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
950 "adder header control to parent", TRUE
);
952 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
955 retVal
= SendMessage(hChild
, HDM_SETHOTDIVIDER
, TRUE
, (LPARAM
) 0X00050005);
958 retVal
= SendMessage(hChild
, HDM_SETHOTDIVIDER
, FALSE
, 100);
960 retVal
= SendMessage(hChild
, HDM_SETHOTDIVIDER
, FALSE
, 1);
962 if (winetest_interactive
)
963 ok_sequence(sequences
, HEADER_SEQ_INDEX
, setHotDivider_seq_interactive
,
964 "setHotDivider sequence testing", TRUE
);
966 ok_sequence(sequences
, HEADER_SEQ_INDEX
, setHotDivider_seq_noninteractive
,
967 "setHotDivider sequence testing", FALSE
);
969 DestroyWindow(hChild
);
972 static void test_hdm_imageMessages(HWND hParent
)
974 HIMAGELIST hImageList
= ImageList_Create (4, 4, 0, 1, 0);
975 HIMAGELIST hImageListRetVal
;
978 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
979 hChild
= create_custom_header_control(hParent
, TRUE
);
980 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
981 "adder header control to parent", TRUE
);
983 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
985 hImageListRetVal
= (HIMAGELIST
) SendMessage(hChild
, HDM_SETIMAGELIST
, 0, (LPARAM
) hImageList
);
986 ok(hImageListRetVal
== NULL
, "Expected NULL, got %d\n", (int) hImageListRetVal
);
988 hImageListRetVal
= (HIMAGELIST
) SendMessage(hChild
, HDM_GETIMAGELIST
, 0, 0);
989 ok(hImageListRetVal
!= NULL
, "Expected non-NULL handle, got %d\n", (int) hImageListRetVal
);
991 hImageListRetVal
= (HIMAGELIST
) SendMessage(hChild
, HDM_CREATEDRAGIMAGE
, 0, 0);
992 ok(hImageListRetVal
!= NULL
, "Expected non-NULL handle, got %d\n", (int) hImageListRetVal
);
994 ok_sequence(sequences
, HEADER_SEQ_INDEX
, imageMessages_seq
, "imageMessages sequence testing", FALSE
);
996 DestroyWindow(hChild
);
999 static void test_hdm_filterMessages(HWND hParent
)
1004 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1005 hChild
= create_custom_header_control(hParent
, TRUE
);
1007 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
1008 "adder header control to parent", TRUE
);
1010 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1013 /* msdn incorrecly states that return value
1014 * is the index of the filter control being
1015 * modified. The sendMessage here should
1016 * return previous filter timeout value
1018 retVal
= SendMessage(hChild
, HDM_SETFILTERCHANGETIMEOUT
, 1, 100);
1019 expect(1000, retVal
);
1020 retVal
= SendMessage(hChild
, HDM_CLEARFILTER
, 0, 1);
1022 retVal
= SendMessage(hChild
, HDM_EDITFILTER
, 1, 0);
1025 if (winetest_interactive
)
1026 ok_sequence(sequences
, HEADER_SEQ_INDEX
, filterMessages_seq_interactive
,
1027 "filterMessages sequence testing", TRUE
);
1029 ok_sequence(sequences
, HEADER_SEQ_INDEX
, filterMessages_seq_noninteractive
,
1030 "filterMessages sequence testing", TRUE
);
1031 DestroyWindow(hChild
);
1035 static void test_hdm_unicodeformatMessages(HWND hParent
)
1040 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1041 hChild
= create_custom_header_control(hParent
, TRUE
);
1042 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
1043 "adder header control to parent", TRUE
);
1045 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1046 retVal
= SendMessage(hChild
, HDM_SETUNICODEFORMAT
, TRUE
, 0);
1048 retVal
= SendMessage(hChild
, HDM_GETUNICODEFORMAT
, 0, 0);
1051 ok_sequence(sequences
, HEADER_SEQ_INDEX
, unicodeformatMessages_seq
,
1052 "unicodeformatMessages sequence testing", FALSE
);
1053 DestroyWindow(hChild
);
1056 static void test_hdm_bitmapmarginMessages(HWND hParent
)
1061 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1062 hChild
= create_custom_header_control(hParent
, TRUE
);
1063 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
1064 "adder header control to parent", TRUE
);
1066 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1067 retVal
= SendMessage(hChild
, HDM_GETBITMAPMARGIN
, 0, 0);
1070 ok_sequence(sequences
, HEADER_SEQ_INDEX
, bitmapmarginMessages_seq
,
1071 "bitmapmarginMessages sequence testing", FALSE
);
1072 DestroyWindow(hChild
);
1075 static void test_hdm_index_messages(HWND hParent
)
1083 static const int lpiarray
[2] = {1, 0};
1084 static int lpiarrayReceived
[2];
1085 static char firstHeaderItem
[] = "Name";
1086 static char secondHeaderItem
[] = "Size";
1087 static char thirdHeaderItem
[] = "Type";
1088 static char fourthHeaderItem
[] = "Date Modified";
1089 static char *items
[] = {firstHeaderItem
, secondHeaderItem
, thirdHeaderItem
, fourthHeaderItem
};
1091 hdItem
.mask
= HDI_TEXT
| HDI_WIDTH
| HDI_FORMAT
;
1092 hdItem
.fmt
= HDF_LEFT
;
1094 hdItem
.cchTextMax
= 260;
1096 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1097 hChild
= create_custom_header_control(hParent
, FALSE
);
1098 if (winetest_interactive
)
1099 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq_interactive
,
1100 "adder header control to parent", TRUE
);
1102 ok_sequence(sequences
, PARENT_SEQ_INDEX
, add_header_to_parent_seq
,
1103 "adder header control to parent", TRUE
);
1104 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1105 for ( loopcnt
= 0 ; loopcnt
< 4 ; loopcnt
++ )
1107 hdItem
.pszText
= items
[loopcnt
];
1108 retVal
= SendMessage(hChild
, HDM_INSERTITEM
, loopcnt
, (LPARAM
) &hdItem
);
1109 ok(retVal
== loopcnt
, "Adding item %d failed with return value %d\n", ( loopcnt
+ 1 ), retVal
);
1111 ok_sequence(sequences
, HEADER_SEQ_INDEX
, insertItem_seq
, "insertItem sequence testing", FALSE
);
1113 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1115 retVal
= SendMessage(hChild
, HDM_DELETEITEM
, 3, (LPARAM
) &hdItem
);
1116 ok(retVal
== TRUE
, "Deleting item 3 should return TRUE, got %d\n", retVal
);
1117 retVal
= SendMessage(hChild
, HDM_GETITEMCOUNT
, 0, (LPARAM
) &hdItem
);
1118 ok(retVal
== 3, "Getting item count should return 3, got %d\n", retVal
);
1120 retVal
= SendMessage(hChild
, HDM_DELETEITEM
, 3, (LPARAM
) &hdItem
);
1121 ok(retVal
== FALSE
, "Deleting already-deleted item should return FALSE, got %d\n", retVal
);
1122 retVal
= SendMessage(hChild
, HDM_GETITEMCOUNT
, 0, (LPARAM
) &hdItem
);
1123 ok(retVal
== 3, "Getting item count should return 3, got %d\n", retVal
);
1125 retVal
= SendMessage(hChild
, HDM_DELETEITEM
, 2, (LPARAM
) &hdItem
);
1126 ok(retVal
== TRUE
, "Deleting item 2 should return TRUE, got %d\n", retVal
);
1127 retVal
= SendMessage(hChild
, HDM_GETITEMCOUNT
, 0, (LPARAM
) &hdItem
);
1128 ok(retVal
== 2, "Getting item count should return 2, got %d\n", retVal
);
1130 ok_sequence(sequences
, HEADER_SEQ_INDEX
, deleteItem_getItemCount_seq
,
1131 "deleteItem_getItemCount sequence testing", FALSE
);
1133 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1135 retVal
= SendMessage(hChild
, HDM_GETITEM
, 3, (LPARAM
) &hdItem
);
1136 ok(retVal
== FALSE
, "Getting already-deleted item should return FALSE, got %d\n", retVal
);
1138 retVal
= SendMessage(hChild
, HDM_GETITEM
, 0, (LPARAM
) &hdItem
);
1139 ok(retVal
== TRUE
, "Getting the 1st header item should return TRUE, got %d\n", retVal
);
1141 ok_sequence(sequences
, HEADER_SEQ_INDEX
, getItem_seq
, "getItem sequence testing", FALSE
);
1143 /* check if the item is the right one */
1144 strcmpResult
= strcmp(hdItem
.pszText
, firstHeaderItem
);
1145 expect(0, strcmpResult
);
1146 expect(80, hdItem
.cxy
);
1148 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1150 iSize
= SendMessage(hChild
, HDM_GETITEMCOUNT
, 0, (LPARAM
) &hdItem
);
1151 retVal
= SendMessage(hChild
, HDM_SETORDERARRAY
, (WPARAM
) iSize
, (LPARAM
) (LPINT
) lpiarray
);
1152 ok(retVal
== TRUE
, "Setting header items order should return TRUE, got %d\n", retVal
);
1154 retVal
= SendMessage(hChild
, HDM_GETORDERARRAY
, (WPARAM
) iSize
, (LPARAM
) (LPINT
) lpiarrayReceived
);
1155 ok(retVal
== TRUE
, "Getting header items order should return TRUE, got %d\n", retVal
);
1157 ok_sequence(sequences
, HEADER_SEQ_INDEX
, orderArray_seq
, "set_get_orderArray sequence testing", FALSE
);
1159 /* check if the array order is set correctly and the size of the array is corret. */
1161 expect(lpiarray
[0], lpiarrayReceived
[0]);
1162 expect(lpiarray
[1], lpiarrayReceived
[1]);
1164 hdItem
.mask
= HDI_FORMAT
;
1165 hdItem
.fmt
= HDF_CENTER
| HDF_STRING
;
1167 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
1169 retVal
= SendMessage(hChild
, HDM_SETITEM
, 0, (LPARAM
) &hdItem
);
1170 ok(retVal
== TRUE
, "Aligning 1st header item to center should return TRUE, got %d\n", retVal
);
1171 hdItem
.fmt
= HDF_RIGHT
| HDF_STRING
;
1172 retVal
= SendMessage(hChild
, HDM_SETITEM
, 1, (LPARAM
) &hdItem
);
1173 ok(retVal
== TRUE
, "Aligning 2nd header item to right should return TRUE, got %d\n", retVal
);
1175 ok_sequence(sequences
, HEADER_SEQ_INDEX
, setItem_seq
, "setItem sequence testing", FALSE
);
1176 DestroyWindow(hChild
);
1179 #define TEST_NMCUSTOMDRAW(draw_stage, item_spec, lparam, _left, _top, _right, _bottom) \
1180 ok(nm->dwDrawStage == draw_stage, "Invalid dwDrawStage %d vs %d\n", draw_stage, nm->dwDrawStage); \
1181 if (item_spec != -1) \
1182 ok(nm->dwItemSpec == item_spec, "Invalid dwItemSpec %d vs %ld\n", item_spec, nm->dwItemSpec); \
1183 ok(nm->lItemlParam == lparam, "Invalid lItemlParam %d vs %ld\n", lparam, nm->lItemlParam); \
1184 ok(nm->rc.top == _top && nm->rc.bottom == _bottom && nm->rc.left == _left && nm->rc.right == _right, \
1185 "Invalid rect (%d,%d) (%d,%d) vs (%d,%d) (%d,%d)\n", _left, _top, _right, _bottom, \
1186 nm->rc.left, nm->rc.top, nm->rc.right, nm->rc.bottom);
1188 static LRESULT
customdraw_1(int n
, NMCUSTOMDRAW
*nm
)
1190 if (nm
== NULL
) { /* test ended */
1191 ok(n
==1, "NM_CUSTOMDRAW messages: %d, expected: 1\n", n
);
1198 /* don't test dwItemSpec - it's 0 no comctl5 but 1308756 on comctl6 */
1199 TEST_NMCUSTOMDRAW(CDDS_PREPAINT
, -1, 0, 0, 0, 670, 18);
1203 ok(FALSE
, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n
, nm
->dwDrawStage
);
1207 static LRESULT
customdraw_2(int n
, NMCUSTOMDRAW
*nm
)
1209 if (nm
== NULL
) { /* test ended */
1210 ok(n
==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n
);
1217 TEST_NMCUSTOMDRAW(CDDS_PREPAINT
, -1, 0, 0, 0, 670, 18);
1218 return CDRF_NOTIFYITEMDRAW
;
1220 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT
, 0, 0, 0, 0, 50, 18);
1223 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT
, 1, 5, 50, 0, 150, 18);
1226 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT
, 2, 10, 150, 0, 300, 18);
1230 ok(FALSE
, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n
, nm
->dwDrawStage
);
1234 static LRESULT
customdraw_3(int n
, NMCUSTOMDRAW
*nm
)
1236 if (nm
== NULL
) { /* test ended */
1237 ok(n
==5, "NM_CUSTOMDRAW messages: %d, expected: 5\n", n
);
1244 TEST_NMCUSTOMDRAW(CDDS_PREPAINT
, -1, 0, 0, 0, 670, 18);
1245 return CDRF_NOTIFYITEMDRAW
|CDRF_NOTIFYPOSTERASE
|CDRF_NOTIFYPOSTPAINT
|CDRF_SKIPDEFAULT
;
1247 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT
, 0, 0, 0, 0, 50, 18);
1250 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT
, 1, 5, 50, 0, 150, 18);
1253 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT
, 2, 10, 150, 0, 300, 18);
1256 TEST_NMCUSTOMDRAW(CDDS_POSTPAINT
, -1, 0, 0, 0, 670, 18);
1260 ok(FALSE
, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n
, nm
->dwDrawStage
);
1265 static LRESULT
customdraw_4(int n
, NMCUSTOMDRAW
*nm
)
1267 if (nm
== NULL
) { /* test ended */
1268 ok(n
==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n
);
1275 TEST_NMCUSTOMDRAW(CDDS_PREPAINT
, -1, 0, 0, 0, 670, 18);
1276 return CDRF_NOTIFYITEMDRAW
|CDRF_NOTIFYPOSTPAINT
;
1278 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT
, 0, 0, 0, 0, 50, 18);
1281 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT
, 2, 10, 150, 0, 300, 18);
1284 TEST_NMCUSTOMDRAW(CDDS_POSTPAINT
, -1, 0, 0, 0, 670, 18);
1288 ok(FALSE
, "To many custom draw messages (n=%d, nm->dwDrawStage=%d)\n", n
, nm
->dwDrawStage
);
1292 static void run_customdraw_scenario(CUSTOMDRAWPROC proc
)
1294 g_CustomDrawProc
= proc
;
1295 g_CustomDrawCount
= 0;
1296 InvalidateRect(hWndHeader
, NULL
, TRUE
);
1297 UpdateWindow(hWndHeader
);
1298 proc(g_CustomDrawCount
, NULL
);
1299 g_CustomDrawProc
= NULL
;
1302 static void test_customdraw(void)
1307 CHAR name
[] = "Test";
1308 hWndHeader
= create_header_control();
1309 GetClientRect(hWndHeader
, &rect
);
1310 ok(rect
.right
- rect
.left
== 670 && rect
.bottom
- rect
.top
== 18,
1311 "Tests will fail as header size is %dx%d instead of 670x18\n",
1312 rect
.right
- rect
.left
== 670, rect
.bottom
- rect
.top
== 18);
1314 for (i
= 0; i
< 3; i
++)
1316 ZeroMemory(&item
, sizeof(item
));
1317 item
.mask
= HDI_TEXT
|HDI_WIDTH
;
1318 item
.cxy
= 50*(i
+1);
1319 item
.pszText
= name
;
1321 SendMessage(hWndHeader
, HDM_INSERTITEM
, i
, (LPARAM
)&item
);
1324 run_customdraw_scenario(customdraw_1
);
1325 run_customdraw_scenario(customdraw_2
);
1326 run_customdraw_scenario(customdraw_3
);
1328 ZeroMemory(&item
, sizeof(item
));
1329 item
.mask
= HDI_FORMAT
;
1330 item
.fmt
= HDF_OWNERDRAW
;
1331 SendMessage(hWndHeader
, HDM_SETITEM
, 1, (LPARAM
)&item
);
1332 g_DrawItem
.CtlID
= 0;
1333 g_DrawItem
.CtlType
= ODT_HEADER
;
1334 g_DrawItem
.hwndItem
= hWndHeader
;
1335 g_DrawItem
.itemID
= 1;
1336 g_DrawItem
.itemState
= 0;
1337 SendMessage(hWndHeader
, HDM_GETITEMRECT
, 1, (LPARAM
)&g_DrawItem
.rcItem
);
1338 run_customdraw_scenario(customdraw_4
);
1339 ok(g_DrawItemReceived
, "WM_DRAWITEM not received\n");
1340 DestroyWindow(hWndHeader
);
1342 g_DrawItem
.CtlType
= 0;
1343 g_DrawItemReceived
= FALSE
;
1346 static void check_order(const int expected_id
[], const int expected_order
[],
1347 int count
, const char *type
)
1352 ok(getItemCount(hWndHeader
) == count
, "Invalid item count in order tests\n");
1353 for (i
= 0; i
< count
; i
++)
1355 hdi
.mask
= HDI_LPARAM
|HDI_ORDER
;
1356 SendMessage(hWndHeader
, HDM_GETITEMA
, i
, (LPARAM
)&hdi
);
1357 ok(hdi
.lParam
== expected_id
[i
],
1358 "Invalid item ids after '%s'- item %d has lParam %d\n", type
, i
, (int)hdi
.lParam
);
1359 ok(hdi
.iOrder
== expected_order
[i
],
1360 "Invalid item order after '%s'- item %d has iOrder %d\n", type
, i
, hdi
.iOrder
);
1364 static void test_header_order (void)
1366 const int rand1
[] = {0, 1, 1, 0, 4};
1367 const int rand2
[] = {4, 5, 6, 7, 4};
1368 const int rand3
[] = {5, 5, 1, 6, 1};
1369 const int rand4
[] = {1, 5, 2, 7, 6, 1, 4, 2, 3, 2};
1370 const int rand5
[] = {7, 8, 5, 6, 7, 2, 1, 9, 10, 10};
1371 const int rand6
[] = {2, 8, 3, 4, 0};
1373 const int ids1
[] = {3, 0, 2, 1, 4};
1374 const int ord1
[] = {0, 1, 2, 3, 4};
1375 const int ids2
[] = {3, 9, 7, 0, 2, 1, 4, 8, 6, 5};
1376 const int ord2
[] = {0, 4, 7, 1, 2, 3, 9, 8, 6, 5};
1377 const int ord3
[] = {0, 3, 9, 2, 1, 8, 7, 6, 5, 4};
1378 const int ids4
[] = {9, 0, 1, 8, 6};
1379 const int ord4
[] = {1, 0, 4, 3, 2};
1385 hWndHeader
= create_header_control();
1387 ZeroMemory(&hdi
, sizeof(HDITEMA
));
1388 hdi
.mask
= HDI_TEXT
| HDI_LPARAM
;
1389 hdi
.pszText
= buffer
;
1390 strcpy(buffer
, "test");
1392 for (i
= 0; i
< 5; i
++)
1395 SendMessage(hWndHeader
, HDM_INSERTITEMA
, rand1
[i
], (LPARAM
)&hdi
);
1398 check_order(ids1
, ord1
, 5, "insert without iOrder");
1400 hdi
.mask
|= HDI_ORDER
;
1401 for (i
= 0; i
< 5; i
++)
1404 hdi
.iOrder
= rand2
[i
];
1405 SendMessage(hWndHeader
, HDM_INSERTITEMA
, rand3
[i
], (LPARAM
)&hdi
);
1408 check_order(ids2
, ord2
, 10, "insert with order");
1410 hdi
.mask
= HDI_ORDER
;
1411 for (i
=0; i
<10; i
++)
1413 hdi
.iOrder
= rand5
[i
];
1414 SendMessage(hWndHeader
, HDM_SETITEMA
, rand4
[i
], (LPARAM
)&hdi
);
1417 check_order(ids2
, ord3
, 10, "setitems changing order");
1420 SendMessage(hWndHeader
, HDM_DELETEITEM
, rand6
[i
], 0);
1421 check_order(ids4
, ord4
, 5, "deleteitem");
1423 DestroyWindow(hWndHeader
);
1426 static LRESULT CALLBACK
HeaderTestWndProc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1433 NMHEADERA
*hdr
= (NMHEADER
*)lParam
;
1434 EXPECTEDNOTIFY
*expected
;
1437 if (hdr
->hdr
.code
== NM_CUSTOMDRAW
)
1438 if (g_CustomDrawProc
)
1439 return g_CustomDrawProc(g_CustomDrawCount
++, (NMCUSTOMDRAW
*)hdr
);
1441 for (i
=0; i
<nUnexpectedNotify
; i
++)
1442 ok(hdr
->hdr
.code
!= unexpectedNotify
[i
], "Received invalid notify %d\n", hdr
->hdr
.code
);
1444 if (nReceivedNotify
>= nExpectedNotify
|| hdr
->hdr
.hwndFrom
!= hWndHeader
)
1447 expected
= &expectedNotify
[nReceivedNotify
];
1448 if (hdr
->hdr
.code
!= expected
->iCode
)
1452 compare_items(hdr
->hdr
.code
, &expected
->hdItem
, hdr
->pitem
, expected
->fUnicode
);
1457 di
= (DRAWITEMSTRUCT
*)lParam
;
1458 ok(g_DrawItem
.CtlType
!= 0, "Unexpected WM_DRAWITEM\n");
1459 if (g_DrawItem
.CtlType
== 0) return 0;
1460 g_DrawItemReceived
= TRUE
;
1461 compare(di
->CtlType
, g_DrawItem
.CtlType
, "%d");
1462 compare(di
->CtlID
, g_DrawItem
.CtlID
, "%d");
1463 compare(di
->hwndItem
, g_DrawItem
.hwndItem
, "%p");
1464 compare(di
->itemID
, g_DrawItem
.itemID
, "%d");
1465 compare(di
->itemState
, g_DrawItem
.itemState
, "%d");
1466 compare(di
->rcItem
.left
, g_DrawItem
.rcItem
.left
, "%d");
1467 compare(di
->rcItem
.top
, g_DrawItem
.rcItem
.top
, "%d");
1468 compare(di
->rcItem
.right
, g_DrawItem
.rcItem
.right
, "%d");
1469 compare(di
->rcItem
.bottom
, g_DrawItem
.rcItem
.bottom
, "%d");
1477 return DefWindowProcA(hWnd
, msg
, wParam
, lParam
);
1483 static void init(void) {
1485 INITCOMMONCONTROLSEX icex
;
1487 icex
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
1488 icex
.dwICC
= ICC_USEREX_CLASSES
;
1489 InitCommonControlsEx(&icex
);
1491 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
1494 wc
.hInstance
= GetModuleHandleA(NULL
);
1496 wc
.hCursor
= LoadCursorA(NULL
, MAKEINTRESOURCEA(IDC_ARROW
));
1497 wc
.hbrBackground
= GetSysColorBrush(COLOR_WINDOW
);
1498 wc
.lpszMenuName
= NULL
;
1499 wc
.lpszClassName
= "HeaderTestClass";
1500 wc
.lpfnWndProc
= HeaderTestWndProc
;
1501 RegisterClassA(&wc
);
1503 hHeaderParentWnd
= CreateWindowExA(0, "HeaderTestClass", "Header test", WS_OVERLAPPEDWINDOW
,
1504 CW_USEDEFAULT
, CW_USEDEFAULT
, 672+2*GetSystemMetrics(SM_CXSIZEFRAME
),
1505 226+GetSystemMetrics(SM_CYCAPTION
)+2*GetSystemMetrics(SM_CYSIZEFRAME
),
1506 NULL
, NULL
, GetModuleHandleA(NULL
), 0);
1507 assert(hHeaderParentWnd
!= NULL
);
1508 ShowWindow(hHeaderParentWnd
, SW_SHOW
);
1517 test_header_control();
1518 test_header_order();
1521 DestroyWindow(hHeaderParentWnd
);
1523 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
1524 parent_hwnd
= create_custom_parent_window();
1525 ok_sequence(sequences
, PARENT_SEQ_INDEX
, create_parent_wnd_seq
, "create parent windows", FALSE
);
1527 test_hdm_index_messages(parent_hwnd
);
1528 test_hdm_getitemrect(parent_hwnd
);
1529 test_hdm_hittest(parent_hwnd
);
1530 test_hdm_layout(parent_hwnd
);
1531 test_hdm_ordertoindex(parent_hwnd
);
1532 test_hdm_sethotdivider(parent_hwnd
);
1533 test_hdm_imageMessages(parent_hwnd
);
1534 test_hdm_filterMessages(parent_hwnd
);
1535 test_hdm_unicodeformatMessages(parent_hwnd
);
1536 test_hdm_bitmapmarginMessages(parent_hwnd
);
1538 DestroyWindow(parent_hwnd
);