ReactOS  0.4.14-dev-606-g14ebc0b
listview.c
Go to the documentation of this file.
1 /*
2  * ListView tests
3  *
4  * Copyright 2006 Mike McCormack for CodeWeavers
5  * Copyright 2007 George Gov
6  * Copyright 2009-2014 Nikolay Sivov
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include <stdio.h>
24 #include <windows.h>
25 #include <commctrl.h>
26 
27 #include "wine/test.h"
28 #include "v6util.h"
29 #include "msg.h"
30 
31 static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
32 static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
33 static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
34 static BOOL (WINAPI *p_TrackMouseEvent)(TRACKMOUSEEVENT *);
35 
36 enum seq_index {
44 };
45 
46 #define LISTVIEW_ID 0
47 #define HEADER_ID 1
48 
49 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
50 #define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
51  "expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
52 
53 static const WCHAR testparentclassW[] =
54  {'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
55 
57 /* prevents edit box creation, LVN_BEGINLABELEDIT return value */
58 static BOOL blockEdit;
59 /* return nonzero on NM_HOVER */
61 /* notification data for LVN_ITEMCHANGED */
63 /* notification data for LVN_ITEMCHANGING */
65 /* format reported to control:
66  -1 falls to defproc, anything else returned */
68 /* indicates we're running < 5.80 version */
70 /* item data passed to LVN_GETDISPINFOA */
72 /* alter notification code A->W */
74 /* dispinfo data sent with LVN_LVN_ENDLABELEDIT */
76 /* when this is set focus will be tested on LVN_DELETEITEM */
78 /* Whether to send WM_KILLFOCUS to the edit control during LVN_ENDLABELEDIT */
80 
81 static HWND subclass_editbox(HWND hwndListview);
82 
83 static void init_functions(void)
84 {
85  HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
86 
87 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
92 #undef X
93 }
94 
96 
97 static const struct message create_ownerdrawfixed_parent_seq[] = {
98  { WM_NOTIFYFORMAT, sent },
99  { WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
100  { WM_MEASUREITEM, sent },
101  { WM_PARENTNOTIFY, sent },
102  { 0 }
103 };
104 
105 static const struct message redraw_listview_seq[] = {
106  { WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
107  { WM_PAINT, sent|id, 0, 0, HEADER_ID },
108  { WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
110  { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
111  { WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
113  { 0 }
114 };
115 
116 static const struct message listview_icon_spacing_seq[] = {
117  { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
118  { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
119  { LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
120  { 0 }
121 };
122 
123 static const struct message listview_color_seq[] = {
124  { LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
125  { LVM_GETBKCOLOR, sent },
126  { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
127  { LVM_GETTEXTCOLOR, sent },
128  { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
130 
131  { LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
132  { LVM_GETBKCOLOR, sent },
133  { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
134  { LVM_GETTEXTCOLOR, sent },
135  { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
137 
139  { LVM_GETBKCOLOR, sent },
141  { LVM_GETTEXTCOLOR, sent },
144 
145  { LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
146  { LVM_GETBKCOLOR, sent },
147  { LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
148  { LVM_GETTEXTCOLOR, sent },
149  { LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
151  { 0 }
152 };
153 
154 static const struct message listview_item_count_seq[] = {
155  { LVM_GETITEMCOUNT, sent },
156  { LVM_INSERTITEMA, sent },
157  { LVM_INSERTITEMA, sent },
158  { LVM_INSERTITEMA, sent },
159  { LVM_GETITEMCOUNT, sent },
160  { LVM_DELETEITEM, sent|wparam, 2 },
161  { WM_NCPAINT, sent|optional },
163  { LVM_GETITEMCOUNT, sent },
165  { LVM_GETITEMCOUNT, sent },
166  { LVM_INSERTITEMA, sent },
167  { LVM_INSERTITEMA, sent },
168  { LVM_GETITEMCOUNT, sent },
169  { LVM_INSERTITEMA, sent },
170  { LVM_GETITEMCOUNT, sent },
171  { 0 }
172 };
173 
174 static const struct message listview_itempos_seq[] = {
175  { LVM_INSERTITEMA, sent },
176  { LVM_INSERTITEMA, sent },
177  { LVM_INSERTITEMA, sent },
179  { WM_NCPAINT, sent|optional },
186  { 0 }
187 };
188 
189 static const struct message listview_ownerdata_switchto_seq[] = {
190  { WM_STYLECHANGING, sent },
191  { WM_STYLECHANGED, sent },
192  { 0 }
193 };
194 
195 static const struct message listview_getorderarray_seq[] = {
197  { HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
199  { HDM_GETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
200  { 0 }
201 };
202 
203 static const struct message listview_setorderarray_seq[] = {
205  { HDM_SETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
207  { HDM_SETORDERARRAY, sent|id|wparam, 0, 0, HEADER_ID },
208  { 0 }
209 };
210 
211 static const struct message empty_seq[] = {
212  { 0 }
213 };
214 
216  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
217  { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
218  { 0 }
219 };
220 
221 static const struct message forward_erasebkgnd_parent_seq[] = {
222  { WM_ERASEBKGND, sent },
223  { 0 }
224 };
225 
227  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
228  { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
229  { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
230  { 0 }
231 };
232 
234  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
235  { 0 }
236 };
237 
238 static const struct message ownerdata_defocus_all_parent_seq[] = {
239  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
240  { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
241  { WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
242  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
243  { 0 }
244 };
245 
247  { WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
248  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
249  { 0 }
250 };
251 
252 static const struct message change_all_parent_seq[] = {
253  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
254  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
255 
256  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
257  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
258 
259  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
260  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
261 
262  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
263  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
264 
265  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
266  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
267  { 0 }
268 };
269 
270 static const struct message changing_all_parent_seq[] = {
271  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
272  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
273  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
274  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
275  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
276  { 0 }
277 };
278 
280  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
281  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
282  { 0 }
283 };
284 
285 static const struct message single_getdispinfo_parent_seq[] = {
286  { WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
287  { 0 }
288 };
289 
290 static const struct message getitemposition_seq1[] = {
292  { 0 }
293 };
294 
295 static const struct message getitemposition_seq2[] = {
297  { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
298  { 0 }
299 };
300 
301 static const struct message getsubitemrect_seq[] = {
302  { LVM_GETSUBITEMRECT, sent|id|wparam, -1, 0, LISTVIEW_ID },
303  { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
304  { LVM_GETSUBITEMRECT, sent|id|wparam, 0, 0, LISTVIEW_ID },
305  { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
306  { LVM_GETSUBITEMRECT, sent|id|wparam, -10, 0, LISTVIEW_ID },
307  { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
308  { LVM_GETSUBITEMRECT, sent|id|wparam, 20, 0, LISTVIEW_ID },
309  { HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
310  { 0 }
311 };
312 
313 static const struct message editbox_create_pos[] = {
314  /* sequence sent after LVN_BEGINLABELEDIT */
315  /* next two are 4.7x specific */
318 
320  { WM_NCCALCSIZE, sent },
322  { WM_MOVE, sent|defwinproc },
323  { WM_SIZE, sent|defwinproc },
324  /* the rest is todo, skipped in 4.7x */
327  { 0 }
328 };
329 
330 static const struct message scroll_parent_seq[] = {
331  { WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
332  { WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
333  { 0 }
334 };
335 
336 static const struct message setredraw_seq[] = {
338  { 0 }
339 };
340 
341 static const struct message lvs_ex_transparentbkgnd_seq[] = {
343  { 0 }
344 };
345 
346 static const struct message edit_end_nochange[] = {
347  { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
348  { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW }, /* todo */
349  { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
350  { 0 }
351 };
352 
353 static const struct message hover_parent[] = {
354  { WM_GETDLGCODE, sent }, /* todo_wine */
355  { WM_NOTIFY, sent|id, 0, 0, NM_HOVER },
356  { 0 }
357 };
358 
359 static const struct message listview_destroy[] = {
360  { 0x0090, sent|optional }, /* Vista */
361  { WM_PARENTNOTIFY, sent },
362  { WM_SHOWWINDOW, sent },
365  { WM_DESTROY, sent },
366  { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
367  { WM_NCDESTROY, sent },
368  { 0 }
369 };
370 
371 static const struct message listview_ownerdata_destroy[] = {
372  { 0x0090, sent|optional }, /* Vista */
373  { WM_PARENTNOTIFY, sent },
374  { WM_SHOWWINDOW, sent },
377  { WM_DESTROY, sent },
378  { WM_NCDESTROY, sent },
379  { 0 }
380 };
381 
382 static const struct message listview_ownerdata_deleteall[] = {
384  { WM_NOTIFY, sent|id, 0, 0, LVN_DELETEALLITEMS },
385  { 0 }
386 };
387 
388 static const struct message listview_header_changed_seq[] = {
389  { LVM_SETCOLUMNA, sent },
390  { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
391  { WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
392  { 0 }
393 };
394 
395 static const struct message parent_header_click_seq[] = {
396  { WM_NOTIFY, sent|id, 0, 0, LVN_COLUMNCLICK },
397  { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCLICKA },
398  { 0 }
399 };
400 
401 static const struct message parent_header_divider_dclick_seq[] = {
402  { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGINGA },
403  { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
404  { WM_NOTIFY, sent|id, 0, 0, NM_CUSTOMDRAW },
405  { WM_NOTIFY, sent|id, 0, 0, HDN_ITEMCHANGEDA },
407  { 0 }
408 };
409 
410 static const struct message listview_set_imagelist[] = {
411  { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
412  { 0 }
413 };
414 
415 static const struct message listview_header_set_imagelist[] = {
416  { LVM_SETIMAGELIST, sent|id, 0, 0, LISTVIEW_ID },
417  { HDM_SETIMAGELIST, sent|id, 0, 0, HEADER_ID },
418  { 0 }
419 };
420 
421 static const struct message parent_insert_focused_seq[] = {
422  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
423  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
424  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
425  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
426  { WM_NOTIFY, sent|id, 0, 0, LVN_INSERTITEM },
427  { 0 }
428 };
429 
430 static const struct message parent_report_cd_seq[] = {
439  { 0 }
440 };
441 
442 static const struct message parent_list_cd_seq[] = {
447  { 0 }
448 };
449 
450 static const struct message listview_end_label_edit[] = {
451  { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
452  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING},
453  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
454  { WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
455  { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
456  { 0 }
457 };
458 
460  { WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
461  { WM_COMMAND, sent|id|optional, 0, 0, EN_KILLFOCUS }, /* todo: not sent by wine yet */
462  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
463  { WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
464  { WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
465  { WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
466  { 0 }
467 };
468 
470 {
471  static LONG defwndproc_counter = 0;
472  LRESULT ret;
473  struct message msg;
474 
475  msg.message = message;
476  msg.flags = sent|wparam|lparam;
477  if (defwndproc_counter) msg.flags |= defwinproc;
478  msg.wParam = wParam;
479  msg.lParam = lParam;
480  if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
481  if (message == WM_COMMAND) msg.id = HIWORD(wParam);
482 
483  /* log system messages, except for painting */
484  if (message < WM_USER &&
485  message != WM_PAINT &&
486  message != WM_ERASEBKGND &&
487  message != WM_NCPAINT &&
488  message != WM_NCHITTEST &&
489  message != WM_GETTEXT &&
490  message != WM_GETICON &&
492  {
495  }
497 
498  switch (message)
499  {
500  case WM_NOTIFY:
501  {
502  switch (((NMHDR*)lParam)->code)
503  {
504  case LVN_BEGINLABELEDITA:
505  {
506  HWND edit = NULL;
507 
508  /* subclass edit box */
509  if (!blockEdit)
510  edit = subclass_editbox(((NMHDR*)lParam)->hwndFrom);
511 
512  if (edit)
513  {
514  INT len = SendMessageA(edit, EM_GETLIMITTEXT, 0, 0);
515  ok(len == 259 || broken(len == 260) /* includes NULL in NT4 */,
516  "text limit %d, expected 259\n", len);
517  }
518 
519  return blockEdit;
520  }
521  case LVN_ENDLABELEDITA:
522  {
523  HWND edit;
524 
525  /* always accept new item text */
527  g_editbox_disp_info = *di;
528 
529  /* edit control still available from this notification */
530  edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
531  ok(IsWindow(edit), "expected valid edit control handle\n");
532  ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
533 
535  SendMessageA(edit, WM_KILLFOCUS, 0, 0);
536 
537  return TRUE;
538  }
539  case LVN_ITEMCHANGING:
540  {
541  NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
542  g_nmlistview_changing = *nmlv;
543  }
544  break;
545  case LVN_ITEMCHANGED:
546  {
547  NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
548  g_nmlistview = *nmlv;
549  }
550  break;
551  case LVN_GETDISPINFOA:
552  {
553  NMLVDISPINFOA *dispinfo = (NMLVDISPINFOA*)lParam;
554  g_itema = dispinfo->item;
555 
556  if (g_disp_A_to_W && (dispinfo->item.mask & LVIF_TEXT))
557  {
558  static const WCHAR testW[] = {'T','E','S','T',0};
559  dispinfo->hdr.code = LVN_GETDISPINFOW;
560  memcpy(dispinfo->item.pszText, testW, sizeof(testW));
561  }
562 
563  /* test control buffer size for text, 10 used to mask cases when control
564  is using caller buffer to process LVM_GETITEM for example */
565  if (dispinfo->item.mask & LVIF_TEXT && dispinfo->item.cchTextMax > 10)
566  ok(dispinfo->item.cchTextMax == 260 ||
567  broken(dispinfo->item.cchTextMax == 264) /* NT4 reports aligned size */,
568  "buffer size %d\n", dispinfo->item.cchTextMax);
569  }
570  break;
571  case LVN_DELETEITEM:
573  {
574  NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
575  UINT state;
576 
578  ok(state == 0, "got state %x\n", state);
579  }
580  break;
581  case NM_HOVER:
582  if (g_block_hover) return 1;
583  break;
584  }
585  break;
586  }
587  case WM_NOTIFYFORMAT:
588  {
589  /* force to return format */
590  if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
591  break;
592  }
593  }
594 
595  defwndproc_counter++;
596  if (IsWindowUnicode(hwnd))
598  else
600  defwndproc_counter--;
601 
602  return ret;
603 }
604 
606 {
607  WNDCLASSA clsA;
608  WNDCLASSW clsW;
609 
610  if (Unicode)
611  {
612  clsW.style = 0;
614  clsW.cbClsExtra = 0;
615  clsW.cbWndExtra = 0;
617  clsW.hIcon = 0;
618  clsW.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
620  clsW.lpszMenuName = NULL;
622  }
623  else
624  {
625  clsA.style = 0;
627  clsA.cbClsExtra = 0;
628  clsA.cbWndExtra = 0;
630  clsA.hIcon = 0;
631  clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
633  clsA.lpszMenuName = NULL;
634  clsA.lpszClassName = "Listview test parent class";
635  }
636 
637  return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
638 }
639 
641 {
642  static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W',0};
643  HWND hwnd;
644 
645  if (!register_parent_wnd_class(Unicode))
646  return NULL;
647 
648  blockEdit = FALSE;
649  notifyFormat = -1;
650 
651  if (Unicode)
655  0, 0, 100, 100,
657  else
658  hwnd = CreateWindowExA(0, "Listview test parent class",
659  "Listview test parent window",
662  0, 0, 100, 100,
665  return hwnd;
666 }
667 
669 {
671  static LONG defwndproc_counter = 0;
672  LRESULT ret;
673  struct message msg;
674 
675  msg.message = message;
676  msg.flags = sent|wparam|lparam;
677  if (defwndproc_counter) msg.flags |= defwinproc;
678  msg.wParam = wParam;
679  msg.lParam = lParam;
680  msg.id = LISTVIEW_ID;
683 
684  defwndproc_counter++;
685  ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
686  defwndproc_counter--;
687  return ret;
688 }
689 
691 {
692  WNDPROC oldproc;
693  HWND hwnd;
694  RECT rect;
695 
697  hwnd = CreateWindowExA(0, WC_LISTVIEWA, "foo",
699  0, 0, rect.right, rect.bottom,
701  ok(hwnd != NULL, "gle=%d\n", GetLastError());
702 
703  if (!hwnd) return NULL;
704 
708 
709  return hwnd;
710 }
711 
712 /* unicode listview window with specified parent */
714 {
715  WNDPROC oldproc;
716  HWND hwnd;
717  RECT rect;
718  static const WCHAR nameW[] = {'f','o','o',0};
719 
723  0, 0, rect.right, rect.bottom,
725  ok(hwnd != NULL, "gle=%d\n", GetLastError());
726 
727  if (!hwnd) return NULL;
728 
732 
733  return hwnd;
734 }
735 
736 static BOOL is_win_xp(void)
737 {
738  HWND hwnd, header;
739  BOOL ret;
740 
742  SendMessageA(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_HEADERINALLVIEWS, LVS_EX_HEADERINALLVIEWS);
744  ret = !IsWindow(header);
745 
747 
748  return ret;
749 }
750 
752 {
754  static LONG defwndproc_counter = 0;
755  struct message msg = { 0 };
756  LRESULT ret;
757 
758  msg.message = message;
759  msg.flags = sent|wparam|lparam;
760  if (defwndproc_counter) msg.flags |= defwinproc;
761  msg.wParam = wParam;
762  msg.lParam = lParam;
763  msg.id = HEADER_ID;
765 
766  defwndproc_counter++;
767  ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
768  defwndproc_counter--;
769  return ret;
770 }
771 
772 static HWND subclass_header(HWND hwndListview)
773 {
774  WNDPROC oldproc;
775  HWND hwnd;
776 
777  hwnd = (HWND)SendMessageA(hwndListview, LVM_GETHEADER, 0, 0);
781 
782  return hwnd;
783 }
784 
786 {
788  static LONG defwndproc_counter = 0;
789  struct message msg = { 0 };
790  LRESULT ret;
791 
792  msg.message = message;
793  msg.flags = sent|wparam|lparam;
794  if (defwndproc_counter) msg.flags |= defwinproc;
795  msg.wParam = wParam;
796  msg.lParam = lParam;
797 
798  /* all we need is sizing */
799  if (message == WM_WINDOWPOSCHANGING ||
800  message == WM_NCCALCSIZE ||
802  message == WM_MOVE ||
803  message == WM_SIZE)
804  {
806  }
807 
808  defwndproc_counter++;
809  ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
810  defwndproc_counter--;
811  return ret;
812 }
813 
814 static HWND subclass_editbox(HWND hwndListview)
815 {
816  WNDPROC oldproc;
817  HWND hwnd;
818 
819  hwnd = (HWND)SendMessageA(hwndListview, LVM_GETEDITCONTROL, 0, 0);
823 
824  return hwnd;
825 }
826 
827 /* Performs a single LVM_HITTEST test */
828 static void test_lvm_hittest_(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
829  BOOL todo_item, BOOL todo_flags, int line)
830 {
831  LVHITTESTINFO lpht;
832  INT ret;
833 
834  lpht.pt.x = x;
835  lpht.pt.y = y;
836  lpht.iSubItem = 10;
837 
838  ret = SendMessageA(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
839 
840  todo_wine_if(todo_item)
841  {
842  ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
843  ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
844  ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
845  }
846 
847  if (todo_flags)
848  {
849  todo_wine
850  ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
851  }
852  else if (broken_flags)
853  ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
854  "Expected flags %x, got %x\n", flags, lpht.flags);
855  else
856  ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
857 }
858 
859 #define test_lvm_hittest(a,b,c,d,e,f,g,h) test_lvm_hittest_(a,b,c,d,e,f,g,h,__LINE__)
860 
861 /* Performs a single LVM_SUBITEMHITTEST test */
863  BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
864 {
865  LVHITTESTINFO lpht;
866  INT ret;
867 
868  lpht.pt.x = x;
869  lpht.pt.y = y;
870 
872 
873  todo_wine_if(todo_item)
874  {
875  ok_(__FILE__, line)(ret == item, "Expected %d retval, got %d\n", item, ret);
876  ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
877  }
878 
879  todo_wine_if(todo_subitem)
880  ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
881 
882  todo_wine_if(todo_flags)
883  ok_(__FILE__, line)(lpht.flags == flags, "Expected flags 0x%x, got 0x%x\n", flags, lpht.flags);
884 }
885 
886 #define test_lvm_subitemhittest(a,b,c,d,e,f,g,h,i) test_lvm_subitemhittest_(a,b,c,d,e,f,g,h,i,__LINE__)
887 
888 static void test_images(void)
889 {
890  HWND hwnd;
891  INT r;
892  LVITEMA item;
894  HBITMAP hbmp;
895  RECT r1, r2;
896  static CHAR hello[] = "hello";
897 
898  himl = pImageList_Create(40, 40, 0, 4, 4);
899  ok(himl != NULL, "failed to create imagelist\n");
900 
901  hbmp = CreateBitmap(40, 40, 1, 1, NULL);
902  ok(hbmp != NULL, "failed to create bitmap\n");
903 
904  r = pImageList_Add(himl, hbmp, 0);
905  ok(r == 0, "should be zero\n");
906 
908  10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
909  ok(hwnd != NULL, "failed to create listview window\n");
910 
913 
914  ok(r == 0, "should return zero\n");
915 
917  ok(r == 0, "should return zero\n");
918 
920  ok(r != 0, "got 0\n");
921 
922  /* returns dimensions */
923 
925  ok(r == 0, "should be zero items\n");
926 
927  item.mask = LVIF_IMAGE | LVIF_TEXT;
928  item.iItem = 0;
929  item.iSubItem = 1;
930  item.iImage = 0;
931  item.pszText = 0;
933  ok(r == -1, "should fail\n");
934 
935  item.iSubItem = 0;
936  item.pszText = hello;
938  ok(r == 0, "should not fail\n");
939 
940  SetRect(&r1, LVIR_ICON, 0, 0, 0);
942  expect(1, r);
943 
945  ok(r == TRUE, "should not fail\n");
946 
947  item.iSubItem = 0;
948  item.pszText = hello;
950  ok(r == 0, "should not fail\n");
951 
952  SetRect(&r2, LVIR_ICON, 0, 0, 0);
954  expect(1, r);
955 
956  ok(EqualRect(&r1, &r2), "rectangle should be the same\n");
957 
959 }
960 
961 static void test_checkboxes(void)
962 {
963  HWND hwnd;
964  LVITEMA item;
965  DWORD r;
966  static CHAR text[] = "Text",
967  text2[] = "Text2",
968  text3[] = "Text3";
969 
971  10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
972  ok(hwnd != NULL, "failed to create listview window\n");
973 
974  /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
975  item.mask = LVIF_TEXT | LVIF_STATE;
976  item.stateMask = 0xffff;
977  item.state = 0xfccc;
978  item.iItem = 0;
979  item.iSubItem = 0;
980  item.pszText = text;
982  expect(0, r);
983 
984  item.iItem = 0;
985  item.mask = LVIF_STATE;
986  item.stateMask = 0xffff;
988  expect(1, r);
989  ok(item.state == 0xfccc, "state %x\n", item.state);
990 
991  /* Don't set LVIF_STATE */
992  item.mask = LVIF_TEXT;
993  item.stateMask = 0xffff;
994  item.state = 0xfccc;
995  item.iItem = 1;
996  item.iSubItem = 0;
997  item.pszText = text;
999  expect(1, r);
1000 
1001  item.iItem = 1;
1002  item.mask = LVIF_STATE;
1003  item.stateMask = 0xffff;
1005  expect(1, r);
1006  ok(item.state == 0, "state %x\n", item.state);
1007 
1009  expect(0, r);
1010 
1011  /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
1012  item.iItem = 0;
1013  item.mask = LVIF_STATE;
1014  item.stateMask = 0xffff;
1016  expect(1, r);
1017  if (item.state != 0x1ccc)
1018  {
1019  win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
1021  return;
1022  }
1023 
1024  /* Now add an item without specifying a state and check that its state goes to 0x1000 */
1025  item.iItem = 2;
1026  item.mask = LVIF_TEXT;
1027  item.state = 0;
1028  item.pszText = text2;
1030  expect(2, r);
1031 
1032  item.iItem = 2;
1033  item.mask = LVIF_STATE;
1034  item.stateMask = 0xffff;
1036  expect(1, r);
1037  ok(item.state == 0x1000, "state %x\n", item.state);
1038 
1039  /* Add a further item this time specifying a state and still its state goes to 0x1000 */
1040  item.iItem = 3;
1041  item.mask = LVIF_TEXT | LVIF_STATE;
1042  item.stateMask = 0xffff;
1043  item.state = 0x2aaa;
1044  item.pszText = text3;
1046  expect(3, r);
1047 
1048  item.iItem = 3;
1049  item.mask = LVIF_STATE;
1050  item.stateMask = 0xffff;
1052  expect(1, r);
1053  ok(item.state == 0x1aaa, "state %x\n", item.state);
1054 
1055  /* Set an item's state to checked */
1056  item.iItem = 3;
1057  item.mask = LVIF_STATE;
1058  item.stateMask = 0xf000;
1059  item.state = 0x2000;
1061  expect(1, r);
1062 
1063  item.iItem = 3;
1064  item.mask = LVIF_STATE;
1065  item.stateMask = 0xffff;
1067  expect(1, r);
1068  ok(item.state == 0x2aaa, "state %x\n", item.state);
1069 
1070  /* Check that only the bits we asked for are returned,
1071  * and that all the others are set to zero
1072  */
1073  item.iItem = 3;
1074  item.mask = LVIF_STATE;
1075  item.stateMask = 0xf000;
1076  item.state = 0xffff;
1078  expect(1, r);
1079  ok(item.state == 0x2000, "state %x\n", item.state);
1080 
1081  /* Set the style again and check that doesn't change an item's state */
1083  ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1084 
1085  item.iItem = 3;
1086  item.mask = LVIF_STATE;
1087  item.stateMask = 0xffff;
1089  expect(1, r);
1090  ok(item.state == 0x2aaa, "state %x\n", item.state);
1091 
1092  /* Unsetting the checkbox extended style doesn't change an item's state */
1094  ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
1095 
1096  item.iItem = 3;
1097  item.mask = LVIF_STATE;
1098  item.stateMask = 0xffff;
1100  expect(1, r);
1101  ok(item.state == 0x2aaa, "state %x\n", item.state);
1102 
1103  /* Now setting the style again will change an item's state */
1105  expect(0, r);
1106 
1107  item.iItem = 3;
1108  item.mask = LVIF_STATE;
1109  item.stateMask = 0xffff;
1111  expect(1, r);
1112  ok(item.state == 0x1aaa, "state %x\n", item.state);
1113 
1114  /* Toggle checkbox tests (bug 9934) */
1115  memset (&item, 0xcc, sizeof(item));
1116  item.mask = LVIF_STATE;
1117  item.iItem = 3;
1118  item.iSubItem = 0;
1119  item.state = LVIS_FOCUSED;
1120  item.stateMask = LVIS_FOCUSED;
1122  expect(1, r);
1123 
1124  item.iItem = 3;
1125  item.mask = LVIF_STATE;
1126  item.stateMask = 0xffff;
1128  expect(1, r);
1129  ok(item.state == 0x1aab, "state %x\n", item.state);
1130 
1132  expect(0, r);
1134  expect(0, r);
1135 
1136  item.iItem = 3;
1137  item.mask = LVIF_STATE;
1138  item.stateMask = 0xffff;
1140  expect(1, r);
1141  ok(item.state == 0x2aab, "state %x\n", item.state);
1142 
1144  expect(0, r);
1146  expect(0, r);
1147 
1148  item.iItem = 3;
1149  item.mask = LVIF_STATE;
1150  item.stateMask = 0xffff;
1152  expect(1, r);
1153  ok(item.state == 0x1aab, "state %x\n", item.state);
1154 
1156 }
1157 
1158 static void insert_column(HWND hwnd, int idx)
1159 {
1160  LVCOLUMNA column;
1161  INT rc;
1162 
1163  memset(&column, 0xcc, sizeof(column));
1164  column.mask = LVCF_SUBITEM;
1165  column.iSubItem = idx;
1166 
1168  expect(idx, rc);
1169 }
1170 
1171 static void insert_item(HWND hwnd, int idx)
1172 {
1173  static CHAR text[] = "foo";
1174 
1175  LVITEMA item;
1176  INT rc;
1177 
1178  memset(&item, 0xcc, sizeof (item));
1179  item.mask = LVIF_TEXT;
1180  item.iItem = idx;
1181  item.iSubItem = 0;
1182  item.pszText = text;
1183 
1185  expect(idx, rc);
1186 }
1187 
1188 static void test_items(void)
1189 {
1190  const LPARAM lparamTest = 0x42;
1191  static CHAR text[] = "Text";
1192  char buffA[5];
1193  HWND hwnd;
1194  LVITEMA item;
1195  DWORD r;
1196 
1198  10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1199  ok(hwnd != NULL, "failed to create listview window\n");
1200 
1201  /*
1202  * Test setting/getting item params
1203  */
1204 
1205  /* Set up two columns */
1206  insert_column(hwnd, 0);
1207  insert_column(hwnd, 1);
1208 
1209  /* LVIS_SELECTED with zero stateMask */
1210  /* set */
1211  memset (&item, 0, sizeof (item));
1212  item.mask = LVIF_STATE;
1213  item.state = LVIS_SELECTED;
1214  item.stateMask = 0;
1215  item.iItem = 0;
1216  item.iSubItem = 0;
1218  expect(0, r);
1219  /* get */
1220  memset (&item, 0xcc, sizeof (item));
1221  item.mask = LVIF_STATE;
1222  item.stateMask = LVIS_SELECTED;
1223  item.state = 0;
1224  item.iItem = 0;
1225  item.iSubItem = 0;
1227  expect(1, r);
1228  ok(item.state & LVIS_SELECTED, "Expected LVIS_SELECTED\n");
1229  r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1230  ok(r, "got %d\n", r);
1231 
1232  /* LVIS_SELECTED with zero stateMask */
1233  /* set */
1234  memset (&item, 0, sizeof (item));
1235  item.mask = LVIF_STATE;
1236  item.state = LVIS_FOCUSED;
1237  item.stateMask = 0;
1238  item.iItem = 0;
1239  item.iSubItem = 0;
1241  expect(0, r);
1242  /* get */
1243  memset (&item, 0xcc, sizeof (item));
1244  item.mask = LVIF_STATE;
1245  item.stateMask = LVIS_FOCUSED;
1246  item.state = 0;
1247  item.iItem = 0;
1248  item.iSubItem = 0;
1250  expect(1, r);
1251  ok(item.state & LVIS_FOCUSED, "Expected LVIS_FOCUSED\n");
1252  r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1253  ok(r, "got %d\n", r);
1254 
1255  /* LVIS_CUT with LVIS_FOCUSED stateMask */
1256  /* set */
1257  memset (&item, 0, sizeof (item));
1258  item.mask = LVIF_STATE;
1259  item.state = LVIS_CUT;
1260  item.stateMask = LVIS_FOCUSED;
1261  item.iItem = 0;
1262  item.iSubItem = 0;
1264  expect(0, r);
1265  /* get */
1266  memset (&item, 0xcc, sizeof (item));
1267  item.mask = LVIF_STATE;
1268  item.stateMask = LVIS_CUT;
1269  item.state = 0;
1270  item.iItem = 0;
1271  item.iSubItem = 0;
1273  expect(1, r);
1274  ok(item.state & LVIS_CUT, "Expected LVIS_CUT\n");
1275  r = SendMessageA(hwnd, LVM_DELETEITEM, 0, 0);
1276  ok(r, "got %d\n", r);
1277 
1278  /* Insert an item with just a param */
1279  memset (&item, 0xcc, sizeof (item));
1280  item.mask = LVIF_PARAM;
1281  item.iItem = 0;
1282  item.iSubItem = 0;
1283  item.lParam = lparamTest;
1285  expect(0, r);
1286 
1287  /* Test getting of the param */
1288  memset (&item, 0xcc, sizeof (item));
1289  item.mask = LVIF_PARAM;
1290  item.iItem = 0;
1291  item.iSubItem = 0;
1293  expect(1, r);
1294  ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1295 
1296  /* Set up a subitem */
1297  memset (&item, 0xcc, sizeof (item));
1298  item.mask = LVIF_TEXT;
1299  item.iItem = 0;
1300  item.iSubItem = 1;
1301  item.pszText = text;
1303  expect(1, r);
1304 
1305  item.mask = LVIF_TEXT;
1306  item.iItem = 0;
1307  item.iSubItem = 1;
1308  item.pszText = buffA;
1309  item.cchTextMax = sizeof(buffA);
1311  expect(1, r);
1312  ok(!memcmp(item.pszText, text, sizeof(text)), "got text %s, expected %s\n", item.pszText, text);
1313 
1314  /* set up with extra flag */
1315  /* 1. reset subitem text */
1316  item.mask = LVIF_TEXT;
1317  item.iItem = 0;
1318  item.iSubItem = 1;
1319  item.pszText = NULL;
1321  expect(1, r);
1322 
1323  item.mask = LVIF_TEXT;
1324  item.iItem = 0;
1325  item.iSubItem = 1;
1326  item.pszText = buffA;
1327  buffA[0] = 'a';
1328  item.cchTextMax = sizeof(buffA);
1330  expect(1, r);
1331  ok(item.pszText[0] == 0, "got %p\n", item.pszText);
1332 
1333  /* 2. set new text with extra flag specified */
1334  item.mask = LVIF_TEXT | LVIF_DI_SETITEM;
1335  item.iItem = 0;
1336  item.iSubItem = 1;
1337  item.pszText = text;
1339  ok(r == 1 || broken(r == 0) /* NT4 */, "ret %d\n", r);
1340 
1341  if (r == 1)
1342  {
1343  item.mask = LVIF_TEXT;
1344  item.iItem = 0;
1345  item.iSubItem = 1;
1346  item.pszText = buffA;
1347  buffA[0] = 'a';
1348  item.cchTextMax = sizeof(buffA);
1350  expect(1, r);
1351  ok(!memcmp(item.pszText, text, sizeof(text)), "got %s, expected %s\n", item.pszText, text);
1352  }
1353 
1354  /* Query param from subitem: returns main item param */
1355  memset (&item, 0xcc, sizeof (item));
1356  item.mask = LVIF_PARAM;
1357  item.iItem = 0;
1358  item.iSubItem = 1;
1360  expect(1, r);
1361  ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1362 
1363  /* Set up param on first subitem: no effect */
1364  memset (&item, 0xcc, sizeof (item));
1365  item.mask = LVIF_PARAM;
1366  item.iItem = 0;
1367  item.iSubItem = 1;
1368  item.lParam = lparamTest+1;
1370  expect(0, r);
1371 
1372  /* Query param from subitem again: should still return main item param */
1373  memset (&item, 0xcc, sizeof (item));
1374  item.mask = LVIF_PARAM;
1375  item.iItem = 0;
1376  item.iSubItem = 1;
1378  expect(1, r);
1379  ok(item.lParam == lparamTest, "got lParam %lx, expected %lx\n", item.lParam, lparamTest);
1380 
1381  /**** Some tests of state highlighting ****/
1382  memset (&item, 0xcc, sizeof (item));
1383  item.mask = LVIF_STATE;
1384  item.iItem = 0;
1385  item.iSubItem = 0;
1386  item.state = LVIS_SELECTED;
1387  item.stateMask = LVIS_SELECTED | LVIS_DROPHILITED;
1389  expect(1, r);
1390  item.iSubItem = 1;
1391  item.state = LVIS_DROPHILITED;
1393  expect(1, r);
1394 
1395  memset (&item, 0xcc, sizeof (item));
1396  item.mask = LVIF_STATE;
1397  item.iItem = 0;
1398  item.iSubItem = 0;
1399  item.stateMask = -1;
1401  expect(1, r);
1402  ok(item.state == LVIS_SELECTED, "got state %x, expected %x\n", item.state, LVIS_SELECTED);
1403  item.iSubItem = 1;
1405  expect(1, r);
1406  todo_wine ok(item.state == LVIS_DROPHILITED, "got state %x, expected %x\n", item.state, LVIS_DROPHILITED);
1407 
1408  /* some notnull but meaningless masks */
1409  memset (&item, 0, sizeof(item));
1410  item.mask = LVIF_NORECOMPUTE;
1411  item.iItem = 0;
1412  item.iSubItem = 0;
1414  expect(1, r);
1415  memset (&item, 0, sizeof(item));
1416  item.mask = LVIF_DI_SETITEM;
1417  item.iItem = 0;
1418  item.iSubItem = 0;
1420  expect(1, r);
1421 
1422  /* set text to callback value already having it */
1424  expect(TRUE, r);
1425  memset (&item, 0, sizeof (item));
1426  item.mask = LVIF_TEXT;
1427  item.pszText = LPSTR_TEXTCALLBACKA;
1428  item.iItem = 0;
1430  expect(0, r);
1431  memset (&item, 0, sizeof (item));
1432 
1434 
1435  item.pszText = LPSTR_TEXTCALLBACKA;
1437  expect(TRUE, r);
1438 
1440  "check callback text comparison rule", FALSE);
1441 
1443 }
1444 
1445 static void test_columns(void)
1446 {
1447  HWND hwnd, header;
1448  LVCOLUMNA column;
1449  LVITEMA item;
1450  INT order[2];
1451  CHAR buff[5];
1452  DWORD rc;
1453 
1455  10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1456  ok(hwnd != NULL, "failed to create listview window\n");
1457 
1459  ok(header == NULL, "got %p\n", header);
1460 
1462  ok(rc == 0, "got %d\n", rc);
1463 
1465  ok(header == NULL, "got %p\n", header);
1466 
1468 
1470  10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
1471  ok(hwnd != NULL, "failed to create listview window\n");
1472 
1473  rc = SendMessageA(hwnd, LVM_DELETECOLUMN, -1, 0);
1474  ok(!rc, "got %d\n", rc);
1475 
1476  rc = SendMessageA(hwnd, LVM_DELETECOLUMN, 0, 0);
1477  ok(!rc, "got %d\n", rc);
1478 
1479  /* Add a column with no mask */
1480  memset(&column, 0xcc, sizeof(column));
1481  column.mask = 0;
1483  ok(rc == 0, "Inserting column with no mask failed with %d\n", rc);
1484 
1485  /* Check its width */
1486  rc = SendMessageA(hwnd, LVM_GETCOLUMNWIDTH, 0, 0);
1487  ok(rc == 10, "Inserting column with no mask failed to set width to 10 with %d\n", rc);
1488 
1490 
1491  /* LVM_GETCOLUMNORDERARRAY */
1494 
1495  memset(&column, 0, sizeof(column));
1496  column.mask = LVCF_WIDTH;
1497  column.cx = 100;
1499  expect(0, rc);
1500 
1501  column.cx = 200;
1503  expect(1, rc);
1504 
1506 
1508  expect(1, rc);
1509  ok(order[0] == 0, "Expected order 0, got %d\n", order[0]);
1510  ok(order[1] == 1, "Expected order 1, got %d\n", order[1]);
1511 
1513  expect(0, rc);
1514 
1516 
1517  /* LVM_SETCOLUMNORDERARRAY */
1519 
1520  order[0] = 0;
1521  order[1] = 1;
1523  expect(1, rc);
1524 
1526  expect(0, rc);
1527 
1529 
1530  /* after column added subitem is considered as present */
1531  insert_item(hwnd, 0);
1532 
1534 
1535  item.pszText = buff;
1536  item.cchTextMax = sizeof(buff);
1537  item.iItem = 0;
1538  item.iSubItem = 1;
1539  item.mask = LVIF_TEXT;
1540  memset(&g_itema, 0, sizeof(g_itema));
1541  rc = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
1542  expect(1, rc);
1543  ok(g_itema.iSubItem == 1, "got %d\n", g_itema.iSubItem);
1544 
1546  "get subitem text after column added", FALSE);
1547 
1549 }
1550 
1551 /* test setting imagelist between WM_NCCREATE and WM_CREATE */
1554 
1556 {
1557  LRESULT ret;
1558 
1559  if (uMsg == WM_CREATE)
1560  {
1562  lpcs->style |= LVS_REPORT;
1563  }
1566  return ret;
1567 }
1568 
1569 /* Header creation is delayed in classic implementation. */
1570 #define TEST_NO_HEADER(a) test_header_presence_(a, FALSE, __LINE__)
1571 #define TEST_HEADER_EXPECTED(a) test_header_presence_(a, TRUE, __LINE__)
1572 #define TEST_NO_HEADER2(a, b) test_header_presence_(a, b, __LINE__)
1573 static void test_header_presence_(HWND hwnd, BOOL present, int line)
1574 {
1576 
1577  if (present)
1578  {
1579  ok_(__FILE__, line)(IsWindow(header), "Header should have been created.\n");
1580  if (header) /* FIXME: remove when todo's are fixed */
1581  ok_(__FILE__, line)(header == GetDlgItem(hwnd, 0), "Dialog item expected.\n");
1582  }
1583  else
1584  {
1585  ok_(__FILE__, line)(!IsWindow(header), "Header shouldn't be created.\n");
1586  ok_(__FILE__, line)(NULL == GetDlgItem(hwnd, 0), "NULL dialog item expected.\n");
1587  }
1588 }
1589 
1590 static void test_create(BOOL is_version_6)
1591 {
1592  static const WCHAR testtextW[] = {'t','e','s','t',' ','t','e','x','t',0};
1593  char buff[16];
1594  HWND hList;
1595  HWND hHeader;
1596  LONG_PTR ret;
1597  LONG r;
1598  LVCOLUMNA col;
1599  RECT rect;
1600  WNDCLASSEXA cls;
1601  DWORD style;
1602  ATOM class;
1603 
1604  if (is_win_xp() && is_version_6)
1605  {
1606  win_skip("Skipping some tests on XP.\n");
1607  return;
1608  }
1609 
1610  cls.cbSize = sizeof(WNDCLASSEXA);
1612  ok(r, "Failed to get class info.\n");
1615  cls.lpszClassName = "MyListView32";
1616  class = RegisterClassExA(&cls);
1617  ok(class, "Failed to register class.\n");
1618 
1619  test_create_imagelist = pImageList_Create(16, 16, 0, 5, 10);
1620  hList = CreateWindowA("MyListView32", "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1621  ok((HIMAGELIST)SendMessageA(hList, LVM_GETIMAGELIST, 0, 0) == test_create_imagelist, "Image list not obtained\n");
1622  hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1623  ok(IsWindow(hHeader) && IsWindowVisible(hHeader), "Listview not in report mode\n");
1624  ok(hHeader == GetDlgItem(hList, 0), "Expected header as dialog item\n");
1626 
1627  /* header isn't created on LVS_ICON and LVS_LIST styles */
1628  hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1630 
1631  /* insert column */
1632  memset(&col, 0, sizeof(LVCOLUMNA));
1633  col.mask = LVCF_WIDTH;
1634  col.cx = 100;
1636  expect(0, r);
1638  hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1639  style = GetWindowLongA(hHeader, GWL_STYLE);
1640  ok(!(style & HDS_HIDDEN), "Not expected HDS_HIDDEN\n");
1642 
1643  hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1644  GetModuleHandleA(NULL), 0);
1646  /* insert column */
1647  memset(&col, 0, sizeof(LVCOLUMNA));
1648  col.mask = LVCF_WIDTH;
1649  col.cx = 100;
1651  expect(0, r);
1654 
1655  /* try to switch LVS_ICON -> LVS_REPORT and back LVS_ICON -> LVS_REPORT */
1656  hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE, 0, 0, 100, 100, NULL, NULL,
1657  GetModuleHandleA(NULL), 0);
1659  ok(ret & WS_VISIBLE, "Style wrong, should have WS_VISIBLE\n");
1662  ok((ret & WS_VISIBLE) && (ret & LVS_REPORT), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1665 
1666  /* try to switch LVS_LIST -> LVS_REPORT and back LVS_LIST -> LVS_REPORT */
1667  hList = CreateWindowA(WC_LISTVIEWA, "Test", WS_VISIBLE|LVS_LIST, 0, 0, 100, 100, NULL, NULL,
1668  GetModuleHandleA(NULL), 0);
1671  ok(((ret & WS_VISIBLE) && (ret & LVS_LIST)), "Style wrong, should have WS_VISIBLE|LVS_LIST\n");
1674  ok(((ret & WS_VISIBLE) && (ret & LVS_REPORT)), "Style wrong, should have WS_VISIBLE|LVS_REPORT\n");
1677 
1678  /* LVS_REPORT without WS_VISIBLE */
1679  hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1680  GetModuleHandleA(NULL), 0);
1681  hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1682 todo_wine_if(is_version_6)
1683  TEST_NO_HEADER2(hList, is_version_6);
1684 
1685  /* insert column */
1686  memset(&col, 0, sizeof(LVCOLUMNA));
1687  col.mask = LVCF_WIDTH;
1688  col.cx = 100;
1690  expect(0, r);
1693 
1694  /* LVS_REPORT without WS_VISIBLE, try to show it */
1695  hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1696  GetModuleHandleA(NULL), 0);
1697 todo_wine_if(is_version_6)
1698  TEST_NO_HEADER2(hList, is_version_6);
1699 
1703 
1704  /* LVS_REPORT with LVS_NOCOLUMNHEADER */
1706  0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1708  hHeader = (HWND)SendMessageA(hList, LVM_GETHEADER, 0, 0);
1709  /* HDS_DRAGDROP set by default */
1710  ok(GetWindowLongPtrA(hHeader, GWL_STYLE) & HDS_DRAGDROP, "Expected header to have HDS_DRAGDROP\n");
1712 
1713  /* setting LVS_EX_HEADERDRAGDROP creates header */
1714  hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1715  GetModuleHandleA(NULL), 0);
1716 todo_wine_if(is_version_6)
1717  TEST_NO_HEADER2(hList, is_version_6);
1718 
1722 
1723  /* setting LVS_EX_GRIDLINES creates header */
1724  hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1725  GetModuleHandleA(NULL), 0);
1726 todo_wine_if(is_version_6)
1727  TEST_NO_HEADER2(hList, is_version_6);
1728 
1732 
1733  /* setting LVS_EX_FULLROWSELECT creates header */
1734  hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1735  GetModuleHandleA(NULL), 0);
1736 todo_wine_if(is_version_6)
1737  TEST_NO_HEADER2(hList, is_version_6);
1741 
1742  /* not report style accepts LVS_EX_HEADERDRAGDROP too */
1746  ok(r & LVS_EX_HEADERDRAGDROP, "Expected LVS_EX_HEADERDRAGDROP to be set\n");
1748 
1749  /* requesting header info with LVM_GETSUBITEMRECT doesn't create it */
1750  hList = CreateWindowA(WC_LISTVIEWA, "Test", LVS_REPORT, 0, 0, 100, 100, NULL, NULL,
1751  GetModuleHandleA(NULL), 0);
1752 todo_wine_if(is_version_6)
1753  TEST_NO_HEADER2(hList, is_version_6);
1754 
1755  SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
1757  ok(r == 1, "Unexpected ret value %d.\n", r);
1758  /* right value contains garbage, probably because header columns are not set up */
1759  ok(rect.bottom >= 0, "Unexpected rectangle.\n");
1760 
1761 todo_wine_if(is_version_6)
1762  TEST_NO_HEADER2(hList, is_version_6);
1764 
1765  /* WM_MEASUREITEM should be sent when created with LVS_OWNERDRAWFIXED */
1769  "created with LVS_OWNERDRAWFIXED|LVS_REPORT - parent seq", FALSE);
1771 
1772  /* Test that window text is preserved. */
1774  0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1775  ok(hList != NULL, "Failed to create ListView window.\n");
1776  *buff = 0;
1777  GetWindowTextA(hList, buff, sizeof(buff));
1778  ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1780 
1782  0, 0, 100, 100, hwndparent, NULL, GetModuleHandleA(NULL), NULL);
1783  ok(hList != NULL, "Failed to create ListView window.\n");
1784  *buff = 0;
1785  GetWindowTextA(hList, buff, sizeof(buff));
1786  ok(!strcmp(buff, "test text"), "Unexpected window text %s.\n", buff);
1788 
1789  r = UnregisterClassA("MyListView32", NULL);
1790  ok(r, "Failed to unregister test class.\n");
1791 }
1792 
1793 static void test_redraw(void)
1794 {
1795  HWND hwnd;
1796  HDC hdc;
1797  BOOL res;
1798  DWORD r;
1799  RECT rect;
1800 
1803 
1805 
1807  UpdateWindow(hwnd);
1809 
1811 
1812  /* forward WM_ERASEBKGND to parent on CLR_NONE background color */
1813  /* 1. Without backbuffer */
1815  expect(TRUE, res);
1816 
1818 
1821  ok(r == 1, "Expected not zero result\n");
1823  "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1824 
1826  expect(TRUE, res);
1827 
1830  expect(1, r);
1832  "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1833 
1834  /* 2. With backbuffer */
1838  expect(TRUE, res);
1839 
1842  expect(1, r);
1844  "forward WM_ERASEBKGND on CLR_NONE", FALSE);
1845 
1847  expect(TRUE, res);
1848 
1851  todo_wine expect(1, r);
1853  "don't forward WM_ERASEBKGND on non-CLR_NONE", FALSE);
1854 
1856 
1857  /* test setting the window style to what it already was */
1858  UpdateWindow(hwnd);
1861  ok(rect.left == 0 && rect.top == 0 && rect.right == 0 && rect.bottom == 0,
1862  "Expected empty update rect, got %s\n", wine_dbgstr_rect(&rect));
1863 
1865 }
1866 
1868 {
1869  COLORREF clr, c0ffee = RGB(0xc0, 0xff, 0xee);
1870 
1871  if(message == WM_NOTIFY) {
1872  NMHDR *nmhdr = (NMHDR*)lParam;
1873  if(nmhdr->code == NM_CUSTOMDRAW) {
1874  NMLVCUSTOMDRAW *nmlvcd = (NMLVCUSTOMDRAW*)nmhdr;
1875  struct message msg;
1876 
1877  msg.message = message;
1878  msg.flags = sent|wparam|lparam|custdraw;
1879  msg.wParam = wParam;
1880  msg.lParam = lParam;
1881  msg.id = nmhdr->code;
1882  msg.stage = nmlvcd->nmcd.dwDrawStage;
1884 
1885  switch(nmlvcd->nmcd.dwDrawStage) {
1886  case CDDS_PREPAINT:
1887  SetBkColor(nmlvcd->nmcd.hdc, c0ffee);
1889  case CDDS_ITEMPREPAINT:
1890  nmlvcd->clrTextBk = CLR_DEFAULT;
1891  nmlvcd->clrText = RGB(0, 255, 0);
1894  clr = GetBkColor(nmlvcd->nmcd.hdc);
1895  ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1896  ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1898  {
1899  todo_wine_if(nmlvcd->iSubItem)
1900  ok(clr == c0ffee, "clr=%.8x\n", clr);
1901  }
1902  return CDRF_NOTIFYPOSTPAINT;
1904  clr = GetBkColor(nmlvcd->nmcd.hdc);
1906  todo_wine ok(clr == c0ffee, "clr=%.8x\n", clr);
1907  ok(nmlvcd->clrTextBk == CLR_DEFAULT, "got 0x%x\n", nmlvcd->clrTextBk);
1908  ok(nmlvcd->clrText == RGB(0, 255, 0), "got 0x%x\n", nmlvcd->clrText);
1909  return CDRF_DODEFAULT;
1910  }
1911  return CDRF_DODEFAULT;
1912  }
1913  }
1914 
1916 }
1917 
1918 static void test_customdraw(void)
1919 {
1920  HWND hwnd;
1921  WNDPROC oldwndproc;
1922  LVITEMA item;
1923 
1925 
1926  insert_column(hwnd, 0);
1927  insert_column(hwnd, 1);
1928  insert_item(hwnd, 0);
1929 
1931  (LONG_PTR)cd_wndproc);
1932 
1934  UpdateWindow(hwnd);
1935 
1936  /* message tests */
1939  UpdateWindow(hwnd);
1940  ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT", FALSE);
1941 
1942  /* check colors when item is selected */
1944  item.mask = LVIF_STATE;
1945  item.stateMask = LVIS_SELECTED;
1946  item.state = LVIS_SELECTED;
1948 
1951  UpdateWindow(hwnd);
1952  ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_report_cd_seq, "parent customdraw, LVS_REPORT, selection", FALSE);
1953 
1955 
1957 
1958  insert_column(hwnd, 0);
1959  insert_column(hwnd, 1);
1960  insert_item(hwnd, 0);
1961 
1964  UpdateWindow(hwnd);
1965  ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_list_cd_seq, "parent customdraw, LVS_LIST", FALSE);
1966 
1969 }
1970 
1971 static void test_icon_spacing(void)
1972 {
1973  /* LVM_SETICONSPACING */
1974  /* note: LVM_SETICONSPACING returns the previous icon spacing if successful */
1975 
1976  HWND hwnd;
1977  WORD w, h;
1978  INT r;
1979 
1981  ok(hwnd != NULL, "failed to create a listview window\n");
1982 
1983  r = SendMessageA(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwndparent, NF_REQUERY);
1984  expect(NFR_ANSI, r);
1985 
1986  /* reset the icon spacing to defaults */
1988 
1989  /* now we can request what the defaults are */
1991  w = LOWORD(r);
1992  h = HIWORD(r);
1993 
1995 
1997  ok(r == MAKELONG(w, h) ||
1998  broken(r == MAKELONG(w, w)), /* win98 */
1999  "Expected %d, got %d\n", MAKELONG(w, h), r);
2000 
2002  expect(MAKELONG(20,30), r);
2003 
2005  expect(MAKELONG(25,35), r);
2006 
2008 
2011 }
2012 
2013 static void test_color(void)
2014 {
2015  RECT rect;
2016  HWND hwnd;
2017  DWORD r;
2018  int i;
2019 
2020  COLORREF color;
2021  COLORREF colors[4] = {RGB(0,0,0), RGB(100,50,200), CLR_NONE, RGB(255,255,255)};
2022 
2024  ok(hwnd != NULL, "failed to create a listview window\n");
2025 
2027 
2028  for (i = 0; i < 4; i++)
2029  {
2030  color = colors[i];
2031 
2033  expect(TRUE, r);
2034  r = SendMessageA(hwnd, LVM_GETBKCOLOR, 0, 0);
2035  expect(color, r);
2036 
2038  expect (TRUE, r);
2039  r = SendMessageA(hwnd, LVM_GETTEXTCOLOR, 0, 0);
2040  expect(color, r);
2041 
2043  expect(TRUE, r);
2045  expect(color, r);
2046  }
2047 
2050 
2051  /* invalidation test done separately to avoid a message chain mess */
2052  r = ValidateRect(hwnd, NULL);
2053  expect(TRUE, r);
2054  r = SendMessageA(hwnd, LVM_SETBKCOLOR, 0, colors[0]);
2055  expect(TRUE, r);
2056 
2057  rect.right = rect.bottom = 1;
2058  r = GetUpdateRect(hwnd, &rect, TRUE);
2059  todo_wine expect(FALSE, r);
2060  ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2061 
2062  r = ValidateRect(hwnd, NULL);
2063  expect(TRUE, r);
2064  r = SendMessageA(hwnd, LVM_SETTEXTCOLOR, 0, colors[0]);
2065  expect(TRUE, r);
2066 
2067  rect.right = rect.bottom = 1;
2068  r = GetUpdateRect(hwnd, &rect, TRUE);
2069  todo_wine expect(FALSE, r);
2070  ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2071 
2072  r = ValidateRect(hwnd, NULL);
2073  expect(TRUE, r);
2074  r = SendMessageA(hwnd, LVM_SETTEXTBKCOLOR, 0, colors[0]);
2075  expect(TRUE, r);
2076 
2077  rect.right = rect.bottom = 1;
2078  r = GetUpdateRect(hwnd, &rect, TRUE);
2079  todo_wine expect(FALSE, r);
2080  ok(rect.right == 0 && rect.bottom == 0, "got update rectangle\n");
2081 
2083 }
2084 
2085 static void test_item_count(void)
2086 {
2087  /* LVM_INSERTITEM, LVM_DELETEITEM, LVM_DELETEALLITEMS, LVM_GETITEMCOUNT */
2088 
2089  HWND hwnd;
2090  DWORD r;
2091  HDC hdc;
2092  HFONT hOldFont;
2093  TEXTMETRICA tm;
2094  RECT rect;
2095  INT height;
2096 
2097  LVITEMA item0;
2098  LVITEMA item1;
2099  LVITEMA item2;
2100  static CHAR item0text[] = "item0";
2101  static CHAR item1text[] = "item1";
2102  static CHAR item2text[] = "item2";
2103 
2105  ok(hwnd != NULL, "failed to create a listview window\n");
2106 
2107  /* resize in dpiaware manner to fit all 3 items added */
2108  hdc = GetDC(0);
2110  GetTextMetricsA(hdc, &tm);
2111  /* 2 extra pixels for bounds and header border */
2112  height = tm.tmHeight + 2;
2113  SelectObject(hdc, hOldFont);
2114  ReleaseDC(0, hdc);
2115 
2116  GetWindowRect(hwnd, &rect);
2117  /* 3 items + 1 header + 1 to be sure */
2118  MoveWindow(hwnd, 0, 0, rect.right - rect.left, 5 * height, FALSE);
2119 
2121 
2122  r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2123  expect(0, r);
2124 
2125  /* [item0] */
2126  item0.mask = LVIF_TEXT;
2127  item0.iItem = 0;
2128  item0.iSubItem = 0;
2129  item0.pszText = item0text;
2130  r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2131  expect(0, r);
2132 
2133  /* [item0, item1] */
2134  item1.mask = LVIF_TEXT;
2135  item1.iItem = 1;
2136  item1.iSubItem = 0;
2137  item1.pszText = item1text;
2139  expect(1, r);
2140 
2141  /* [item0, item1, item2] */
2142  item2.mask = LVIF_TEXT;
2143  item2.iItem = 2;
2144  item2.iSubItem = 0;
2145  item2.pszText = item2text;
2147  expect(2, r);
2148 
2149  r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2150  expect(3, r);
2151 
2152  /* [item0, item1] */
2153  r = SendMessageA(hwnd, LVM_DELETEITEM, 2, 0);
2154  expect(TRUE, r);
2155 
2156  r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2157  expect(2, r);
2158 
2159  /* [] */
2161  expect(TRUE, r);
2162 
2163  r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2164  expect(0, r);
2165 
2166  /* [item0] */
2168  expect(0, r);
2169 
2170  /* [item0, item1] */
2172  expect(1, r);
2173 
2174  r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2175  expect(2, r);
2176 
2177  /* [item0, item1, item2] */
2179  expect(2, r);
2180 
2181  r = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2182  expect(3, r);
2183 
2185 
2188 }
2189 
2190 static void test_item_position(void)
2191 {
2192  /* LVM_SETITEMPOSITION/LVM_GETITEMPOSITION */
2193 
2194  HWND hwnd;
2195  DWORD r;
2196  POINT position;
2197 
2198  LVITEMA item0;
2199  LVITEMA item1;
2200  LVITEMA item2;
2201  static CHAR item0text[] = "item0";
2202  static CHAR item1text[] = "item1";
2203  static CHAR item2text[] = "item2";
2204 
2206  ok(hwnd != NULL, "failed to create a listview window\n");
2207 
2209 
2210  /* [item0] */
2211  item0.mask = LVIF_TEXT;
2212  item0.iItem = 0;
2213  item0.iSubItem = 0;
2214  item0.pszText = item0text;
2215  r = SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item0);
2216  expect(0, r);
2217 
2218  /* [item0, item1] */
2219  item1.mask = LVIF_TEXT;
2220  item1.iItem = 1;
2221  item1.iSubItem = 0;
2222  item1.pszText = item1text;
2224  expect(1, r);
2225 
2226  /* [item0, item1, item2] */
2227  item2.mask = LVIF_TEXT;
2228  item2.iItem = 2;
2229  item2.iSubItem = 0;
2230  item2.pszText = item2text;
2232  expect(2, r);
2233 
2235  expect(TRUE, r);
2236  r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 1, (LPARAM) &position);
2237  expect(TRUE, r);
2238  expect2(10, 5, position.x, position.y);
2239 
2241  expect(TRUE, r);
2242  r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 2, (LPARAM) &position);
2243  expect(TRUE, r);
2244  expect2(0, 0, position.x, position.y);
2245 
2247  expect(TRUE, r);
2248  r = SendMessageA(hwnd, LVM_GETITEMPOSITION, 0, (LPARAM) &position);
2249  expect(TRUE, r);
2250  expect2(20, 20, position.x, position.y);
2251 
2252  ok_sequence(sequences, LISTVIEW_SEQ_INDEX, listview_itempos_seq, "test item position seq", TRUE);
2253 
2256 }
2257 
2258 static void test_getorigin(void)
2259 {
2260  /* LVM_GETORIGIN */
2261 
2262  HWND hwnd;
2263  DWORD r;
2264  POINT position;
2265 
2266  position.x = position.y = 0;
2267 
2269  ok(hwnd != NULL, "failed to create a listview window\n");
2271 
2272  r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2273  expect(TRUE, r);
2276 
2278  ok(hwnd != NULL, "failed to create a listview window\n");
2280 
2281  r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2282  expect(TRUE, r);
2285 
2287  ok(hwnd != NULL, "failed to create a listview window\n");
2289 
2290  r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2291  expect(FALSE, r);
2294 
2296  ok(hwnd != NULL, "failed to create a listview window\n");
2298 
2299  r = SendMessageA(hwnd, LVM_GETORIGIN, 0, (LPARAM)&position);
2300  expect(FALSE, r);
2303 }
2304 
2305 static void test_multiselect(void)
2306 {
2307  typedef struct t_select_task
2308  {
2309  const char *descr;
2310  int initPos;
2311  int loopVK;
2312  int count;
2313  int result;
2314  } select_task;
2315 
2316  HWND hwnd;
2317  INT r;
2318  int i, j;
2319  static const int items=5;
2320  DWORD item_count;
2321  BYTE kstate[256];
2322  select_task task;
2323  LONG_PTR style;
2324  LVITEMA item;
2325 
2326  static struct t_select_task task_list[] = {
2327  { "using VK_DOWN", 0, VK_DOWN, -1, -1 },
2328  { "using VK_UP", -1, VK_UP, -1, -1 },
2329  { "using VK_END", 0, VK_END, 1, -1 },
2330  { "using VK_HOME", -1, VK_HOME, 1, -1 }
2331  };
2332 
2334 
2335  for (i = 0; i < items; i++)
2336  insert_item(hwnd, 0);
2337 
2338  item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2339  expect(items, item_count);
2340 
2342  ok(r == -1, "got %d\n", r);
2343 
2345  ok(r == -1, "got %d\n", r);
2346 
2348  ok(r == 0, "got %d\n", r);
2349 
2350  /* out of range index */
2352  ok(r == 0, "got %d\n", r);
2353 
2355  ok(r == 0, "got %d\n", r);
2356 
2358  ok(r == 0, "got %d\n", r);
2359 
2361  ok(r == 0, "got %d\n", r);
2362 
2363  for (i = 0; i < ARRAY_SIZE(task_list); i++) {
2364  DWORD selected_count;
2365  LVITEMA item;
2366 
2367  task = task_list[i];
2368 
2369  /* deselect all items */
2370  item.state = 0;
2371  item.stateMask = LVIS_SELECTED;
2373  ok(r, "got %d\n", r);
2375 
2376  /* set initial position */
2377  r = SendMessageA(hwnd, LVM_SETSELECTIONMARK, 0, (task.initPos == -1 ? item_count -1 : task.initPos));
2378  ok(r, "got %d\n", r);
2379 
2380  item.state = LVIS_SELECTED;
2381  item.stateMask = LVIS_SELECTED;
2382  r = SendMessageA(hwnd, LVM_SETITEMSTATE, task.initPos == -1 ? item_count-1 : task.initPos, (LPARAM)&item);
2383  ok(r, "got %d\n", r);
2384 
2385  selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2386  ok(selected_count == 1, "expected 1, got %d\n", selected_count);
2387 
2388  /* Set SHIFT key pressed */
2389  GetKeyboardState(kstate);
2390  kstate[VK_SHIFT]=0x80;
2391  SetKeyboardState(kstate);
2392 
2393  for (j=1;j<=(task.count == -1 ? item_count : task.count);j++) {
2394  r = SendMessageA(hwnd, WM_KEYDOWN, task.loopVK, 0);
2395  expect(0,r);
2396  r = SendMessageA(hwnd, WM_KEYUP, task.loopVK, 0);
2397  expect(0,r);
2398  }
2399 
2400  selected_count = SendMessageA(hwnd, LVM_GETSELECTEDCOUNT, 0, 0);
2401 
2402  ok((task.result == -1 ? item_count : task.result) == selected_count,
2403  "Failed multiple selection %s. There should be %d selected items (is %d)\n",
2404  task.descr, item_count, selected_count);
2405 
2406  /* Set SHIFT key released */
2407  GetKeyboardState(kstate);
2408  kstate[VK_SHIFT]=0x00;
2409  SetKeyboardState(kstate);
2410  }
2412 
2413  /* make multiple selection, then switch to LVS_SINGLESEL */
2415  for (i=0;i<items;i++) {
2416  insert_item(hwnd, 0);
2417  }
2418  item_count = SendMessageA(hwnd, LVM_GETITEMCOUNT, 0, 0);
2419  expect(items,item_count);
2420 
2421  /* try with NULL pointer */
2422  r = SendMessageA(hwnd, LVM_SETITEMSTATE, 0, 0);
2423  expect(FALSE, r);
2424 
2425  /* select all, check notifications */
2426  item.state = 0;
2427  item.stateMask = LVIS_SELECTED;
2429  ok(r, "got %d\n", r);
2430 
2432 
2433  item.stateMask = LVIS_SELECTED;
2434  item.state = LVIS_SELECTED;
2436  expect(TRUE, r);
2437 
2439  "select all notification", FALSE);
2440 
2441  /* select all again (all selected already) */
2443 
2445 
2446  item.stateMask = LVIS_SELECTED;
2447  item.state = LVIS_SELECTED;
2449  expect(TRUE, r);
2450 
2454 
2456  "select all notification 2", FALSE);
2457 
2458  /* deselect all items */
2460 
2461  item.state = 0;
2462  item.stateMask = LVIS_SELECTED;
2464  ok(r, "got %d\n", r);
2465 
2467  "deselect all notification", FALSE);
2468 
2469  /* deselect all items again */
2471  item.state = 0;
2472  item.stateMask = LVIS_SELECTED;
2474  ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "deselect all notification 2", FALSE);
2475 
2476  /* any non-zero state value does the same */
2478 
2480 
2481  item.stateMask = LVIS_SELECTED;
2482  item.state = LVIS_CUT;
2484  expect(TRUE, r);
2485 
2489 
2491  "set state all notification 3", FALSE);
2492 
2494  ok(r, "got %d\n", r);
2495  for (i = 0; i < 3; i++) {
2496  item.state = LVIS_SELECTED;
2497  item.stateMask = LVIS_SELECTED;
2499  ok(r, "got %d\n", r);
2500  }
2501 
2503  expect(3, r);
2505  expect(-1, r);
2506 
2508  ok(!(style & LVS_SINGLESEL), "LVS_SINGLESEL isn't expected\n");
2510  /* check that style is accepted */
2512  ok(style & LVS_SINGLESEL, "LVS_SINGLESEL expected\n");
2513 
2514  for (i=0;i<3;i++) {
2516  ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2517  }
2519  expect(3, r);
2521  ok(r == -1, "got %d\n", r);
2522 
2523  /* select one more */
2524  item.state = LVIS_SELECTED;
2525  item.stateMask = LVIS_SELECTED;
2527  ok(r, "got %d\n", r);
2528 
2529  for (i=0;i<3;i++) {
2531  ok(!(r & LVIS_SELECTED), "Expected item %d to be unselected\n", i);
2532  }
2533 
2535  ok(r & LVIS_SELECTED, "Expected item %d to be selected\n", i);
2536 
2538  expect(1, r);
2540  expect(-1, r);
2541 
2542  /* try to select all on LVS_SINGLESEL */
2543  memset(&item, 0, sizeof(item));
2544  item.stateMask = LVIS_SELECTED;
2546  expect(TRUE, r);
2548  ok(r == -1, "got %d\n", r);
2549 
2550  item.stateMask = LVIS_SELECTED;
2551  item.state = LVIS_SELECTED;
2553  expect(FALSE, r);
2554 
2556  expect(0, r);
2558  expect(-1, r);
2559 
2560  /* try to deselect all on LVS_SINGLESEL */
2561  item.stateMask = LVIS_SELECTED;
2562  item.state = LVIS_SELECTED;
2564  expect(TRUE, r);
2565 
2566  item.stateMask = LVIS_SELECTED;
2567  item.state = 0;
2569  expect(TRUE, r);
2571  expect(0, r);
2572 
2573  /* 1. selection mark is update when new focused item is set */
2576 
2578  expect(-1, r);
2579 
2580  item.stateMask = LVIS_FOCUSED;
2581  item.state = LVIS_FOCUSED;
2583  expect(TRUE, r);
2584 
2586  expect(0, r);
2587 
2588  /* it's not updated if already set */
2589  item.stateMask = LVIS_FOCUSED;
2590  item.state = LVIS_FOCUSED;
2592  expect(TRUE, r);
2593 
2595  expect(0, r);
2596 
2598  expect(0, r);
2599 
2600  item.stateMask = LVIS_FOCUSED;
2601  item.state = LVIS_FOCUSED;
2603  expect(TRUE, r);
2604 
2606  expect(-1, r);
2607 
2608  /* need to reset focused item first */
2609  item.stateMask = LVIS_FOCUSED;
2610  item.state = 0;
2612  expect(TRUE, r);
2613 
2614  item.stateMask = LVIS_FOCUSED;
2615  item.state = LVIS_FOCUSED;
2617  expect(TRUE, r);
2618 
2620  expect(2, r);
2621 
2622  item.stateMask = LVIS_FOCUSED;
2623  item.state = 0;
2625  expect(TRUE, r);
2626 
2628  expect(2, r);
2629 
2630  /* 2. same tests, with LVM_SETITEM */
2633 
2635  expect(2, r);
2636 
2637  item.stateMask = LVIS_FOCUSED;
2638  item.state = LVIS_FOCUSED;
2639  item.mask = LVIF_STATE;
2640  item.iItem = item.iSubItem = 0;
2642  expect(TRUE, r);
2643 
2645  expect(0, r);
2646 
2647  /* it's not updated if already set */
2648  item.stateMask = LVIS_FOCUSED;
2649  item.state = LVIS_FOCUSED;
2650  item.mask = LVIF_STATE;
2651  item.iItem = 1;
2652  item.iSubItem = 0;
2654  expect(TRUE, r);
2655 
2657  expect(0, r);
2658 
2660  expect(0, r);
2661 
2662  item.stateMask = LVIS_FOCUSED;
2663  item.state = LVIS_FOCUSED;
2664  item.mask = LVIF_STATE;
2665  item.iItem = 1;
2666  item.iSubItem = 0;
2668  expect(TRUE, r);
2669 
2671  expect(-1, r);
2672 
2673  /* need to reset focused item first */
2674  item.stateMask = LVIS_FOCUSED;
2675  item.state = 0;
2677  expect(TRUE, r);
2678 
2679  item.stateMask = LVIS_FOCUSED;
2680  item.state = LVIS_FOCUSED;
2681  item.mask = LVIF_STATE;
2682  item.iItem = 2;
2683  item.iSubItem = 0;
2685  expect(TRUE, r);
2686 
2688  expect(2, r);
2689 
2690  item.stateMask = LVIS_FOCUSED;
2691  item.state = 0;
2693  expect(TRUE, r);
2694 
2696  expect(2, r);
2697 
2699 }
2700 
2701 static void test_subitem_rect(void)
2702 {
2703  HWND hwnd;
2704  DWORD r;
2705  LVCOLUMNA col;
2706  RECT rect, rect2;
2707  INT arr[3];
2708 
2709  /* test LVM_GETSUBITEMRECT for header */
2711  ok(hwnd != NULL, "failed to create a listview window\n");
2712  /* add some columns */
2713  memset(&col, 0, sizeof(LVCOLUMNA));
2714  col.mask = LVCF_WIDTH;
2715  col.cx = 100;
2716  r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2717  expect(0, r);
2718  col.cx = 150;
2719  r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2720  expect(1, r);
2721  col.cx = 200;
2722  r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2723  expect(2, r);
2724  /* item = -1 means header, subitem index is 1 based */
2725  SetRect(&rect, LVIR_BOUNDS, 0, 0, 0);
2727  expect(0, r);
2728 
2729  SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2731  expect(1, r);
2732 
2733  expect(100, rect.left);
2734  expect(250, rect.right);
2735  expect(3, rect.top);
2736 
2737  SetRect(&rect, LVIR_BOUNDS, 2, 0, 0);
2739  expect(1, r);
2740 
2741  expect(250, rect.left);
2742  expect(450, rect.right);
2743  expect(3, rect.top);
2744 
2745  /* item LVS_REPORT padding isn't applied to subitems */
2746  insert_item(hwnd, 0);
2747 
2748  SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2750  expect(1, r);
2751  expect(100, rect.left);
2752  expect(250, rect.right);
2753 
2754  SetRect(&rect, LVIR_ICON, 1, 0, 0);
2756  expect(1, r);
2757  /* no icon attached - zero width rectangle, with no left padding */
2758  expect(100, rect.left);
2759  expect(100, rect.right);
2760 
2761  SetRect(&rect, LVIR_LABEL, 1, 0, 0);
2763  expect(1, r);
2764  /* same as full LVIR_BOUNDS */
2765  expect(100, rect.left);
2766  expect(250, rect.right);
2767 
2768  r = SendMessageA(hwnd, LVM_SCROLL, 10, 0);
2769  ok(r, "got %d\n", r);
2770 
2771  SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2773  expect(1, r);
2774  expect(90, rect.left);
2775  expect(240, rect.right);
2776 
2777  SendMessageA(hwnd, LVM_SCROLL, -10, 0);
2778 
2779  /* test header interaction */
2782 
2783  SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2785  expect(1, r);
2786 
2787  SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2789  expect(1, r);
2790 
2791  SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2793  expect(1, r);
2794 
2795  SetRect(&rect, LVIR_BOUNDS, 1, 0, 0);
2797  expect(1, r);
2798 
2799  ok_sequence(sequences, LISTVIEW_SEQ_INDEX, getsubitemrect_seq, "LVM_GETSUBITEMRECT negative index", FALSE);
2800 
2802 
2803  /* test subitem rects after re-arranging columns */
2805  ok(hwnd != NULL, "failed to create a listview window\n");
2806  memset(&col, 0, sizeof(LVCOLUMNA));
2807  col.mask = LVCF_WIDTH;
2808 
2809  col.cx = 100;
2810  r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM)&col);
2811  expect(0, r);
2812 
2813  col.cx = 200;
2814  r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 1, (LPARAM)&col);
2815  expect(1, r);
2816 
2817  col.cx = 300;
2818  r = SendMessageA(hwnd, LVM_INSERTCOLUMNA, 2, (LPARAM)&col);
2819  expect(2, r);
2820 
2821  insert_item(hwnd, 0);
2822  insert_item(hwnd, 1);
2823 
2824  /* wrong item is refused for main item */
2825  SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2827  expect(FALSE, r);
2828 
2829  /* for subitems rectangle is calculated even if there's no item added */
2830  SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2832  expect(TRUE, r);
2833 
2834  SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2836  expect(TRUE, r);
2837  expect(rect.right, rect2.right);
2838  expect(rect.left, rect2.left);
2839  expect(rect.bottom, rect2.top);
2840  ok(rect2.bottom > rect2.top, "expected not zero height\n");
2841 
2842  arr[0] = 1; arr[1] = 0; arr[2] = 2;
2844  expect(TRUE, r);
2845 
2846  SetRect(&rect, LVIR_BOUNDS, 0, -1, -1);
2848  expect(TRUE, r);
2849  expect(0, rect.left);
2850  expect(600, rect.right);
2851 
2852  SetRect(&rect, LVIR_BOUNDS, 1, -1, -1);
2854  expect(TRUE, r);
2855  expect(0, rect.left);
2856  expect(200, rect.right);
2857 
2858  SetRect(&rect2, LVIR_BOUNDS, 1, -1, -1);
2860  expect(TRUE, r);
2861  expect(0, rect2.left);
2862  expect(200, rect2.right);
2863  /* items are of the same height */
2864  ok(rect2.top > 0, "expected positive item height\n");
2865  expect(rect.bottom, rect2.top);
2866  expect(rect.bottom * 2 - rect.top, rect2.bottom);
2867 
2868  SetRect(&rect, LVIR_BOUNDS, 2, -1, -1);
2870  expect(TRUE, r);
2871  expect(300, rect.left);
2872  expect(600, rect.right);
2873 
2875 
2876  /* try it for non LVS_REPORT style */
2877  hwnd = CreateWindowA(WC_LISTVIEWA, "Test", LVS_ICON, 0, 0, 100, 100, NULL, NULL,
2878  GetModuleHandleA(NULL), 0);
2879  SetRect(&rect, LVIR_BOUNDS, 1, -10, -10);
2881  expect(0, r);
2882  /* rect is unchanged */
2883  expect(0, rect.left);
2884  expect(-10, rect.right);
2885  expect(1, rect.top);
2886  expect(-10, rect.bottom);
2888 }
2889 
2890 /* comparison callback for test_sorting */
2892 {
2893  if (first == second) return 0;
2894  return (first > second ? 1 : -1);
2895 }
2896 
2897 static void test_sorting(void)
2898 {
2899  HWND hwnd;
2900  LVITEMA item = {0};
2901  INT r;
2902  LONG_PTR style;
2903  static CHAR names[][5] = {"A", "B", "C", "D", "0"};
2904  CHAR buff[10];
2905 
2907  ok(hwnd != NULL, "failed to create a listview window\n");
2908 
2909  /* insert some items */
2910  item.mask = LVIF_PARAM | LVIF_STATE;
2911  item.state = LVIS_SELECTED;
2912  item.iItem = 0;
2913  item.iSubItem = 0;
2914  item.lParam = 3;
2916  expect(0, r);
2917 
2918  item.mask = LVIF_PARAM;
2919  item.iItem = 1;
2920  item.iSubItem = 0;
2921  item.lParam = 2;
2923  expect(1, r);
2924 
2925  item.mask = LVIF_STATE | LVIF_PARAM;
2926  item.state = LVIS_SELECTED;
2927  item.iItem = 2;
2928  item.iSubItem = 0;
2929  item.lParam = 4;
2931  expect(2, r);
2932 
2934  expect(-1, r);
2935 
2937  expect(2, r);
2938 
2940  expect(TRUE, r);
2941 
2943  expect(2, r);
2945  expect(-1, r);
2947  expect(0, r);
2952 
2954 
2955  /* switch to LVS_SORTASCENDING when some items added */
2957  ok(hwnd != NULL, "failed to create a listview window\n");
2958 
2959  item.mask = LVIF_TEXT;
2960  item.iItem = 0;
2961  item.iSubItem = 0;
2962  item.pszText = names[1];
2964  expect(0, r);
2965 
2966  item.mask = LVIF_TEXT;
2967  item.iItem = 1;
2968  item.iSubItem = 0;
2969  item.pszText = names[2];
2971  expect(1, r);
2972 
2973  item.mask = LVIF_TEXT;
2974  item.iItem = 2;
2975  item.iSubItem = 0;
2976  item.pszText = names[0];
2978  expect(2, r);
2979 
2983  ok(style & LVS_SORTASCENDING, "Expected LVS_SORTASCENDING to be set\n");
2984 
2985  /* no sorting performed when switched to LVS_SORTASCENDING */
2986  item.mask = LVIF_TEXT;
2987  item.iItem = 0;
2988  item.pszText = buff;
2989  item.cchTextMax = sizeof(buff);
2991  expect(TRUE, r);
2992  ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
2993 
2994  item.iItem = 1;
2996  expect(TRUE, r);
2997  ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
2998 
2999  item.iItem = 2;
3001  expect(TRUE, r);
3002  ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3003 
3004  /* adding new item doesn't resort list */
3005  item.mask = LVIF_TEXT;
3006  item.iItem = 3;
3007  item.iSubItem = 0;
3008  item.pszText = names[3];
3010  expect(3, r);
3011 
3012  item.mask = LVIF_TEXT;
3013  item.iItem = 0;
3014  item.pszText = buff;
3015  item.cchTextMax = sizeof(buff);
3017  expect(TRUE, r);
3018  ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3019 
3020  item.iItem = 1;
3022  expect(TRUE, r);
3023  ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3024 
3025  item.iItem = 2;
3027  expect(TRUE, r);
3028  ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3029 
3030  item.iItem = 3;
3032  expect(TRUE, r);
3033  ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3034 
3035  /* corner case - item should be placed at first position */
3036  item.mask = LVIF_TEXT;
3037  item.iItem = 4;
3038  item.iSubItem = 0;
3039  item.pszText = names[4];
3041  expect(0, r);
3042 
3043  item.iItem = 0;
3044  item.pszText = buff;
3045  item.cchTextMax = sizeof(buff);
3047  expect(TRUE, r);
3048  ok(lstrcmpA(buff, names[4]) == 0, "Expected '%s', got '%s'\n", names[4], buff);
3049 
3050  item.iItem = 1;
3051  item.pszText = buff;
3052  item.cchTextMax = sizeof(buff);
3054  expect(TRUE, r);
3055  ok(lstrcmpA(buff, names[1]) == 0, "Expected '%s', got '%s'\n", names[1], buff);
3056 
3057  item.iItem = 2;
3059  expect(TRUE, r);
3060  ok(lstrcmpA(buff, names[2]) == 0, "Expected '%s', got '%s'\n", names[2], buff);
3061 
3062  item.iItem = 3;
3064  expect(TRUE, r);
3065  ok(lstrcmpA(buff, names[0]) == 0, "Expected '%s', got '%s'\n", names[0], buff);
3066 
3067  item.iItem = 4;
3069  expect(TRUE, r);
3070  ok(lstrcmpA(buff, names[3]) == 0, "Expected '%s', got '%s'\n", names[3], buff);
3071 
3073 }
3074 
3075 static void test_ownerdata(void)
3076 {
3077  static char test_str[] = "test";
3078 
3079  HWND hwnd;
3080  LONG_PTR style, ret;
3081  DWORD res;
3082  LVITEMA item;
3083 
3084  /* it isn't possible to set LVS_OWNERDATA after creation */
3085  if (g_is_below_5)
3086  {
3087  win_skip("set LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3088  }
3089  else
3090  {
3092  ok(hwnd != NULL, "failed to create a listview window\n");
3094  ok(!(style & LVS_OWNERDATA) && style, "LVS_OWNERDATA isn't expected\n");
3095 
3097 
3099  ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3101  "try to switch to LVS_OWNERDATA seq", FALSE);
3102 
3104  ok(!(style & LVS_OWNERDATA), "LVS_OWNERDATA isn't expected\n");
3106  }
3107 
3108  /* try to set LVS_OWNERDATA after creation just having it */
3110  ok(hwnd != NULL, "failed to create a listview window\n");
3112  ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3113 
3115 
3117  ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3119  "try to switch to LVS_OWNERDATA seq", FALSE);
3121 
3122  /* try to remove LVS_OWNERDATA after creation just having it */
3123  if (g_is_below_5)
3124  {
3125  win_skip("remove LVS_OWNERDATA after creation leads to crash on < 5.80\n");
3126  }
3127  else
3128  {
3130  ok(hwnd != NULL, "failed to create a listview window\n");
3132  ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3133 
3135 
3137  ok(ret == style, "Expected set GWL_STYLE to succeed\n");
3139  "try to switch to LVS_OWNERDATA seq", FALSE);
3141  ok(style & LVS_OWNERDATA, "LVS_OWNERDATA is expected\n");
3143  }
3144 
3145  /* try select an item */
3147  ok(hwnd != NULL, "failed to create a listview window\n");
3149  expect(1, res);
3151  expect(0, res);
3152  memset(&item, 0, sizeof(item));
3153  item.stateMask = LVIS_SELECTED;
3154  item.state = LVIS_SELECTED;
3156  expect(TRUE, res);
3158  expect(1, res);
3160  expect(1, res);
3162 
3163  /* LVM_SETITEM and LVM_SETITEMTEXT is unsupported on LVS_OWNERDATA */
3165  ok(hwnd != NULL, "failed to create a listview window\n");
3167  expect(1, res);
3169