opengl32: Correctly interpret glMapBuffer() access in wow64 mapping.
[wine.git] / dlls / comctl32 / tests / header.c
blobc027d292385a54c6540d421eb644a8cef3cbdf99
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
22 #include <windows.h>
23 #include <commctrl.h>
25 #include "wine/test.h"
26 #include "v6util.h"
27 #include "msg.h"
29 static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
30 static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
32 typedef struct tagEXPECTEDNOTIFY
34 INT iCode;
35 BOOL fUnicode;
36 HDITEMA hdItem;
37 } EXPECTEDNOTIFY;
39 typedef LRESULT (*CUSTOMDRAWPROC)(int n, NMCUSTOMDRAW *nm);
41 static CUSTOMDRAWPROC g_CustomDrawProc;
42 static int g_CustomDrawCount;
43 static DRAWITEMSTRUCT g_DrawItem;
44 static BOOL g_DrawItemReceived;
45 static DWORD g_customheight;
47 static EXPECTEDNOTIFY expectedNotify[10];
48 static INT nExpectedNotify = 0;
49 static INT nReceivedNotify = 0;
50 static INT unexpectedNotify[10];
51 static INT nUnexpectedNotify = 0;
53 static HWND hHeaderParentWnd;
54 static HWND hWndHeader;
55 #define MAX_CHARS 100
57 #define compare(val, exp, fmt) ok((val) == (exp), #val " value: " fmt ", expected: " fmt "\n", (val), (exp))
59 #define expect(expected,got) expect_(__LINE__, expected, got)
60 static inline void expect_(unsigned line, DWORD expected, DWORD got)
62 ok_(__FILE__, line)(expected == got, "Expected %ld, got %ld\n", expected, got);
65 #define NUM_MSG_SEQUENCES 2
66 #define PARENT_SEQ_INDEX 0
67 #define HEADER_SEQ_INDEX 1
69 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
71 static const struct message create_parent_wnd_seq[] = {
72 { WM_GETMINMAXINFO, sent },
73 { WM_NCCREATE, sent },
74 { WM_NCCALCSIZE, sent|wparam, 0 },
75 { WM_CREATE, sent },
76 { 0 }
79 static const struct message add_header_to_parent_seq_interactive[] = {
80 { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
81 { WM_QUERYUISTATE, sent },
82 { WM_PARENTNOTIFY, sent|wparam, 1 },
83 { WM_SHOWWINDOW, sent|wparam, 1 },
84 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
85 { WM_WINDOWPOSCHANGING, sent|wparam, 0 },
86 { WM_ACTIVATEAPP, sent|wparam, 1 },
87 { WM_NCACTIVATE, sent|wparam, 1 },
88 { WM_ACTIVATE, sent|wparam, 1 },
89 { WM_IME_SETCONTEXT, sent|defwinproc|wparam, 1 },
90 { WM_IME_NOTIFY, sent|defwinproc|wparam, 2 },
91 { WM_SETFOCUS, sent|defwinproc|wparam, 0 },
92 { WM_WINDOWPOSCHANGED, sent|wparam, 0 },
93 { WM_SIZE, sent|wparam, 0 },
94 { WM_MOVE, sent|wparam, 0 },
95 { 0 }
98 static const struct message add_header_to_parent_seq[] = {
99 { WM_NOTIFYFORMAT, sent|lparam, 0, NF_QUERY },
100 { WM_QUERYUISTATE, sent|optional },
101 { WM_PARENTNOTIFY, sent },
102 { 0 }
105 static const struct message insertItem_seq[] = {
106 { HDM_INSERTITEMA, sent|wparam, 0 },
107 { HDM_INSERTITEMA, sent|wparam, 1 },
108 { HDM_INSERTITEMA, sent|wparam, 2 },
109 { HDM_INSERTITEMA, sent|wparam, 3 },
110 { 0 }
113 static const struct message getItem_seq[] = {
114 { HDM_GETITEMA, sent|wparam, 3 },
115 { HDM_GETITEMA, sent|wparam, 0 },
116 { 0 }
120 static const struct message deleteItem_getItemCount_seq[] = {
121 { HDM_DELETEITEM, sent|wparam, 3 },
122 { HDM_GETITEMCOUNT, sent },
123 { HDM_DELETEITEM, sent|wparam, 3 },
124 { HDM_GETITEMCOUNT, sent },
125 { HDM_DELETEITEM, sent|wparam, 2 },
126 { HDM_GETITEMCOUNT, sent },
127 { 0 }
130 static const struct message orderArray_seq[] = {
131 { HDM_SETORDERARRAY, sent|wparam, 2 },
132 { HDM_GETORDERARRAY, sent|wparam, 2 },
133 { 0 }
136 static const struct message setItem_seq[] = {
137 { HDM_SETITEMA, sent|wparam, 0 },
138 { HDM_SETITEMA, sent|wparam, 1 },
139 { 0 }
142 static const struct message getItemRect_seq[] = {
143 { HDM_GETITEMRECT, sent|wparam, 1 },
144 { HDM_GETITEMRECT, sent|wparam, 0 },
145 { HDM_GETITEMRECT, sent|wparam, 10 },
146 { 0 }
149 static const struct message layout_seq[] = {
150 { HDM_LAYOUT, sent },
151 { 0 }
154 static const struct message orderToIndex_seq[] = {
155 { HDM_ORDERTOINDEX, sent|wparam, 1 },
156 { 0 }
159 static const struct message hittest_seq[] = {
160 { HDM_HITTEST, sent },
161 { HDM_HITTEST, sent },
162 { HDM_HITTEST, sent },
163 { 0 }
166 static const struct message setHotDivider_seq_interactive[] = {
167 { HDM_SETHOTDIVIDER, sent|wparam, TRUE },
168 { WM_PAINT, sent|defwinproc},
169 { WM_NCPAINT, sent|defwinproc},
170 { WM_ERASEBKGND, sent|defwinproc},
171 { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 100 },
172 { WM_PAINT, sent|defwinproc},
173 { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 1},
174 { WM_PAINT, sent|defwinproc},
175 { 0 }
178 static const struct message setHotDivider_seq_noninteractive[] = {
179 { HDM_SETHOTDIVIDER, sent|wparam, TRUE },
180 { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 100 },
181 { HDM_SETHOTDIVIDER, sent|wparam|lparam, FALSE, 1},
182 { 0 }
185 static const struct message imageMessages_seq[] = {
186 { HDM_SETIMAGELIST, sent },
187 { HDM_GETIMAGELIST, sent },
188 { HDM_CREATEDRAGIMAGE, sent },
189 { 0 }
192 static const struct message filterMessages_seq_interactive[] = {
193 { HDM_SETFILTERCHANGETIMEOUT, sent|wparam|lparam, 1, 100 },
194 { HDM_CLEARFILTER, sent|wparam|lparam, 0, 1 },
195 { HDM_EDITFILTER, sent|wparam|lparam, 1, 0 },
196 { WM_PARENTNOTIFY, sent|wparam|defwinproc, WM_CREATE },
197 { WM_CTLCOLOREDIT, sent|defwinproc },
198 { WM_COMMAND, sent|defwinproc },
199 { 0 }
202 static const struct message filterMessages_seq_noninteractive[] = {
203 { HDM_SETFILTERCHANGETIMEOUT, sent|wparam|lparam, 1, 100 },
204 { HDM_CLEARFILTER, sent|wparam|lparam, 0, 1 },
205 { HDM_EDITFILTER, sent|wparam|lparam, 1, 0 },
206 { WM_PARENTNOTIFY, sent|wparam|defwinproc|optional, WM_CREATE },
207 { WM_COMMAND, sent|defwinproc|optional },
208 { 0 }
211 static const struct message unicodeformatMessages_seq[] = {
212 { HDM_SETUNICODEFORMAT, sent|wparam, TRUE },
213 { HDM_GETUNICODEFORMAT, sent },
214 { 0 }
217 static const struct message bitmapmarginMessages_seq[] = {
218 { HDM_GETBITMAPMARGIN, sent },
219 { 0 }
223 static void expect_notify(INT iCode, BOOL fUnicode, HDITEMA *lpItem)
225 ok(nExpectedNotify < 10, "notification count %d\n", nExpectedNotify);
226 if (nExpectedNotify < 10)
228 expectedNotify[nExpectedNotify].iCode = iCode;
229 expectedNotify[nExpectedNotify].fUnicode = fUnicode;
230 expectedNotify[nExpectedNotify].hdItem = *lpItem;
231 nExpectedNotify++;
235 static void dont_expect_notify(INT iCode)
237 ok(nExpectedNotify < 10, "notification count %d\n", nExpectedNotify);
238 if (nExpectedNotify < 10)
239 unexpectedNotify[nUnexpectedNotify++] = iCode;
242 static BOOL notifies_received(void)
244 BOOL fRet = (nExpectedNotify == nReceivedNotify);
245 nExpectedNotify = nReceivedNotify = 0;
246 nUnexpectedNotify = 0;
247 return fRet;
250 static LONG addItem(HWND hdex, int idx, LPSTR text)
252 HDITEMA hdItem;
253 hdItem.mask = HDI_TEXT | HDI_WIDTH;
254 hdItem.cxy = 100;
255 hdItem.pszText = text;
256 hdItem.cchTextMax = 0;
257 return SendMessageA(hdex, HDM_INSERTITEMA, idx, (LPARAM)&hdItem);
260 static LONG setItem(HWND hdex, int idx, LPSTR text, BOOL fCheckNotifies)
262 LONG ret;
263 HDITEMA hdexItem;
264 hdexItem.mask = HDI_TEXT;
265 hdexItem.pszText = text;
266 hdexItem.cchTextMax = 0;
267 if (fCheckNotifies)
269 expect_notify(HDN_ITEMCHANGINGA, FALSE, &hdexItem);
270 expect_notify(HDN_ITEMCHANGEDA, FALSE, &hdexItem);
272 ret = SendMessageA(hdex, HDM_SETITEMA, idx, (LPARAM)&hdexItem);
273 if (fCheckNotifies)
274 ok(notifies_received(), "setItem(): not all expected notifies were received\n");
275 return ret;
278 static LONG setItemUnicodeNotify(HWND hdex, int idx, LPSTR text, LPWSTR wText)
280 LONG ret;
281 HDITEMA hdexItem;
282 HDITEMW hdexNotify;
283 hdexItem.mask = HDI_TEXT;
284 hdexItem.pszText = text;
285 hdexItem.cchTextMax = 0;
287 hdexNotify.mask = HDI_TEXT;
288 hdexNotify.pszText = wText;
290 expect_notify(HDN_ITEMCHANGINGW, TRUE, (HDITEMA*)&hdexNotify);
291 expect_notify(HDN_ITEMCHANGEDW, TRUE, (HDITEMA*)&hdexNotify);
292 ret = SendMessageA(hdex, HDM_SETITEMA, idx, (LPARAM)&hdexItem);
293 ok(notifies_received(), "setItemUnicodeNotify(): not all expected notifies were received\n");
294 return ret;
297 static LONG delItem(HWND hdex, int idx)
299 return SendMessageA(hdex, HDM_DELETEITEM, idx, 0);
302 static LONG getItemCount(HWND hdex)
304 return SendMessageA(hdex, HDM_GETITEMCOUNT, 0, 0);
307 static LONG getItem(HWND hdex, int idx, LPSTR textBuffer)
309 HDITEMA hdItem;
310 hdItem.mask = HDI_TEXT;
311 hdItem.pszText = textBuffer;
312 hdItem.cchTextMax = MAX_CHARS;
313 return SendMessageA(hdex, HDM_GETITEMA, idx, (LPARAM)&hdItem);
316 static void addReadDelItem(HWND hdex, HDITEMA *phdiCreate, int maskRead, HDITEMA *phdiRead)
318 ok(SendMessageA(hdex, HDM_INSERTITEMA, 0, (LPARAM)phdiCreate)!=-1, "Adding item failed\n");
319 ZeroMemory(phdiRead, sizeof(HDITEMA));
320 phdiRead->mask = maskRead;
321 ok(SendMessageA(hdex, HDM_GETITEMA, 0, (LPARAM)phdiRead)!=0, "Getting item data failed\n");
322 ok(SendMessageA(hdex, HDM_DELETEITEM, 0, 0)!=0, "Deleting item failed\n");
325 static HWND create_header_control (void)
327 HWND handle;
328 HDLAYOUT hlayout;
329 RECT rectwin;
330 WINDOWPOS winpos;
332 handle = CreateWindowExA(0, WC_HEADERA, NULL,
333 WS_CHILD|WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
334 0, 0, 0, 0,
335 hHeaderParentWnd, NULL, NULL, NULL);
336 ok(handle != NULL, "failed to create header window\n");
338 if (winetest_interactive)
339 ShowWindow (hHeaderParentWnd, SW_SHOW);
341 GetClientRect(hHeaderParentWnd,&rectwin);
342 hlayout.prc = &rectwin;
343 hlayout.pwpos = &winpos;
344 SendMessageA(handle, HDM_LAYOUT, 0, (LPARAM)&hlayout);
345 SetWindowPos(handle, winpos.hwndInsertAfter, winpos.x, winpos.y,
346 winpos.cx, winpos.cy, 0);
348 return handle;
351 static void compare_items(INT iCode, HDITEMA *hdi1, HDITEMA *hdi2, BOOL fUnicode)
353 ok(hdi1->mask == hdi2->mask, "Notify %d mask mismatch (%08x != %08x)\n", iCode, hdi1->mask, hdi2->mask);
354 if (hdi1->mask & HDI_WIDTH)
356 ok(hdi1->cxy == hdi2->cxy, "Notify %d cxy mismatch (%08x != %08x)\n", iCode, hdi1->cxy, hdi2->cxy);
358 if (hdi1->mask & HDI_TEXT)
360 if (hdi1->pszText == LPSTR_TEXTCALLBACKA)
362 ok(hdi1->pszText == LPSTR_TEXTCALLBACKA, "Notify %d - only one item is LPSTR_TEXTCALLBACK\n", iCode);
364 else
365 if (fUnicode)
367 char buf1[260];
368 char buf2[260];
369 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)hdi1->pszText, -1, buf1, 260, NULL, NULL);
370 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)hdi2->pszText, -1, buf2, 260, NULL, NULL);
371 ok(lstrcmpW((LPWSTR)hdi1->pszText, (LPWSTR)hdi2->pszText)==0,
372 "Notify %d text mismatch (L\"%s\" vs L\"%s\")\n",
373 iCode, buf1, buf2);
375 else
377 ok(strcmp(hdi1->pszText, hdi2->pszText)==0,
378 "Notify %d text mismatch (\"%s\" vs \"%s\")\n",
379 iCode, hdi1->pszText, hdi2->pszText);
384 static char pszFirstItem[] = "First Item";
385 static char pszSecondItem[] = "Second Item";
386 static char pszThirdItem[] = "Third Item";
387 static char pszFourthItem[] = "Fourth Item";
388 static char pszReplaceItem[] = "Replace Item";
389 static char pszOutOfRangeItem[] = "Out Of Range Item";
391 static char *str_items[] =
392 {pszFirstItem, pszSecondItem, pszThirdItem, pszFourthItem, pszReplaceItem, pszOutOfRangeItem};
394 static char pszUniTestA[] = "TST";
395 static WCHAR pszUniTestW[] = {'T','S','T',0};
398 #define TEST_GET_ITEM(i,c)\
399 { res = getItem(hWndHeader, i, buffer);\
400 ok(res != 0, "Getting item[%d] using valid index failed unexpectedly (%ld)\n", i, res);\
401 ok(strcmp(str_items[c], buffer) == 0, "Getting item[%d] returned \"%s\" expecting \"%s\"\n", i, buffer, str_items[c]);\
404 #define TEST_GET_ITEMCOUNT(i)\
405 { res = getItemCount(hWndHeader);\
406 ok(res == i, "Got Item Count as %ld\n", res);\
409 static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
411 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
412 static LONG defwndproc_counter = 0;
413 struct message msg = { 0 };
414 LRESULT ret;
416 msg.message = message;
417 msg.flags = sent|wparam|lparam;
418 if (defwndproc_counter) msg.flags |= defwinproc;
419 msg.wParam = wParam;
420 msg.lParam = lParam;
421 add_message(sequences, HEADER_SEQ_INDEX, &msg);
423 defwndproc_counter++;
424 ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
425 defwndproc_counter--;
427 return ret;
430 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
432 static LONG defwndproc_counter = 0;
433 LRESULT ret;
434 struct message msg;
436 /* do not log painting messages */
437 if (message != WM_PAINT &&
438 message != WM_ERASEBKGND &&
439 message != WM_NCPAINT &&
440 message != WM_NCHITTEST &&
441 message != WM_GETTEXT &&
442 message != WM_GETICON &&
443 message != WM_DEVICECHANGE)
446 msg.message = message;
447 msg.flags = sent|wparam|lparam;
448 if (defwndproc_counter) msg.flags |= defwinproc;
449 msg.wParam = wParam;
450 msg.lParam = lParam;
451 msg.id = 0;
452 add_message(sequences, PARENT_SEQ_INDEX, &msg);
455 defwndproc_counter++;
456 ret = DefWindowProcA(hwnd, message, wParam, lParam);
457 defwndproc_counter--;
459 return ret;
462 static BOOL register_parent_wnd_class(void)
464 WNDCLASSA cls;
466 cls.style = 0;
467 cls.lpfnWndProc = parent_wnd_proc;
468 cls.cbClsExtra = 0;
469 cls.cbWndExtra = 0;
470 cls.hInstance = GetModuleHandleA(NULL);
471 cls.hIcon = 0;
472 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
473 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
474 cls.lpszMenuName = NULL;
475 cls.lpszClassName = "Header test parent class";
476 return RegisterClassA(&cls);
479 static HWND create_custom_parent_window(void)
481 if (!register_parent_wnd_class())
482 return NULL;
484 return CreateWindowExA(0, "Header test parent class", "Header Message Sequence Testing",
485 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
486 672+2*GetSystemMetrics(SM_CXSIZEFRAME),
487 226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
488 NULL, NULL, GetModuleHandleA(NULL), 0);
491 static HWND create_custom_header_control(HWND hParent, BOOL preloadHeaderItems)
493 WNDPROC oldproc;
494 HWND childHandle;
495 HDLAYOUT hlayout;
496 RECT rectwin;
497 WINDOWPOS winpos;
498 int retVal;
499 int loopcnt;
500 static char firstHeaderItem[] = "Name";
501 static char secondHeaderItem[] = "Size";
502 static char *items[] = {secondHeaderItem, firstHeaderItem};
503 HDITEMA hdItem;
504 hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT;
505 hdItem.fmt = HDF_LEFT;
506 hdItem.cxy = 80;
507 hdItem.cchTextMax = 260;
509 flush_sequences(sequences, NUM_MSG_SEQUENCES);
511 childHandle = CreateWindowExA(0, WC_HEADERA, NULL,
512 WS_CHILD|WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
513 0, 0, 0, 0,
514 hParent, NULL, NULL, NULL);
515 ok(childHandle != NULL, "failed to create child window\n");
516 if (preloadHeaderItems)
518 for ( loopcnt = 0 ; loopcnt < 2 ; loopcnt++ )
520 hdItem.pszText = items[loopcnt];
521 retVal = SendMessageA(childHandle, HDM_INSERTITEMA, 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 oldproc = (WNDPROC)SetWindowLongPtrA(childHandle, GWLP_WNDPROC,
537 (LONG_PTR)header_subclass_proc);
538 SetWindowLongPtrA(childHandle, GWLP_USERDATA, (LONG_PTR)oldproc);
539 return childHandle;
542 static void header_item_getback(HWND hwnd, UINT mask, HDITEMA *item)
544 int ret;
546 ret = SendMessageA(hwnd, HDM_INSERTITEMA, 0, (LPARAM)item);
547 ok(ret != -1, "Failed to add header item.\n");
549 memset(item, 0, sizeof(*item));
550 item->mask = mask;
552 ret = SendMessageA(hwnd, HDM_GETITEMA, 0, (LPARAM)item);
553 ok(ret != 0, "Failed to get item data.\n");
554 ret = SendMessageA(hwnd, HDM_DELETEITEM, 0, 0);
555 ok(ret != 0, "Failed to delete item.\n");
558 static void test_item_auto_format(HWND parent)
560 static char text[] = "Test";
561 HDITEMA item;
562 HBITMAP hbm;
563 HWND hwnd;
565 hwnd = create_custom_header_control(parent, FALSE);
567 /* Windows implicitly sets some format bits in INSERTITEM */
569 /* HDF_STRING is automatically set and cleared for no text */
570 item.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT;
571 item.pszText = text;
572 item.cxy = 100;
573 item.fmt = HDF_CENTER;
574 header_item_getback(hwnd, HDI_FORMAT, &item);
575 ok(item.fmt == (HDF_STRING | HDF_CENTER), "Unexpected item format mask %#x.\n", item.fmt);
577 item.mask = HDI_WIDTH | HDI_FORMAT;
578 item.pszText = text;
579 item.fmt = HDF_CENTER | HDF_STRING;
580 header_item_getback(hwnd, HDI_FORMAT, &item);
581 ok(item.fmt == HDF_CENTER, "Unexpected item format mask %#x.\n", item.fmt);
583 /* HDF_BITMAP is automatically set and cleared for a NULL bitmap or no bitmap */
584 item.mask = HDI_BITMAP | HDI_WIDTH | HDI_FORMAT;
585 item.hbm = hbm = CreateBitmap(16, 16, 1, 8, NULL);
586 item.fmt = HDF_CENTER;
587 header_item_getback(hwnd, HDI_FORMAT, &item);
588 ok(item.fmt == (HDF_BITMAP | HDF_CENTER), "Unexpected item format mask %#x.\n", item.fmt);
589 DeleteObject(hbm);
591 item.mask = HDI_BITMAP | HDI_WIDTH | HDI_FORMAT;
592 item.hbm = NULL;
593 item.fmt = HDF_CENTER | HDF_BITMAP;
594 header_item_getback(hwnd, HDI_FORMAT, &item);
595 ok(item.fmt == HDF_CENTER, "Unexpected item format mask %#x.\n", item.fmt);
597 item.mask = HDI_WIDTH | HDI_FORMAT;
598 item.fmt = HDF_CENTER | HDF_BITMAP;
599 header_item_getback(hwnd, HDI_FORMAT, &item);
600 ok(item.fmt == HDF_CENTER, "Unexpected item format mask %#x.\n", item.fmt);
602 /* HDF_IMAGE is automatically set but not cleared */
603 item.mask = HDI_IMAGE | HDI_WIDTH | HDI_FORMAT;
604 item.iImage = 17;
605 header_item_getback(hwnd, HDI_FORMAT, &item);
606 ok(item.fmt == (HDF_IMAGE | HDF_CENTER), "Unexpected item format mask %#x.\n", item.fmt);
608 item.mask = HDI_WIDTH | HDI_FORMAT;
609 item.fmt = HDF_CENTER | HDF_IMAGE;
610 item.iImage = 0;
611 header_item_getback(hwnd, HDI_FORMAT, &item);
612 ok(item.fmt == (HDF_CENTER | HDF_IMAGE), "Unexpected item format mask %#x.\n", item.fmt);
614 DestroyWindow(hwnd);
617 static void check_auto_fields(void)
619 HDITEMA hdiCreate;
620 HDITEMA hdiRead;
621 static CHAR text[] = "Test";
622 LONG res;
624 /* Windows stores the format, width, lparam even if they are not in the item's mask */
625 ZeroMemory(&hdiCreate, sizeof(HDITEMA));
626 hdiCreate.mask = HDI_TEXT;
627 hdiCreate.cxy = 100;
628 hdiCreate.pszText = text;
629 addReadDelItem(hWndHeader, &hdiCreate, HDI_WIDTH, &hdiRead);
630 TEST_GET_ITEMCOUNT(6);
631 ok(hdiRead.cxy == hdiCreate.cxy, "cxy should be automatically set\n");
633 ZeroMemory(&hdiCreate, sizeof(HDITEMA));
634 hdiCreate.mask = HDI_TEXT;
635 hdiCreate.pszText = text;
636 hdiCreate.lParam = 0x12345678;
637 addReadDelItem(hWndHeader, &hdiCreate, HDI_LPARAM, &hdiRead);
638 TEST_GET_ITEMCOUNT(6);
639 ok(hdiRead.lParam == hdiCreate.lParam, "lParam should be automatically set\n");
641 ZeroMemory(&hdiCreate, sizeof(HDITEMA));
642 hdiCreate.mask = HDI_TEXT;
643 hdiCreate.pszText = text;
644 hdiCreate.fmt = HDF_STRING|HDF_CENTER;
645 addReadDelItem(hWndHeader, &hdiCreate, HDI_FORMAT, &hdiRead);
646 TEST_GET_ITEMCOUNT(6);
647 ok(hdiRead.fmt == hdiCreate.fmt, "fmt should be automatically set\n");
649 /* others fields are not set */
650 ZeroMemory(&hdiCreate, sizeof(HDITEMA));
651 hdiCreate.mask = HDI_TEXT;
652 hdiCreate.pszText = text;
653 hdiCreate.hbm = CreateBitmap(16, 16, 1, 8, NULL);
654 addReadDelItem(hWndHeader, &hdiCreate, HDI_BITMAP, &hdiRead);
655 TEST_GET_ITEMCOUNT(6);
656 ok(hdiRead.hbm == NULL, "hbm should not be automatically set\n");
657 DeleteObject(hdiCreate.hbm);
659 ZeroMemory(&hdiCreate, sizeof(HDITEMA));
660 hdiCreate.mask = HDI_IMAGE;
661 hdiCreate.iImage = 17;
662 hdiCreate.pszText = text;
663 addReadDelItem(hWndHeader, &hdiCreate, HDI_TEXT, &hdiRead);
664 TEST_GET_ITEMCOUNT(6);
665 ok(hdiRead.pszText==NULL, "pszText shouldn't be automatically set\n");
667 /* field from comctl >4.0 not tested as the system probably won't touch them */
670 static void check_mask(void)
672 HDITEMA hdi;
673 static CHAR text[] = "ABC";
674 LRESULT ret;
676 /* don't create items if the mask is zero */
677 ZeroMemory(&hdi, sizeof(hdi));
678 hdi.mask = 0;
679 hdi.cxy = 200;
680 hdi.pszText = text;
681 hdi.fmt = 0;
682 hdi.iOrder = 0;
683 hdi.lParam = 17;
684 hdi.cchTextMax = 260;
685 ret = SendMessageA(hWndHeader, HDM_INSERTITEMA, 0, (LPARAM)&hdi);
686 ok(ret == -1, "Creating an item with a zero mask should have failed\n");
687 if (ret != -1) SendMessageA(hWndHeader, HDM_DELETEITEM, 0, 0);
689 /* with a non-zero mask creation will succeed */
690 ZeroMemory(&hdi, sizeof(hdi));
691 hdi.mask = HDI_LPARAM;
692 ret = SendMessageA(hWndHeader, HDM_INSERTITEMA, 0, (LPARAM)&hdi);
693 ok(ret != -1, "Adding item with non-zero mask failed\n");
694 if (ret != -1)
695 SendMessageA(hWndHeader, HDM_DELETEITEM, 0, 0);
697 /* in SETITEM if the mask contains a unknown bit, it is ignored */
698 ZeroMemory(&hdi, sizeof(hdi));
699 hdi.mask = 0x08000000 | HDI_LPARAM | HDI_IMAGE;
700 hdi.lParam = 133;
701 hdi.iImage = 17;
702 ret = SendMessageA(hWndHeader, HDM_INSERTITEMA, 0, (LPARAM)&hdi);
703 ok(ret != -1, "Adding item failed\n");
705 if (ret != -1)
707 /* check result */
708 ZeroMemory(&hdi, sizeof(hdi));
709 hdi.mask = HDI_LPARAM | HDI_IMAGE;
710 SendMessageA(hWndHeader, HDM_GETITEMA, 0, (LPARAM)&hdi);
711 ok(hdi.lParam == 133, "comctl32 4.0 field not set\n");
712 ok(hdi.iImage == 17, "comctl32 >4.0 field not set\n");
714 /* but in GETITEM if an unknown bit is set, comctl32 uses only version 4.0 fields */
715 ZeroMemory(&hdi, sizeof(hdi));
716 hdi.mask = 0x08000000 | HDI_LPARAM | HDI_IMAGE;
717 SendMessageA(hWndHeader, HDM_GETITEMA, 0, (LPARAM)&hdi);
718 ok(hdi.lParam == 133, "comctl32 4.0 field not read\n");
719 ok(hdi.iImage == 0, "comctl32 >4.0 field shouldn't be read\n");
721 SendMessageA(hWndHeader, HDM_DELETEITEM, 0, 0);
725 static void test_header_control (void)
727 LONG res;
728 static char buffer[MAX_CHARS];
729 int i;
731 hWndHeader = create_header_control ();
733 for (i = 3; i >= 0; i--)
735 TEST_GET_ITEMCOUNT(3-i);
736 res = addItem(hWndHeader, 0, str_items[i]);
737 ok(res == 0, "Adding simple item failed (%ld)\n", res);
740 TEST_GET_ITEMCOUNT(4);
741 res = addItem(hWndHeader, 99, str_items[i+1]);
742 ok(res != -1, "Adding Out of Range item should fail with -1 got (%ld)\n", res);
743 TEST_GET_ITEMCOUNT(5);
744 res = addItem(hWndHeader, 5, str_items[i+1]);
745 ok(res != -1, "Adding Out of Range item should fail with -1 got (%ld)\n", res);
746 TEST_GET_ITEMCOUNT(6);
748 for (i = 0; i < 4; i++) { TEST_GET_ITEM(i,i); TEST_GET_ITEMCOUNT(6); }
750 res=getItem(hWndHeader, 99, buffer);
751 ok(res == 0, "Getting Out of Range item should fail with 0 (%ld), got %s\n", res,buffer);
752 res=getItem(hWndHeader, 5, buffer);
753 ok(res == 1, "Getting Out of Range item should fail with 1 (%ld), got %s\n", res,buffer);
754 res=getItem(hWndHeader, -2, buffer);
755 ok(res == 0, "Getting Out of Range item should fail with 0 (%ld), got %s\n", res,buffer);
757 if (winetest_interactive)
759 UpdateWindow(hHeaderParentWnd);
760 UpdateWindow(hWndHeader);
763 TEST_GET_ITEMCOUNT(6);
764 res=setItem(hWndHeader, 99, str_items[5], FALSE);
765 ok(res == 0, "Setting Out of Range item should fail with 0 (%ld)\n", res);
766 res=setItem(hWndHeader, 5, str_items[5], TRUE);
767 ok(res == 1, "Setting Out of Range item should fail with 1 (%ld)\n", res);
768 res=setItem(hWndHeader, -2, str_items[5], FALSE);
769 ok(res == 0, "Setting Out of Range item should fail with 0 (%ld)\n", res);
770 TEST_GET_ITEMCOUNT(6);
772 for (i = 0; i < 4; i++)
774 res = setItem(hWndHeader, i, str_items[4], TRUE);
775 ok(res != 0, "Setting %d item failed (%ld)\n", i+1, res);
776 TEST_GET_ITEM(i, 4);
777 TEST_GET_ITEMCOUNT(6);
780 SendMessageA(hWndHeader, HDM_SETUNICODEFORMAT, TRUE, 0);
781 setItemUnicodeNotify(hWndHeader, 3, pszUniTestA, pszUniTestW);
782 SendMessageA(hWndHeader, WM_NOTIFYFORMAT, (WPARAM)hHeaderParentWnd, NF_REQUERY);
783 setItem(hWndHeader, 3, str_items[4], TRUE);
785 dont_expect_notify(HDN_GETDISPINFOA);
786 dont_expect_notify(HDN_GETDISPINFOW);
787 addItem(hWndHeader, 0, LPSTR_TEXTCALLBACKA);
788 setItem(hWndHeader, 0, str_items[4], TRUE);
789 /* unexpected notifies cleared by notifies_received in setItem */
790 dont_expect_notify(HDN_GETDISPINFOA);
791 dont_expect_notify(HDN_GETDISPINFOW);
792 setItem(hWndHeader, 0, LPSTR_TEXTCALLBACKA, TRUE);
793 /* unexpected notifies cleared by notifies_received in setItem */
794 delItem(hWndHeader, 0);
796 TEST_GET_ITEMCOUNT(6);
797 check_auto_fields();
798 TEST_GET_ITEMCOUNT(6);
799 check_mask();
800 TEST_GET_ITEMCOUNT(6);
802 res = delItem(hWndHeader, 5);
803 ok(res == 1, "Deleting Out of Range item should fail with 1 (%ld)\n", res);
804 res = delItem(hWndHeader, -2);
805 ok(res == 0, "Deleting Out of Range item should fail with 0 (%ld)\n", res);
806 TEST_GET_ITEMCOUNT(5);
808 res = delItem(hWndHeader, 3);
809 ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
810 TEST_GET_ITEMCOUNT(4);
811 res = delItem(hWndHeader, 0);
812 ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
813 TEST_GET_ITEMCOUNT(3);
814 res = delItem(hWndHeader, 0);
815 ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
816 TEST_GET_ITEMCOUNT(2);
817 res = delItem(hWndHeader, 0);
818 ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
819 TEST_GET_ITEMCOUNT(1);
821 DestroyWindow(hWndHeader);
824 static void test_hdm_getitemrect(HWND hParent)
827 HWND hChild;
828 RECT rect;
829 int retVal;
831 flush_sequences(sequences, NUM_MSG_SEQUENCES);
832 hChild = create_custom_header_control(hParent, TRUE);
833 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
834 "adder header control to parent", FALSE);
836 retVal = SendMessageA(hChild, HDM_GETITEMRECT, 1, (LPARAM) &rect);
837 ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal);
838 /* check bounding rectangle information of 2nd header item */
839 expect(80, rect.left);
840 expect(0, rect.top);
841 expect(160, rect.right);
842 expect(g_customheight, rect.bottom);
844 retVal = SendMessageA(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect);
846 ok(retVal == TRUE, "Getting item rect should TRUE, got %d\n", retVal);
847 /* check bounding rectangle information of 1st header item */
848 expect(0, rect.left);
849 expect(0, rect.top);
851 expect(80, rect.right);
852 expect(g_customheight, rect.bottom);
854 retVal = SendMessageA(hChild, HDM_GETITEMRECT, 10, (LPARAM) &rect);
855 ok(retVal == 0, "Getting rect of nonexistent item should return 0, got %d\n", retVal);
857 ok_sequence(sequences, HEADER_SEQ_INDEX, getItemRect_seq, "getItemRect sequence testing", FALSE);
858 DestroyWindow(hChild);
861 static void test_hdm_layout(HWND hParent)
863 HWND hChild;
864 int retVal;
865 RECT rect;
866 HDLAYOUT hdLayout;
867 WINDOWPOS windowPos;
868 hdLayout.prc = &rect;
869 hdLayout.pwpos = &windowPos;
871 flush_sequences(sequences, NUM_MSG_SEQUENCES);
872 hChild = create_custom_header_control(hParent, TRUE);
873 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
874 "adder header control to parent", FALSE);
876 windowPos.hwnd = (HWND)0xdeadbeef;
877 flush_sequences(sequences, NUM_MSG_SEQUENCES);
878 retVal = SendMessageA(hChild, HDM_LAYOUT, 0, (LPARAM) &hdLayout);
879 expect(TRUE, retVal);
880 ok(windowPos.hwnd == (HWND)0xdeadbeef, "Unexpected value %p.\n", windowPos.hwnd);
881 ok(!windowPos.hwndInsertAfter, "Unexpected value %p.\n", windowPos.hwndInsertAfter);
883 ok_sequence(sequences, HEADER_SEQ_INDEX, layout_seq, "layout sequence testing", FALSE);
885 DestroyWindow(hChild);
888 static void test_hdm_ordertoindex(HWND hParent)
890 HWND hChild;
891 int retVal;
893 flush_sequences(sequences, NUM_MSG_SEQUENCES);
894 hChild = create_custom_header_control(hParent, TRUE);
895 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
896 "adder header control to parent", FALSE);
898 flush_sequences(sequences, NUM_MSG_SEQUENCES);
899 retVal = SendMessageA(hChild, HDM_ORDERTOINDEX, 1, 0);
900 expect(1, retVal);
902 ok_sequence(sequences, HEADER_SEQ_INDEX, orderToIndex_seq, "orderToIndex sequence testing", FALSE);
903 DestroyWindow(hChild);
906 static void test_hdm_hittest(HWND hParent)
908 HWND hChild;
909 int retVal;
910 POINT pt;
911 HDHITTESTINFO hdHitTestInfo;
912 const int firstItemRightBoundary = 80;
913 const int secondItemRightBoundary = 160;
914 const int bottomBoundary = g_customheight;
916 pt.x = firstItemRightBoundary - 1;
917 pt.y = bottomBoundary - 1;
918 hdHitTestInfo.pt = pt;
921 flush_sequences(sequences, NUM_MSG_SEQUENCES);
922 hChild = create_custom_header_control(hParent, TRUE);
923 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
924 "adder header control to parent", FALSE);
926 flush_sequences(sequences, NUM_MSG_SEQUENCES);
927 retVal = SendMessageA(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo);
928 expect(0, retVal);
929 expect(0, hdHitTestInfo.iItem);
930 expect(HHT_ONDIVIDER, hdHitTestInfo.flags);
932 pt.x = secondItemRightBoundary - 1;
933 pt.y = bottomBoundary - 1;
934 hdHitTestInfo.pt = pt;
935 retVal = SendMessageA(hChild, HDM_HITTEST, 1, (LPARAM) &hdHitTestInfo);
936 expect(1, retVal);
937 expect(1, hdHitTestInfo.iItem);
938 expect(HHT_ONDIVIDER, hdHitTestInfo.flags);
940 pt.x = secondItemRightBoundary;
941 pt.y = bottomBoundary + 1;
942 hdHitTestInfo.pt = pt;
943 retVal = SendMessageA(hChild, HDM_HITTEST, 0, (LPARAM) &hdHitTestInfo);
944 expect(-1, retVal);
945 expect(-1, hdHitTestInfo.iItem);
946 expect(HHT_BELOW, hdHitTestInfo.flags);
948 ok_sequence(sequences, HEADER_SEQ_INDEX, hittest_seq, "hittest sequence testing", FALSE);
950 DestroyWindow(hChild);
953 static void test_hdm_sethotdivider(HWND hParent)
955 HWND hChild;
956 int retVal;
957 /* low word: x coordinate = 5
958 * high word: y coordinate = 5
961 flush_sequences(sequences, NUM_MSG_SEQUENCES);
962 hChild = create_custom_header_control(hParent, TRUE);
963 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
964 "adder header control to parent", FALSE);
966 flush_sequences(sequences, NUM_MSG_SEQUENCES);
967 retVal = SendMessageA(hChild, HDM_SETHOTDIVIDER, TRUE, MAKELPARAM(5, 5));
968 expect(0, retVal);
970 retVal = SendMessageA(hChild, HDM_SETHOTDIVIDER, FALSE, 100);
971 expect(100, retVal);
972 retVal = SendMessageA(hChild, HDM_SETHOTDIVIDER, FALSE, 1);
973 expect(1, retVal);
974 if (winetest_interactive)
975 ok_sequence(sequences, HEADER_SEQ_INDEX, setHotDivider_seq_interactive,
976 "setHotDivider sequence testing", TRUE);
977 else
978 ok_sequence(sequences, HEADER_SEQ_INDEX, setHotDivider_seq_noninteractive,
979 "setHotDivider sequence testing", FALSE);
981 DestroyWindow(hChild);
984 static void test_hdm_imageMessages(HWND hParent)
986 HIMAGELIST hImageList = pImageList_Create (4, 4, 0, 1, 0);
987 HIMAGELIST hIml;
988 BOOL wasValid;
989 HWND hChild;
991 flush_sequences(sequences, NUM_MSG_SEQUENCES);
992 hChild = create_custom_header_control(hParent, TRUE);
993 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
994 "adder header control to parent", FALSE);
996 flush_sequences(sequences, NUM_MSG_SEQUENCES);
998 hIml = (HIMAGELIST) SendMessageA(hChild, HDM_SETIMAGELIST, 0, (LPARAM) hImageList);
999 ok(hIml == NULL, "Expected NULL, got %p\n", hIml);
1001 hIml = (HIMAGELIST) SendMessageA(hChild, HDM_GETIMAGELIST, 0, 0);
1002 ok(hIml != NULL, "Expected non-NULL handle, got %p\n", hIml);
1004 hIml = (HIMAGELIST) SendMessageA(hChild, HDM_CREATEDRAGIMAGE, 0, 0);
1005 ok(hIml != NULL, "Expected non-NULL handle, got %p\n", hIml);
1006 pImageList_Destroy(hIml);
1008 ok_sequence(sequences, HEADER_SEQ_INDEX, imageMessages_seq, "imageMessages sequence testing", FALSE);
1010 DestroyWindow(hChild);
1012 wasValid = pImageList_Destroy(hImageList);
1013 ok(wasValid, "Header must not free image list at destruction!\n");
1016 static void test_hdm_filterMessages(HWND hParent)
1018 HWND hChild;
1019 int retVal, timeout;
1021 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1022 hChild = create_custom_header_control(hParent, TRUE);
1023 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
1024 "adder header control to parent", FALSE);
1026 timeout = SendMessageA(hChild, HDM_SETFILTERCHANGETIMEOUT, 0, 0);
1027 ok(timeout == 1000, "got %d\n", timeout);
1029 timeout = SendMessageA(hChild, HDM_SETFILTERCHANGETIMEOUT, 0, 0);
1030 ok(timeout == 1000, "got %d\n", timeout);
1032 timeout = SendMessageA(hChild, HDM_SETFILTERCHANGETIMEOUT, 0, -100);
1033 ok(timeout == 1000, "got %d\n", timeout);
1035 timeout = SendMessageA(hChild, HDM_SETFILTERCHANGETIMEOUT, 1, 100);
1036 ok(timeout == -100, "got %d\n", timeout);
1037 retVal = SendMessageA(hChild, HDM_SETFILTERCHANGETIMEOUT, 1, timeout);
1038 ok(retVal == 100, "got %d\n", retVal);
1040 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1042 /* msdn incorrectly states that return value
1043 * is the index of the filter control being
1044 * modified. The sendMessage here should
1045 * return previous filter timeout value
1048 retVal = SendMessageA(hChild, HDM_SETFILTERCHANGETIMEOUT, 1, 100);
1049 expect(timeout, retVal);
1051 todo_wine
1053 retVal = SendMessageA(hChild, HDM_CLEARFILTER, 0, 1);
1054 if (retVal == 0)
1055 win_skip("HDM_CLEARFILTER needs 5.80\n");
1056 else
1057 expect(1, retVal);
1059 retVal = SendMessageA(hChild, HDM_EDITFILTER, 1, 0);
1060 if (retVal == 0)
1061 win_skip("HDM_EDITFILTER needs 5.80\n");
1062 else
1063 expect(1, retVal);
1065 if (winetest_interactive)
1066 ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_interactive,
1067 "filterMessages sequence testing", TRUE);
1068 else
1069 ok_sequence(sequences, HEADER_SEQ_INDEX, filterMessages_seq_noninteractive,
1070 "filterMessages sequence testing", FALSE);
1071 DestroyWindow(hChild);
1075 static void test_hdm_unicodeformatMessages(HWND hParent)
1077 HWND hChild;
1078 int retVal;
1080 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1081 hChild = create_custom_header_control(hParent, TRUE);
1082 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
1083 "adder header control to parent", FALSE);
1085 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1086 retVal = SendMessageA(hChild, HDM_SETUNICODEFORMAT, TRUE, 0);
1087 expect(0, retVal);
1088 retVal = SendMessageA(hChild, HDM_GETUNICODEFORMAT, 0, 0);
1089 expect(1, retVal);
1091 ok_sequence(sequences, HEADER_SEQ_INDEX, unicodeformatMessages_seq,
1092 "unicodeformatMessages sequence testing", FALSE);
1093 DestroyWindow(hChild);
1096 static void test_hdm_bitmapmarginMessages(HWND hParent)
1098 HWND hChild;
1099 int retVal;
1101 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1102 hChild = create_custom_header_control(hParent, TRUE);
1103 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
1104 "adder header control to parent", FALSE);
1106 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1107 retVal = SendMessageA(hChild, HDM_GETBITMAPMARGIN, 0, 0);
1108 if (retVal == 0)
1109 win_skip("HDM_GETBITMAPMARGIN needs 5.80\n");
1110 else
1111 expect(6, retVal);
1113 ok_sequence(sequences, HEADER_SEQ_INDEX, bitmapmarginMessages_seq,
1114 "bitmapmarginMessages sequence testing", FALSE);
1115 DestroyWindow(hChild);
1118 static void test_hdm_index_messages(HWND hParent)
1120 HWND hChild;
1121 int retVal, i, iSize;
1122 static const int lpiarray[2] = {1, 0};
1123 static const char *item_texts[] = {
1124 "Name", "Size", "Type", "Date Modified"
1126 RECT rect;
1127 HDITEMA hdItem;
1128 char buffA[32];
1129 int array[2];
1131 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1132 hChild = create_custom_header_control(hParent, FALSE);
1133 if (winetest_interactive)
1134 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq_interactive,
1135 "adder header control to parent", TRUE);
1136 else
1137 ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
1138 "adder header control to parent", FALSE);
1139 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1140 for (i = 0; i < ARRAY_SIZE(item_texts); i++)
1142 hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT;
1143 hdItem.pszText = (char*)item_texts[i];
1144 hdItem.fmt = HDF_LEFT;
1145 hdItem.cxy = 80;
1147 retVal = SendMessageA(hChild, HDM_INSERTITEMA, i, (LPARAM) &hdItem);
1148 ok(retVal == i, "Adding item %d failed with return value %d\n", i, retVal);
1150 ok_sequence(sequences, HEADER_SEQ_INDEX, insertItem_seq, "insertItem sequence testing", FALSE);
1152 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1154 retVal = SendMessageA(hChild, HDM_DELETEITEM, 3, (LPARAM) &hdItem);
1155 ok(retVal == TRUE, "Deleting item 3 should return TRUE, got %d\n", retVal);
1156 retVal = SendMessageA(hChild, HDM_GETITEMCOUNT, 0, 0);
1157 ok(retVal == 3, "Getting item count should return 3, got %d\n", retVal);
1159 retVal = SendMessageA(hChild, HDM_DELETEITEM, 3, (LPARAM) &hdItem);
1160 ok(retVal == FALSE, "Deleting already-deleted item should return FALSE, got %d\n", retVal);
1161 retVal = SendMessageA(hChild, HDM_GETITEMCOUNT, 0, 0);
1162 ok(retVal == 3, "Getting item count should return 3, got %d\n", retVal);
1164 retVal = SendMessageA(hChild, HDM_DELETEITEM, 2, (LPARAM) &hdItem);
1165 ok(retVal == TRUE, "Deleting item 2 should return TRUE, got %d\n", retVal);
1166 retVal = SendMessageA(hChild, HDM_GETITEMCOUNT, 0, 0);
1167 ok(retVal == 2, "Getting item count should return 2, got %d\n", retVal);
1169 ok_sequence(sequences, HEADER_SEQ_INDEX, deleteItem_getItemCount_seq,
1170 "deleteItem_getItemCount sequence testing", FALSE);
1172 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1174 hdItem.mask = HDI_WIDTH;
1175 retVal = SendMessageA(hChild, HDM_GETITEMA, 3, (LPARAM) &hdItem);
1176 ok(retVal == FALSE, "Getting already-deleted item should return FALSE, got %d\n", retVal);
1178 hdItem.mask = HDI_TEXT | HDI_WIDTH;
1179 hdItem.pszText = buffA;
1180 hdItem.cchTextMax = ARRAY_SIZE(buffA);
1181 retVal = SendMessageA(hChild, HDM_GETITEMA, 0, (LPARAM) &hdItem);
1182 ok(retVal == TRUE, "Getting the 1st header item should return TRUE, got %d\n", retVal);
1184 ok_sequence(sequences, HEADER_SEQ_INDEX, getItem_seq, "getItem sequence testing", FALSE);
1186 /* check if the item is the right one */
1187 ok(!strcmp(hdItem.pszText, item_texts[0]), "got wrong item %s, expected %s\n",
1188 hdItem.pszText, item_texts[0]);
1189 expect(80, hdItem.cxy);
1191 iSize = SendMessageA(hChild, HDM_GETITEMCOUNT, 0, 0);
1193 /* item should be updated just after accepting new array */
1194 ShowWindow(hChild, SW_HIDE);
1195 retVal = SendMessageA(hChild, HDM_SETORDERARRAY, iSize, (LPARAM) lpiarray);
1196 expect(TRUE, retVal);
1197 rect.left = 0;
1198 retVal = SendMessageA(hChild, HDM_GETITEMRECT, 0, (LPARAM) &rect);
1199 expect(TRUE, retVal);
1200 ok(rect.left != 0, "Expected updated rectangle\n");
1202 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1204 retVal = SendMessageA(hChild, HDM_SETORDERARRAY, iSize, (LPARAM) lpiarray);
1205 ok(retVal == TRUE, "Setting header items order should return TRUE, got %d\n", retVal);
1207 retVal = SendMessageA(hChild, HDM_GETORDERARRAY, 2, (LPARAM) array);
1208 ok(retVal == TRUE, "Getting header items order should return TRUE, got %d\n", retVal);
1210 ok_sequence(sequences, HEADER_SEQ_INDEX, orderArray_seq, "set_get_orderArray sequence testing", FALSE);
1212 /* check if the array order is set correctly and the size of the array is correct. */
1213 expect(2, iSize);
1214 ok(lpiarray[0] == array[0], "got %d, expected %d\n", array[0], lpiarray[0]);
1215 ok(lpiarray[1] == array[1], "got %d, expected %d\n", array[1], lpiarray[1]);
1217 hdItem.mask = HDI_FORMAT;
1218 hdItem.fmt = HDF_CENTER | HDF_STRING;
1220 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1222 retVal = SendMessageA(hChild, HDM_SETITEMA, 0, (LPARAM) &hdItem);
1223 ok(retVal == TRUE, "Aligning 1st header item to center should return TRUE, got %d\n", retVal);
1224 hdItem.fmt = HDF_RIGHT | HDF_STRING;
1225 retVal = SendMessageA(hChild, HDM_SETITEMA, 1, (LPARAM) &hdItem);
1226 ok(retVal == TRUE, "Aligning 2nd header item to right should return TRUE, got %d\n", retVal);
1228 ok_sequence(sequences, HEADER_SEQ_INDEX, setItem_seq, "setItem sequence testing", FALSE);
1229 DestroyWindow(hChild);
1232 static void test_hdf_fixedwidth(HWND hParent)
1234 HWND hChild;
1235 HDITEMA hdItem;
1236 DWORD ret;
1237 RECT rect;
1238 HDHITTESTINFO ht;
1240 hChild = create_custom_header_control(hParent, FALSE);
1242 hdItem.mask = HDI_WIDTH | HDI_FORMAT;
1243 hdItem.fmt = HDF_FIXEDWIDTH;
1244 hdItem.cxy = 80;
1246 ret = SendMessageA(hChild, HDM_INSERTITEMA, 0, (LPARAM)&hdItem);
1247 expect(0, ret);
1249 /* try to change width */
1250 rect.right = rect.bottom = 0;
1251 SendMessageA(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
1252 ok(rect.right != 0, "Expected not zero width\n");
1253 ok(rect.bottom != 0, "Expected not zero height\n");
1255 SendMessageA(hChild, WM_LBUTTONDOWN, 0, MAKELPARAM(rect.right, rect.bottom / 2));
1256 SendMessageA(hChild, WM_MOUSEMOVE, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2));
1257 SendMessageA(hChild, WM_LBUTTONUP, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2));
1259 SendMessageA(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
1261 if (hdItem.cxy != rect.right)
1263 win_skip("HDF_FIXEDWIDTH format not supported\n");
1264 DestroyWindow(hChild);
1265 return;
1268 /* try to adjust with message */
1269 hdItem.mask = HDI_WIDTH;
1270 hdItem.cxy = 90;
1272 ret = SendMessageA(hChild, HDM_SETITEMA, 0, (LPARAM)&hdItem);
1273 expect(TRUE, ret);
1275 rect.right = 0;
1276 SendMessageA(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
1277 expect(90, rect.right);
1279 /* hittesting doesn't report ondivider flag for HDF_FIXEDWIDTH */
1280 ht.pt.x = rect.right - 1;
1281 ht.pt.y = rect.bottom / 2;
1282 SendMessageA(hChild, HDM_HITTEST, 0, (LPARAM)&ht);
1283 expect(HHT_ONHEADER, ht.flags);
1285 /* try to adjust with message */
1286 hdItem.mask = HDI_FORMAT;
1287 hdItem.fmt = 0;
1289 ret = SendMessageA(hChild, HDM_SETITEMA, 0, (LPARAM)&hdItem);
1290 expect(TRUE, ret);
1292 ht.pt.x = 90;
1293 ht.pt.y = rect.bottom / 2;
1294 SendMessageA(hChild, HDM_HITTEST, 0, (LPARAM)&ht);
1295 expect(HHT_ONDIVIDER, ht.flags);
1297 DestroyWindow(hChild);
1300 static void test_hds_nosizing(HWND hParent)
1302 HWND hChild;
1303 HDITEMA hdItem;
1304 DWORD ret;
1305 RECT rect;
1306 HDHITTESTINFO ht;
1308 hChild = create_custom_header_control(hParent, FALSE);
1310 memset(&hdItem, 0, sizeof(hdItem));
1311 hdItem.mask = HDI_WIDTH;
1312 hdItem.cxy = 80;
1314 ret = SendMessageA(hChild, HDM_INSERTITEMA, 0, (LPARAM)&hdItem);
1315 expect(0, ret);
1317 /* HDS_NOSIZING only blocks hittesting */
1318 ret = GetWindowLongA(hChild, GWL_STYLE);
1319 SetWindowLongA(hChild, GWL_STYLE, ret | HDS_NOSIZING);
1321 /* try to change width with mouse gestures */
1322 rect.right = rect.bottom = 0;
1323 SendMessageA(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
1324 ok(rect.right != 0, "Expected not zero width\n");
1325 ok(rect.bottom != 0, "Expected not zero height\n");
1327 SendMessageA(hChild, WM_LBUTTONDOWN, 0, MAKELPARAM(rect.right, rect.bottom / 2));
1328 SendMessageA(hChild, WM_MOUSEMOVE, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2));
1329 SendMessageA(hChild, WM_LBUTTONUP, 0, MAKELPARAM(rect.right + 20, rect.bottom / 2));
1331 SendMessageA(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
1333 if (hdItem.cxy != rect.right)
1335 win_skip("HDS_NOSIZING style not supported\n");
1336 DestroyWindow(hChild);
1337 return;
1340 /* this style doesn't set HDF_FIXEDWIDTH for items */
1341 hdItem.mask = HDI_FORMAT;
1342 ret = SendMessageA(hChild, HDM_GETITEMA, 0, (LPARAM)&hdItem);
1343 expect(TRUE, ret);
1344 ok(!(hdItem.fmt & HDF_FIXEDWIDTH), "Unexpected HDF_FIXEDWIDTH\n");
1346 /* try to adjust with message */
1347 hdItem.mask = HDI_WIDTH;
1348 hdItem.cxy = 90;
1350 ret = SendMessageA(hChild, HDM_SETITEMA, 0, (LPARAM)&hdItem);
1351 expect(TRUE, ret);
1353 rect.right = 0;
1354 SendMessageA(hChild, HDM_GETITEMRECT, 0, (LPARAM)&rect);
1355 expect(90, rect.right);
1357 /* hittesting doesn't report ondivider flags for HDS_NOSIZING */
1358 ht.pt.x = rect.right - 1;
1359 ht.pt.y = rect.bottom / 2;
1360 SendMessageA(hChild, HDM_HITTEST, 0, (LPARAM)&ht);
1361 expect(HHT_ONHEADER, ht.flags);
1363 /* try to adjust with message */
1364 ret = GetWindowLongA(hChild, GWL_STYLE);
1365 SetWindowLongA(hChild, GWL_STYLE, ret & ~HDS_NOSIZING);
1367 ht.pt.x = 90;
1368 ht.pt.y = rect.bottom / 2;
1369 SendMessageA(hChild, HDM_HITTEST, 0, (LPARAM)&ht);
1370 expect(HHT_ONDIVIDER, ht.flags);
1372 DestroyWindow(hChild);
1375 #define TEST_NMCUSTOMDRAW(draw_stage, item_spec, lparam, _left, _top, _right, _bottom) \
1376 ok(nm->dwDrawStage == draw_stage, "Invalid dwDrawStage %d vs %ld\n", draw_stage, nm->dwDrawStage); \
1377 if (item_spec != -1) \
1378 ok(nm->dwItemSpec == item_spec, "Invalid dwItemSpec %d vs %Id\n", item_spec, nm->dwItemSpec); \
1379 ok(nm->lItemlParam == lparam, "Invalid lItemlParam %d vs %Id\n", lparam, nm->lItemlParam); \
1380 ok((nm->rc.top == _top && nm->rc.bottom == _bottom && nm->rc.left == _left && nm->rc.right == _right) || \
1381 broken(draw_stage != CDDS_ITEMPREPAINT), /* comctl32 < 5.80 */ \
1382 "Invalid rect (%d,%d)-(%d,%ld) vs %s\n", _left, _top, _right, _bottom, \
1383 wine_dbgstr_rect(&nm->rc));
1385 static LRESULT customdraw_1(int n, NMCUSTOMDRAW *nm)
1387 if (nm == NULL) { /* test ended */
1388 ok(n==1, "NM_CUSTOMDRAW messages: %d, expected: 1\n", n);
1389 return 0;
1392 switch (n)
1394 case 0:
1395 /* don't test dwItemSpec - it's 0 no comctl5 but 1308756 on comctl6 */
1396 TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, g_customheight);
1397 return 0;
1400 ok(FALSE, "Too many custom draw messages (n=%d, nm->dwDrawStage=%ld)\n", n, nm->dwDrawStage);
1401 return -1;
1404 static LRESULT customdraw_2(int n, NMCUSTOMDRAW *nm)
1406 if (nm == NULL) { /* test ended */
1407 ok(n==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n);
1408 return 0;
1411 switch (n)
1413 case 0:
1414 TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, g_customheight);
1415 return CDRF_NOTIFYITEMDRAW;
1416 case 1:
1417 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, g_customheight);
1418 return 0;
1419 case 2:
1420 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, g_customheight);
1421 return 0;
1422 case 3:
1423 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, g_customheight);
1424 return 0;
1427 ok(FALSE, "Too many custom draw messages (n=%d, nm->dwDrawStage=%ld)\n", n, nm->dwDrawStage);
1428 return 0;
1431 static LRESULT customdraw_3(int n, NMCUSTOMDRAW *nm)
1433 if (nm == NULL) { /* test ended */
1434 ok(n==5, "NM_CUSTOMDRAW messages: %d, expected: 5\n", n);
1435 return 0;
1438 switch (n)
1440 case 0:
1441 TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, g_customheight);
1442 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTERASE|CDRF_NOTIFYPOSTPAINT|CDRF_SKIPDEFAULT;
1443 case 1:
1444 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, g_customheight);
1445 return 0;
1446 case 2:
1447 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 1, 5, 50, 0, 150, g_customheight);
1448 return 0;
1449 case 3:
1450 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, g_customheight);
1451 return 0;
1452 case 4:
1453 TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, g_customheight);
1454 return 0;
1457 ok(FALSE, "Too many custom draw messages (n=%d, nm->dwDrawStage=%ld)\n", n, nm->dwDrawStage);
1458 return 0;
1462 static LRESULT customdraw_4(int n, NMCUSTOMDRAW *nm)
1464 if (nm == NULL) { /* test ended */
1465 ok(n==4, "NM_CUSTOMDRAW messages: %d, expected: 4\n", n);
1466 return 0;
1469 switch (n)
1471 case 0:
1472 TEST_NMCUSTOMDRAW(CDDS_PREPAINT, -1, 0, 0, 0, 670, g_customheight);
1473 return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYPOSTPAINT;
1474 case 1:
1475 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 0, 0, 0, 0, 50, g_customheight);
1476 return 0;
1477 case 2:
1478 TEST_NMCUSTOMDRAW(CDDS_ITEMPREPAINT, 2, 10, 150, 0, 300, g_customheight);
1479 return 0;
1480 case 3:
1481 TEST_NMCUSTOMDRAW(CDDS_POSTPAINT, -1, 0, 0, 0, 670, g_customheight);
1482 return 0;
1485 ok(FALSE, "Too many custom draw messages (n=%d, nm->dwDrawStage=%ld)\n", n, nm->dwDrawStage);
1486 return 0;
1489 static void run_customdraw_scenario(CUSTOMDRAWPROC proc)
1491 g_CustomDrawProc = proc;
1492 g_CustomDrawCount = 0;
1493 InvalidateRect(hWndHeader, NULL, TRUE);
1494 UpdateWindow(hWndHeader);
1495 proc(g_CustomDrawCount, NULL);
1496 g_CustomDrawProc = NULL;
1499 static void test_customdraw(void)
1501 int i;
1502 HDITEMA item;
1503 RECT rect;
1504 CHAR name[] = "Test";
1505 hWndHeader = create_header_control();
1506 GetClientRect(hWndHeader, &rect);
1507 ok(rect.right - rect.left == 670 && rect.bottom - rect.top == g_customheight,
1508 "Tests will fail as header size is %ldx%ld instead of 670x%ld\n",
1509 rect.right - rect.left, rect.bottom - rect.top, g_customheight);
1511 for (i = 0; i < 3; i++)
1513 ZeroMemory(&item, sizeof(item));
1514 item.mask = HDI_TEXT|HDI_WIDTH;
1515 item.cxy = 50*(i+1);
1516 item.pszText = name;
1517 item.lParam = i*5;
1518 SendMessageA(hWndHeader, HDM_INSERTITEMA, i, (LPARAM)&item);
1521 run_customdraw_scenario(customdraw_1);
1522 run_customdraw_scenario(customdraw_2);
1523 run_customdraw_scenario(customdraw_3);
1525 ZeroMemory(&item, sizeof(item));
1526 item.mask = HDI_FORMAT;
1527 item.fmt = HDF_OWNERDRAW;
1528 SendMessageA(hWndHeader, HDM_SETITEMA, 1, (LPARAM)&item);
1529 g_DrawItem.CtlID = 0;
1530 g_DrawItem.CtlType = ODT_HEADER;
1531 g_DrawItem.hwndItem = hWndHeader;
1532 g_DrawItem.itemID = 1;
1533 g_DrawItem.itemState = 0;
1534 SendMessageA(hWndHeader, HDM_GETITEMRECT, 1, (LPARAM)&g_DrawItem.rcItem);
1535 run_customdraw_scenario(customdraw_4);
1536 ok(g_DrawItemReceived, "WM_DRAWITEM not received\n");
1537 DestroyWindow(hWndHeader);
1538 hWndHeader = NULL;
1539 g_DrawItem.CtlType = 0;
1540 g_DrawItemReceived = FALSE;
1543 static void check_order(const int expected_id[], const int expected_order[],
1544 int count, const char *type)
1546 int i;
1547 HDITEMA hdi;
1549 ok(getItemCount(hWndHeader) == count, "Invalid item count in order tests\n");
1550 for (i = 0; i < count; i++)
1552 hdi.mask = HDI_LPARAM|HDI_ORDER;
1553 SendMessageA(hWndHeader, HDM_GETITEMA, i, (LPARAM)&hdi);
1554 ok(hdi.lParam == expected_id[i],
1555 "Invalid item ids after '%s'- item %d has lParam %d\n", type, i, (int)hdi.lParam);
1556 ok(hdi.iOrder == expected_order[i],
1557 "Invalid item order after '%s'- item %d has iOrder %d\n", type, i, hdi.iOrder);
1561 static void test_header_order (void)
1563 const int rand1[] = {0, 1, 1, 0, 4};
1564 const int rand2[] = {4, 5, 6, 7, 4};
1565 const int rand3[] = {5, 5, 1, 6, 1};
1566 const int rand4[] = {1, 5, 2, 7, 6, 1, 4, 2, 3, 2};
1567 const int rand5[] = {7, 8, 5, 6, 7, 2, 1, 9, 10, 10};
1568 const int rand6[] = {2, 8, 3, 4, 0};
1570 const int ids1[] = {3, 0, 2, 1, 4};
1571 const int ord1[] = {0, 1, 2, 3, 4};
1572 const int ids2[] = {3, 9, 7, 0, 2, 1, 4, 8, 6, 5};
1573 const int ord2[] = {0, 4, 7, 1, 2, 3, 9, 8, 6, 5};
1574 const int ord3[] = {0, 3, 9, 2, 1, 8, 7, 6, 5, 4};
1575 const int ids4[] = {9, 0, 1, 8, 6};
1576 const int ord4[] = {1, 0, 4, 3, 2};
1578 char buffer[20];
1579 HDITEMA hdi;
1580 int i;
1582 hWndHeader = create_header_control();
1584 ZeroMemory(&hdi, sizeof(HDITEMA));
1585 hdi.mask = HDI_TEXT | HDI_LPARAM;
1586 hdi.pszText = buffer;
1587 strcpy(buffer, "test");
1589 for (i = 0; i < 5; i++)
1591 hdi.lParam = i;
1592 SendMessageA(hWndHeader, HDM_INSERTITEMA, rand1[i], (LPARAM)&hdi);
1594 check_order(ids1, ord1, 5, "insert without iOrder");
1596 hdi.mask |= HDI_ORDER;
1597 for (i = 0; i < 5; i++)
1599 hdi.lParam = i + 5;
1600 hdi.iOrder = rand2[i];
1601 SendMessageA(hWndHeader, HDM_INSERTITEMA, rand3[i], (LPARAM)&hdi);
1603 check_order(ids2, ord2, 10, "insert with order");
1605 hdi.mask = HDI_ORDER;
1606 for (i=0; i<10; i++)
1608 hdi.iOrder = rand5[i];
1609 SendMessageA(hWndHeader, HDM_SETITEMA, rand4[i], (LPARAM)&hdi);
1611 check_order(ids2, ord3, 10, "setitems changing order");
1613 for (i=0; i<5; i++)
1614 SendMessageA(hWndHeader, HDM_DELETEITEM, rand6[i], 0);
1615 check_order(ids4, ord4, 5, "deleteitem");
1617 DestroyWindow(hWndHeader);
1620 static LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1622 DRAWITEMSTRUCT *di;
1623 switch(msg) {
1625 case WM_NOTIFY:
1627 NMHEADERA *hdr = (NMHEADERA*)lParam;
1628 EXPECTEDNOTIFY *expected;
1629 int i;
1631 if (hdr->hdr.code == NM_CUSTOMDRAW)
1632 if (g_CustomDrawProc)
1633 return g_CustomDrawProc(g_CustomDrawCount++, (NMCUSTOMDRAW*)hdr);
1635 for (i=0; i<nUnexpectedNotify; i++)
1636 ok(hdr->hdr.code != unexpectedNotify[i], "Received invalid notify %d\n", hdr->hdr.code);
1638 if (nReceivedNotify >= nExpectedNotify || hdr->hdr.hwndFrom != hWndHeader )
1639 break;
1641 expected = &expectedNotify[nReceivedNotify];
1642 if (hdr->hdr.code != expected->iCode)
1643 break;
1645 nReceivedNotify++;
1646 compare_items(hdr->hdr.code, &expected->hdItem, hdr->pitem, expected->fUnicode);
1647 break;
1650 case WM_DRAWITEM:
1651 di = (DRAWITEMSTRUCT *)lParam;
1652 ok(g_DrawItem.CtlType != 0, "Unexpected WM_DRAWITEM\n");
1653 if (g_DrawItem.CtlType == 0) return 0;
1654 g_DrawItemReceived = TRUE;
1655 compare(di->CtlType, g_DrawItem.CtlType, "%d");
1656 compare(di->CtlID, g_DrawItem.CtlID, "%d");
1657 compare(di->hwndItem, g_DrawItem.hwndItem, "%p");
1658 compare(di->itemID, g_DrawItem.itemID, "%d");
1659 compare(di->itemState, g_DrawItem.itemState, "%d");
1660 compare(di->rcItem.left, g_DrawItem.rcItem.left, "%ld");
1661 compare(di->rcItem.top, g_DrawItem.rcItem.top, "%ld");
1662 compare(di->rcItem.right, g_DrawItem.rcItem.right, "%ld");
1663 compare(di->rcItem.bottom, g_DrawItem.rcItem.bottom, "%ld");
1664 break;
1666 case WM_DESTROY:
1667 PostQuitMessage(0);
1668 break;
1670 default:
1671 return DefWindowProcA(hWnd, msg, wParam, lParam);
1674 return 0L;
1677 static void init_functions(void)
1679 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
1681 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
1682 X(ImageList_Create);
1683 X(ImageList_Destroy);
1684 #undef X
1687 static BOOL init(void)
1689 WNDCLASSA wc;
1690 TEXTMETRICA tm;
1691 HFONT hOldFont;
1692 HDC hdc;
1694 wc.style = CS_HREDRAW | CS_VREDRAW;
1695 wc.cbClsExtra = 0;
1696 wc.cbWndExtra = 0;
1697 wc.hInstance = GetModuleHandleA(NULL);
1698 wc.hIcon = NULL;
1699 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
1700 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
1701 wc.lpszMenuName = NULL;
1702 wc.lpszClassName = "HeaderTestClass";
1703 wc.lpfnWndProc = HeaderTestWndProc;
1704 RegisterClassA(&wc);
1706 /* The height of the header control depends on the height of the system font.
1707 The height of the system font is dpi dependent */
1708 hdc = GetDC(0);
1709 hOldFont = SelectObject(hdc, GetStockObject(SYSTEM_FONT));
1710 GetTextMetricsA(hdc, &tm);
1711 /* 2 dot extra space are needed for the border */
1712 g_customheight = tm.tmHeight + 2;
1713 trace("customdraw height: %ld (dpi: %d)\n", g_customheight, GetDeviceCaps(hdc, LOGPIXELSY));
1714 SelectObject(hdc, hOldFont);
1715 ReleaseDC(0, hdc);
1717 hHeaderParentWnd = CreateWindowExA(0, "HeaderTestClass", "Header test", WS_OVERLAPPEDWINDOW,
1718 CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME),
1719 226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
1720 NULL, NULL, GetModuleHandleA(NULL), 0);
1721 ok(hHeaderParentWnd != NULL, "failed to create parent wnd\n");
1723 ShowWindow(hHeaderParentWnd, SW_SHOW);
1724 return hHeaderParentWnd != NULL;
1727 /* maximum 8 items allowed */
1728 static void check_orderarray(HWND hwnd, DWORD start, DWORD set, DWORD expected,
1729 BOOL todo, int line)
1731 int count, i;
1732 INT order[8];
1733 DWORD ret, array = 0;
1735 count = SendMessageA(hwnd, HDM_GETITEMCOUNT, 0, 0);
1737 /* initial order */
1738 for(i = 1; i<=count; i++)
1739 order[i-1] = start>>(4*(count-i)) & 0xf;
1741 ret = SendMessageA(hwnd, HDM_SETORDERARRAY, count, (LPARAM)order);
1742 ok_(__FILE__, line)(ret, "Expected HDM_SETORDERARRAY to succeed, got %ld\n", ret);
1744 /* new order */
1745 for(i = 1; i<=count; i++)
1746 order[i-1] = set>>(4*(count-i)) & 0xf;
1747 ret = SendMessageA(hwnd, HDM_SETORDERARRAY, count, (LPARAM)order);
1748 ok_(__FILE__, line)(ret, "Expected HDM_SETORDERARRAY to succeed, got %ld\n", ret);
1750 /* check actual order */
1751 ret = SendMessageA(hwnd, HDM_GETORDERARRAY, count, (LPARAM)order);
1752 ok_(__FILE__, line)(ret, "Expected HDM_GETORDERARRAY to succeed, got %ld\n", ret);
1753 for(i = 1; i<=count; i++)
1754 array |= order[i-1]<<(4*(count-i));
1756 todo_wine_if(todo)
1757 ok_(__FILE__, line)(array == expected, "Expected %lx, got %lx\n", expected, array);
1760 static void test_hdm_orderarray(void)
1762 HWND hwnd;
1763 INT order[5];
1764 DWORD ret;
1766 hwnd = create_header_control();
1768 /* three items */
1769 addItem(hwnd, 0, NULL);
1770 addItem(hwnd, 1, NULL);
1771 addItem(hwnd, 2, NULL);
1773 ret = SendMessageA(hwnd, HDM_GETORDERARRAY, 3, (LPARAM)order);
1774 if (!ret)
1776 win_skip("HDM_GETORDERARRAY not implemented.\n");
1777 DestroyWindow(hwnd);
1778 return;
1781 expect(0, order[0]);
1782 expect(1, order[1]);
1783 expect(2, order[2]);
1785 if (0)
1787 /* null pointer, crashes native */
1788 ret = SendMessageA(hwnd, HDM_SETORDERARRAY, 3, 0);
1789 expect(FALSE, ret);
1791 /* count out of limits */
1792 ret = SendMessageA(hwnd, HDM_SETORDERARRAY, 5, (LPARAM)order);
1793 expect(FALSE, ret);
1794 /* count out of limits */
1795 ret = SendMessageA(hwnd, HDM_SETORDERARRAY, 2, (LPARAM)order);
1796 expect(FALSE, ret);
1798 /* try with out of range item index */
1799 /* (0,1,2)->(1,0,3) => (1,0,2) */
1800 check_orderarray(hwnd, 0x120, 0x103, 0x102, FALSE, __LINE__);
1801 /* (1,0,2)->(3,0,1) => (0,2,1) */
1802 check_orderarray(hwnd, 0x102, 0x301, 0x021, TRUE, __LINE__);
1803 /* (0,2,1)->(2,3,1) => (2,0,1) */
1804 check_orderarray(hwnd, 0x021, 0x231, 0x201, FALSE, __LINE__);
1806 /* (0,1,2)->(0,2,2) => (0,1,2) */
1807 check_orderarray(hwnd, 0x012, 0x022, 0x012, FALSE, __LINE__);
1809 addItem(hwnd, 3, NULL);
1811 /* (0,1,2,3)->(0,1,2,2) => (0,1,3,2) */
1812 check_orderarray(hwnd, 0x0123, 0x0122, 0x0132, FALSE, __LINE__);
1813 /* (0,1,2,3)->(0,1,3,3) => (0,1,2,3) */
1814 check_orderarray(hwnd, 0x0123, 0x0133, 0x0123, FALSE, __LINE__);
1815 /* (0,1,2,3)->(0,4,2,3) => (0,1,2,3) */
1816 check_orderarray(hwnd, 0x0123, 0x0423, 0x0123, FALSE, __LINE__);
1817 /* (0,1,2,3)->(4,0,1,2) => (0,1,3,2) */
1818 check_orderarray(hwnd, 0x0123, 0x4012, 0x0132, TRUE, __LINE__);
1819 /* (0,1,3,2)->(4,0,1,4) => (0,3,1,2) */
1820 check_orderarray(hwnd, 0x0132, 0x4014, 0x0312, TRUE, __LINE__);
1821 /* (0,1,2,3)->(4,1,0,2) => (1,0,3,2) */
1822 check_orderarray(hwnd, 0x0123, 0x4102, 0x1032, TRUE, __LINE__);
1823 /* (0,1,2,3)->(0,1,4,2) => (0,1,2,3) */
1824 check_orderarray(hwnd, 0x0123, 0x0142, 0x0132, FALSE, __LINE__);
1825 /* (0,1,2,3)->(4,4,4,4) => (0,1,2,3) */
1826 check_orderarray(hwnd, 0x0123, 0x4444, 0x0123, FALSE, __LINE__);
1827 /* (0,1,2,3)->(4,4,1,2) => (0,1,3,2) */
1828 check_orderarray(hwnd, 0x0123, 0x4412, 0x0132, TRUE, __LINE__);
1829 /* (0,1,2,3)->(4,4,4,1) => (0,2,3,1) */
1830 check_orderarray(hwnd, 0x0123, 0x4441, 0x0231, TRUE, __LINE__);
1831 /* (0,1,2,3)->(1,4,4,4) => (1,0,2,3) */
1832 check_orderarray(hwnd, 0x0123, 0x1444, 0x1023, FALSE, __LINE__);
1833 /* (0,1,2,3)->(4,2,4,1) => (0,2,3,1) */
1834 check_orderarray(hwnd, 0x0123, 0x4241, 0x0231, FALSE, __LINE__);
1835 /* (0,1,2,3)->(4,2,0,1) => (2,0,3,1) */
1836 check_orderarray(hwnd, 0x0123, 0x4201, 0x2031, TRUE, __LINE__);
1837 /* (3,2,1,0)->(4,2,0,1) => (3,2,0,1) */
1838 check_orderarray(hwnd, 0x3210, 0x4201, 0x3201, FALSE, __LINE__);
1840 DestroyWindow(hwnd);
1843 START_TEST(header)
1845 HWND parent_hwnd;
1846 ULONG_PTR ctx_cookie;
1847 HANDLE hCtx;
1849 init_functions();
1850 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1852 if (!init())
1853 return;
1855 test_header_control();
1856 test_item_auto_format(hHeaderParentWnd);
1857 test_header_order();
1858 test_hdm_orderarray();
1859 test_customdraw();
1861 DestroyWindow(hHeaderParentWnd);
1863 flush_sequences(sequences, NUM_MSG_SEQUENCES);
1864 parent_hwnd = create_custom_parent_window();
1865 ok_sequence(sequences, PARENT_SEQ_INDEX, create_parent_wnd_seq, "create parent windows", FALSE);
1867 test_hdm_index_messages(parent_hwnd);
1868 test_hdm_getitemrect(parent_hwnd);
1869 test_hdm_hittest(parent_hwnd);
1870 test_hdm_layout(parent_hwnd);
1871 test_hdm_ordertoindex(parent_hwnd);
1872 test_hdm_sethotdivider(parent_hwnd);
1873 test_hdm_imageMessages(parent_hwnd);
1874 test_hdm_filterMessages(parent_hwnd);
1875 test_hdm_unicodeformatMessages(parent_hwnd);
1876 test_hdm_bitmapmarginMessages(parent_hwnd);
1878 if (!load_v6_module(&ctx_cookie, &hCtx))
1880 DestroyWindow(parent_hwnd);
1881 return;
1884 init_functions();
1886 /* comctl32 version 6 tests start here */
1887 test_hdf_fixedwidth(parent_hwnd);
1888 test_hds_nosizing(parent_hwnd);
1889 test_item_auto_format(parent_hwnd);
1890 test_hdm_layout(parent_hwnd);
1892 unload_v6_module(ctx_cookie, hCtx);
1894 DestroyWindow(parent_hwnd);