ReactOS  0.4.13-dev-563-g0561610
treeview.c
Go to the documentation of this file.
1 /* Unit tests for treeview.
2  *
3  * Copyright 2005 Krzysztof Foltman
4  * Copyright 2007 Christopher James Peterson
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 #include <stdio.h>
23 
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "winreg.h"
30 #include "wine/commctrl.h"
31 
32 #include "wine/test.h"
33 #include "v6util.h"
34 #include "msg.h"
35 
36 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
37 static const char *TEST_CALLBACK_TEXT = "callback_text";
38 
46 static BOOL g_v6;
47 
48 #define NUM_MSG_SEQUENCES 3
49 #define TREEVIEW_SEQ_INDEX 0
50 #define PARENT_SEQ_INDEX 1
51 #define PARENT_CD_SEQ_INDEX 2
52 
53 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
54 
56 static struct msg_sequence *item_sequence[1];
57 
58 static void flush_events(void)
59 {
60  MSG msg;
61  int diff = 200;
62  int min_timeout = 100;
63  DWORD time = GetTickCount() + diff;
64 
65  while (diff > 0)
66  {
67  if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break;
68  while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
69  diff = time - GetTickCount();
70  }
71 }
72 
73 static const struct message FillRootSeq[] = {
74  { TVM_INSERTITEMA, sent },
75  { TVM_INSERTITEMA, sent },
76  { 0 }
77 };
78 
79 static const struct message rootnone_select_seq[] = {
80  { TVM_SELECTITEM, sent|wparam, 9 },
81  { TVM_SELECTITEM, sent|wparam, 9 },
82  { TVM_SELECTITEM, sent|wparam, 9 },
83  { TVM_SELECTITEM, sent|wparam, 9 },
84  { TVM_SELECTITEM, sent|wparam, 9 },
85  { TVM_SELECTITEM, sent|wparam, 9 },
86  { 0 }
87 };
88 
89 static const struct message rootchild_select_seq[] = {
90  { TVM_SELECTITEM, sent|wparam, 9 },
91  { TVM_SELECTITEM, sent|wparam, 9 },
92  { TVM_SELECTITEM, sent|wparam, 9 },
93  { TVM_SELECTITEM, sent|wparam, 9 },
94  { TVM_SELECTITEM, sent|wparam, 9 },
95  { TVM_SELECTITEM, sent|wparam, 9 },
96  { 0 }
97 };
98 
99 static const struct message getitemtext_seq[] = {
100  { TVM_INSERTITEMA, sent },
101  { TVM_GETITEMA, sent },
102  { TVM_DELETEITEM, sent },
103  { 0 }
104 };
105 
106 static const struct message focus_seq[] = {
107  { TVM_INSERTITEMA, sent },
108  { TVM_INSERTITEMA, sent },
109  { TVM_SELECTITEM, sent|wparam, 9 },
110  /* The following end up out of order in wine */
114  { WM_SIZE, sent|defwinproc },
119  { WM_PAINT, sent|defwinproc },
122  { TVM_EDITLABELA, sent },
127  { WM_PAINT, sent|defwinproc },
133  { 0 }
134 };
135 
136 static const struct message test_get_set_bkcolor_seq[] = {
137  { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
138  { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0 },
139  { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
140  { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
141  { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
142  { TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 },
143  { 0 }
144 };
145 
146 static const struct message test_get_set_imagelist_seq[] = {
147  { TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 },
148  { TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 },
149  { 0 }
150 };
151 
152 static const struct message test_get_set_indent_seq[] = {
153  { TVM_SETINDENT, sent|wparam|lparam, 0, 0 },
154  { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
155  /* The actual amount to indent is dependent on the system for this message */
156  { TVM_SETINDENT, sent },
157  { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
158  { 0 }
159 };
160 
161 static const struct message test_get_set_insertmarkcolor_seq[] = {
164  { 0 }
165 };
166 
167 static const struct message test_get_set_item_seq[] = {
168  { TVM_GETITEMA, sent },
169  { TVM_SETITEMA, sent },
170  { TVM_GETITEMA, sent },
171  { TVM_SETITEMA, sent },
172  { 0 }
173 };
174 
175 static const struct message test_get_set_itemheight_seq[] = {
176  { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
177  { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 },
178  { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
179  { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 },
182  { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
183  { 0 }
184 };
185 
186 static const struct message test_get_set_scrolltime_seq[] = {
187  { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 },
188  { TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 },
189  { 0 }
190 };
191 
192 static const struct message test_get_set_textcolor_seq[] = {
193  { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
194  { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
195  { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
196  { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, RGB(255, 255, 255) },
197  { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
199  { 0 }
200 };
201 
202 static const struct message test_get_set_tooltips_seq[] = {
203  { WM_KILLFOCUS, sent },
206  { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 },
207  { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
208  { 0 }
209 };
210 
211 static const struct message test_get_set_unicodeformat_seq[] = {
217  { 0 }
218 };
219 
220 static const struct message test_right_click_seq[] = {
227  { 0 }
228 };
229 
230 static const struct message parent_expand_seq[] = {
231  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
232  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
233  { 0 }
234 };
235 
236 static const struct message parent_expand_kb_seq[] = {
237  { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN },
238  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
239  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
240  { WM_CHANGEUISTATE, sent|optional },
241  { 0 }
242 };
243 
244 static const struct message parent_collapse_2nd_kb_seq[] = {
245  { WM_NOTIFY, sent|id|optional, 0, 0, TVN_KEYDOWN },
246  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
247  { WM_CHANGEUISTATE, sent|optional },
248  { 0 }
249 };
250 
251 static const struct message parent_expand_empty_kb_seq[] = {
252  { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN },
253  { WM_CHANGEUISTATE, sent|optional },
254  { 0 }
255 };
256 
257 static const struct message parent_singleexpand_seq0[] = {
258  /* alpha expands */
259  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
260  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
261  { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
262  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
263  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
264  { 0 }
265 };
266 
267 static const struct message parent_singleexpand_seq1[] = {
268  /* bravo expands */
269  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
270  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
271  { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
272  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
273  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
274  { 0 }
275 };
276 
277 static const struct message parent_singleexpand_seq2[] = {
278  /* delta expands, bravo collapses */
279  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
280  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
281  { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
282  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
283  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
284  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
285  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
286  { 0 }
287 };
288 
289 static const struct message parent_singleexpand_seq3[] = {
290  /* foxtrot expands, alpha and delta collapse */
291  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
292  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
293  { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
294  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
295  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
296  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
297  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
298  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
299  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
300  { 0 }
301 };
302 
303 static const struct message parent_singleexpand_seq4[] = {
304  /* alpha expands, foxtrot collapses */
305  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
306  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
307  { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
308  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
309  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
310  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
311  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
312  { 0 }
313 };
314 
315 static const struct message parent_singleexpand_seq5[] = {
316  /* foxtrot expands while golf is selected, then golf expands and alpha collapses */
317  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
318  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
319  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
320  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
321  { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
322  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
323  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
324  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
325  { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
326  { 0 }
327 };
328 
329 static const struct message parent_singleexpand_seq6[] = {
330  /* hotel does not expand and india does not collapse because they have no children */
331  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
332  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
333  { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
334  { 0 }
335 };
336 
337 static const struct message parent_singleexpand_seq7[] = {
338  /* india does not expand and hotel does not collapse because they have no children */
339  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
340  { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
341  { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
342  { 0 }
343 };
344 
345 static const struct message parent_get_dispinfo_seq[] = {
346  { WM_NOTIFY, sent|id, 0, 0, TVN_GETDISPINFOA },
347  { 0 }
348 };
349 
350 static const struct message empty_seq[] = {
351  { 0 }
352 };
353 
354 static const struct message parent_cd_seq[] = {
361  { 0 }
362 };
363 
364 static const struct message parent_vk_return_seq[] = {
365  { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN },
366  { WM_NOTIFY, sent|id, 0, 0, NM_RETURN },
367  { WM_CHANGEUISTATE, sent|optional },
368  { 0 }
369 };
370 
371 static const struct message parent_right_click_seq[] = {
372  { WM_NOTIFY, sent|id, 0, 0, NM_RCLICK },
373  { WM_CONTEXTMENU, sent },
374  { WM_NOTIFY, sent|optional },
376  { 0 }
377 };
378 
379 static HWND hMainWnd;
380 
382 
383 static int pos = 0;
384 static char sequence[256];
385 
386 static void Clear(void)
387 {
388  pos = 0;
389  sequence[0] = '\0';
390 }
391 
392 static void AddItem(char ch)
393 {
394  sequence[pos++] = ch;
395  sequence[pos] = '\0';
396 }
397 
399 {
400  if (hItem == hRoot) {
401  AddItem('R');
402  return;
403  }
404  if (hItem == hChild) {
405  AddItem('C');
406  return;
407  }
408  if (hItem == NULL) {
409  AddItem('n');
410  return;
411  }
412  AddItem('?');
413 }
414 
415 /* This function hooks in and records all messages to the treeview control */
417 {
418  static LONG defwndproc_counter = 0;
419  LRESULT ret;
421  struct message msg = { 0 };
422 
423  msg.message = message;
424  msg.flags = sent|wparam|lparam;
425  if (defwndproc_counter) msg.flags |= defwinproc;
426  msg.wParam = wParam;
427  msg.lParam = lParam;
429 
430  defwndproc_counter++;
431  ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam);
432  defwndproc_counter--;
433 
434  return ret;
435 }
436 
438 {
440  HWND hTree;
441 
444  0, 0, 120, 100, hMainWnd, (HMENU)100, GetModuleHandleA(0), 0);
445 
446  SetFocus(hTree);
447 
448  /* Record the old WNDPROC so we can call it after recording the messages */
451 
452  return hTree;
453 }
454 
455 static void fill_tree(HWND hTree)
456 {
457  TVINSERTSTRUCTA ins;
458  static CHAR root[] = "Root",
459  child[] = "Child";
460 
461  ins.hParent = TVI_ROOT;
462  ins.hInsertAfter = TVI_ROOT;
463  U(ins).item.mask = TVIF_TEXT;
464  U(ins).item.pszText = root;
466 
467  ins.hParent = hRoot;
468  ins.hInsertAfter = TVI_FIRST;
469  U(ins).item.mask = TVIF_TEXT;
470  U(ins).item.pszText = child;
472 }
473 
474 static void test_fillroot(void)
475 {
476  TVITEMA tvi;
477  HWND hTree;
478 
480 
482 
483  fill_tree(hTree);
484 
485  Clear();
486  AddItem('A');
487  ok(hRoot != NULL, "failed to set root\n");
488  AddItem('B');
489  ok(hChild != NULL, "failed to set child\n");
490  AddItem('.');
492  ok(!strcmp(sequence, "AB."), "Item creation\n");
493 
494  /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */
495  tvi.hItem = hRoot;
498  ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage);
499  ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage);
500 
502 }
503 
504 static void test_callback(void)
505 {
507  HTREEITEM hItem1, hItem2;
508  TVINSERTSTRUCTA ins;
509  TVITEMA tvi;
510  CHAR test_string[] = "Test_string";
511  static const CHAR test2A[] = "TEST2";
512  CHAR buf[128];
513  HWND hTree;
514  DWORD ret;
515 
517 
519  expect(TRUE, ret);
520  ins.hParent = TVI_ROOT;
521  ins.hInsertAfter = TVI_ROOT;
522  U(ins).item.mask = TVIF_TEXT;
523  U(ins).item.pszText = LPSTR_TEXTCALLBACKA;
525  ok(hRoot != NULL, "failed to set root\n");
526 
527  tvi.hItem = hRoot;
528  tvi.mask = TVIF_TEXT;
529  tvi.pszText = buf;
530  tvi.cchTextMax = ARRAY_SIZE(buf);
531  ret = TreeView_GetItemA(hTree, &tvi);
532  expect(TRUE, ret);
533  ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n",
535 
536  ins.hParent = hRoot;
537  ins.hInsertAfter = TVI_FIRST;
538  U(ins).item.mask = TVIF_TEXT;
539  U(ins).item.pszText = test_string;
540  hItem1 = TreeView_InsertItemA(hTree, &ins);
541  ok(hItem1 != NULL, "failed to set Item1\n");
542 
543  tvi.hItem = hItem1;
544  ret = TreeView_GetItemA(hTree, &tvi);
545  expect(TRUE, ret);
546  ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
547  tvi.pszText, test_string);
548 
549  /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */
550  tvi.pszText = NULL;
551  ret = TreeView_SetItemA(hTree, &tvi);
552  expect(TRUE, ret);
553  tvi.pszText = buf;
554  ret = TreeView_GetItemA(hTree, &tvi);
555  expect(TRUE, ret);
556  ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
558 
559  U(ins).item.pszText = NULL;
560  hItem2 = TreeView_InsertItemA(hTree, &ins);
561  ok(hItem2 != NULL, "failed to set Item2\n");
562  tvi.hItem = hItem2;
563  memset(buf, 0, sizeof(buf));
564  ret = TreeView_GetItemA(hTree, &tvi);
565  expect(TRUE, ret);
566  ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
568 
569  /* notification handler changed A->W */
571  tvi.hItem = hItem2;
572  memset(buf, 0, sizeof(buf));
573  ret = TreeView_GetItemA(hTree, &tvi);
574  expect(TRUE, ret);
575  ok(strcmp(tvi.pszText, test2A) == 0, "got %s, expected %s\n",
576  tvi.pszText, test2A);
578 
579  /* handler changes state image index */
581 
582  /* clear selection, handler will set selected state */
584  expect(TRUE, ret);
585 
587 
588  tvi.hItem = hRoot;
589  tvi.mask = TVIF_STATE;
590  tvi.state = TVIS_SELECTED;
591  ret = TreeView_GetItemA(hTree, &tvi);
592  expect(TRUE, ret);
593  ok(tvi.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", tvi.state);
594 
596  "no TVN_GETDISPINFO for a state seq", FALSE);
597 
598  tvi.hItem = hRoot;
599  tvi.mask = TVIF_IMAGE | TVIF_STATE;
600  tvi.state = TVIS_FOCUSED;
601  tvi.stateMask = TVIS_FOCUSED;
602  tvi.iImage = I_IMAGECALLBACK;
603  ret = TreeView_SetItemA(hTree, &tvi);
604  expect(TRUE, ret);
605 
606  /* ask for item image index through callback - state is also set with state image index */
608 
609  tvi.hItem = hRoot;
610  tvi.mask = TVIF_IMAGE;
611  tvi.state = 0;
612  ret = TreeView_GetItemA(hTree, &tvi);
613  expect(TRUE, ret);
614  ok(tvi.state == (INDEXTOSTATEIMAGEMASK(1) | TVIS_FOCUSED), "got 0x%x\n", tvi.state);
615 
617  "callback for state/overlay image index, noop seq", FALSE);
618 
619  /* ask for image again and overwrite state to some value in handler */
621 
623  tvi.hItem = hRoot;
624  tvi.mask = TVIF_IMAGE;
625  tvi.state = INDEXTOSTATEIMAGEMASK(1);
626  tvi.stateMask = 0;
627  ret = TreeView_GetItemA(hTree, &tvi);
628  expect(TRUE, ret);
629  /* handler sets TVIS_SELECTED as well */
630  ok(tvi.state == (TVIS_FOCUSED | TVIS_SELECTED | INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3)), "got 0x%x\n", tvi.state);
632 
634  "callback for state/overlay image index seq", FALSE);
635 
637 }
638 
639 static void test_select(void)
640 {
641  BOOL r;
642  HWND hTree;
643 
645  fill_tree(hTree);
646 
647  /* root-none select tests */
650  expect(TRUE, r);
651  Clear();
652  AddItem('1');
654  expect(TRUE, r);
655  AddItem('2');
657  expect(TRUE, r);
658  AddItem('3');
660  expect(TRUE, r);
661  AddItem('4');
663  expect(TRUE, r);
664  AddItem('5');
666  expect(TRUE, r);
667  AddItem('.');
668  ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
670  "root-none select seq", FALSE);
671 
672  /* root-child select tests */
675  expect(TRUE, r);
676 
677  Clear();
678  AddItem('1');
680  expect(TRUE, r);
681  AddItem('2');
683  expect(TRUE, r);
684  AddItem('3');
686  expect(TRUE, r);
687  AddItem('4');
689  expect(TRUE, r);
690  AddItem('5');
692  expect(TRUE, r);
693  AddItem('.');
694  ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
696  "root-child select seq", FALSE);
697 
699 }
700 
701 static void test_getitemtext(void)
702 {
703  TVINSERTSTRUCTA ins;
705  TVITEMA tvi;
706  HWND hTree;
707 
708  CHAR szBuffer[80] = "Blah";
709  int nBufferSize = ARRAY_SIZE(szBuffer);
710 
712  fill_tree(hTree);
713 
715 
716  /* add an item without TVIF_TEXT mask and pszText == NULL */
717  ins.hParent = hRoot;
718  ins.hInsertAfter = TVI_ROOT;
719  U(ins).item.mask = 0;
720  U(ins).item.pszText = NULL;
721  U(ins).item.cchTextMax = 0;
723  ok(hChild != NULL, "failed to set hChild\n");
724 
725  /* retrieve it with TVIF_TEXT mask */
726  tvi.hItem = hChild;
727  tvi.mask = TVIF_TEXT;
728  tvi.cchTextMax = nBufferSize;
729  tvi.pszText = szBuffer;
730 
731  SendMessageA( hTree, TVM_GETITEMA, 0, (LPARAM)&tvi );
732  ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer);
733  ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n");
735 
737 }
738 
739 static void test_focus(void)
740 {
741  TVINSERTSTRUCTA ins;
742  static CHAR child1[] = "Edit",
743  child2[] = "A really long string";
744  HTREEITEM hChild1, hChild2;
745  HWND hTree;
746  HWND hEdit;
747 
749  fill_tree(hTree);
750 
752 
753  /* This test verifies that when a label is being edited, scrolling
754  * the treeview does not cause the label to lose focus. To test
755  * this, first some additional entries are added to generate
756  * scrollbars.
757  */
758  ins.hParent = hRoot;
759  ins.hInsertAfter = hChild;
760  U(ins).item.mask = TVIF_TEXT;
761  U(ins).item.pszText = child1;
762  hChild1 = TreeView_InsertItemA(hTree, &ins);
763  ok(hChild1 != NULL, "failed to set hChild1\n");
764  ins.hInsertAfter = hChild1;
765  U(ins).item.mask = TVIF_TEXT;
766  U(ins).item.pszText = child2;
767  hChild2 = TreeView_InsertItemA(hTree, &ins);
768  ok(hChild2 != NULL, "failed to set hChild2\n");
769 
774  ok(GetFocus() == hEdit, "Edit control should have focus\n");
776 
778 }
779 
780 static void test_get_set_bkcolor(void)
781 {
782  COLORREF crColor;
783  HWND hTree;
784 
786  fill_tree(hTree);
787 
789 
790  /* If the value is -1, the control is using the system color for the background color. */
791  crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0);
792  ok(crColor == ~0u, "Default background color reported as 0x%.8x\n", crColor);
793 
794  /* Test for black background */
795  SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(0,0,0));
796  crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0);
797  ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor);
798 
799  /* Test for white background */
800  SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(255,255,255));
801  crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0);
802  ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor);
803 
804  /* Reset the default background */
806 
808  "test get set bkcolor", FALSE);
809 
811 }
812 
813 static void test_get_set_imagelist(void)
814 {
816  HWND hTree;
817 
819  fill_tree(hTree);
820 
822 
823  /* Test a NULL HIMAGELIST */
826  ok(himl == NULL, "NULL image list, reported as %p, expected 0.\n", himl);
827 
828  /* TODO: Test an actual image list */
829 
831  "test get imagelist", FALSE);
832 
834 }
835 
836 static void test_get_set_indent(void)
837 {
838  int ulIndent;
839  int ulMinIndent;
840  int ulMoreThanTwiceMin;
841  HWND hTree;
842 
844  fill_tree(hTree);
845 
847 
848  /* Finding the minimum indent */
850  ulMinIndent = SendMessageA(hTree, TVM_GETINDENT, 0, 0);
851 
852  /* Checking an indent that is more than twice the default indent */
853  ulMoreThanTwiceMin = 2*ulMinIndent+1;
854  SendMessageA(hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0);
855  ulIndent = SendMessageA(hTree, TVM_GETINDENT, 0, 0);
856  ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin);
857 
859  "test get set indent", FALSE);
860 
862 }
863 
864 static void test_get_set_insertmark(void)
865 {
866  COLORREF crColor = RGB(0,0,0);
867  HWND hTree;
868 
870  fill_tree(hTree);
871 
873 
875  crColor = SendMessageA(hTree, TVM_GETINSERTMARKCOLOR, 0, 0);
876  ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor);
877 
879  "test get set insertmark color", FALSE);
880 
882 }
883 
884 static void test_get_set_item(void)
885 {
886  TVITEMA tviRoot = {0};
887  int nBufferSize = 80;
888  char szBuffer[80] = {0};
889  HWND hTree, hTree2;
890  DWORD ret;
891 
893  fill_tree(hTree);
894 
895  tviRoot.hItem = hRoot;
896  tviRoot.mask = TVIF_STATE;
897  tviRoot.state = TVIS_FOCUSED;
898  tviRoot.stateMask = TVIS_FOCUSED;
899  ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot);
900  expect(TRUE, ret);
901 
903 
904  /* Test the root item, state is set even when not requested */
905  tviRoot.hItem = hRoot;
906  tviRoot.mask = TVIF_TEXT;
907  tviRoot.state = 0;
908  tviRoot.stateMask = 0;
909  tviRoot.cchTextMax = nBufferSize;
910  tviRoot.pszText = szBuffer;
911  ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
912  expect(TRUE, ret);
913  ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer);
914  ok(tviRoot.state == TVIS_FOCUSED, "got 0x%0x\n", tviRoot.state);
915 
916  /* Change the root text */
917  lstrcpynA(szBuffer, "Testing123", nBufferSize);
918  ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot);
919  expect(TRUE, ret);
920  memset(szBuffer, 0, nBufferSize);
921  ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
922  expect(TRUE, ret);
923  ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer);
924 
925  /* Reset the root text */
926  memset(szBuffer, 0, nBufferSize);
927  lstrcpynA(szBuffer, "Root", nBufferSize);
928  ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot);
929  expect(TRUE, ret);
930 
932  "test get set item", FALSE);
933 
934  /* get item from a different tree */
935  hTree2 = create_treeview_control(0);
936 
937  tviRoot.hItem = hRoot;
938  tviRoot.mask = TVIF_STATE;
939  tviRoot.state = 0;
940  ret = SendMessageA(hTree2, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
941  expect(TRUE, ret);
942  ok(tviRoot.state == TVIS_FOCUSED, "got state 0x%0x\n", tviRoot.state);
943 
944  /* invalid item pointer, nt4 crashes here but later versions just return 0 */
945  tviRoot.hItem = (HTREEITEM)0xdeadbeef;
946  tviRoot.mask = TVIF_STATE;
947  tviRoot.state = 0;
948  ret = SendMessageA(hTree2, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
949  expect(FALSE, ret);
950 
952  DestroyWindow(hTree2);
953 }
954 
955 static void test_get_set_itemheight(void)
956 {
957  int ulOldHeight = 0;
958  int ulNewHeight = 0;
959  HWND hTree;
960 
962  fill_tree(hTree);
963 
965 
966  /* Assuming default height to begin with */
967  ulOldHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
968 
969  /* Explicitly setting and getting the default height */
971  ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
972  ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight);
973 
974  /* Explicitly setting and getting the height of twice the normal */
975  SendMessageA(hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0);
976  ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
977  ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight);
978 
979  /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
981  ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
982  ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8);
983 
985  "test get set item height", FALSE);
986 
987  /* without TVS_NONEVENHEIGHT */
989  /* odd value */
990  ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 3, 0);
991  ok(ulOldHeight == 8, "got %d, expected %d\n", ulOldHeight, 8);
992  ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
993  ok(ulNewHeight == 2, "got %d, expected %d\n", ulNewHeight, 2);
994 
995  ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 4, 0);
996  ok(ulOldHeight == 2, "got %d, expected %d\n", ulOldHeight, 2);
997  ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
998  ok(ulNewHeight == 4, "got %d, expected %d\n", ulNewHeight, 4);
999 
1000  /* with TVS_NONEVENHEIGHT */
1002  /* odd value */
1003  ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 3, 0);
1004  ok(ulOldHeight == 4, "got %d, expected %d\n", ulOldHeight, 4);
1005  ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
1006  ok(ulNewHeight == 3, "got %d, expected %d\n", ulNewHeight, 3);
1007  /* even value */
1008  ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 10, 0);
1009  ok(ulOldHeight == 3, "got %d, expected %d\n", ulOldHeight, 3);
1010  ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
1011  ok(ulNewHeight == 10, "got %d, expected %d\n", ulNewHeight, 10);
1012 
1014 }
1015 
1016 static void test_get_set_scrolltime(void)
1017 {
1018  int ulExpectedTime = 20;
1019  int ulTime = 0;
1020  HWND hTree;
1021 
1023  fill_tree(hTree);
1024 
1026 
1027  SendMessageA(hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0);
1028  ulTime = SendMessageA(hTree, TVM_GETSCROLLTIME, 0, 0);
1029  ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime);
1030 
1032  "test get set scroll time", FALSE);
1033 
1035 }
1036 
1037 static void test_get_set_textcolor(void)
1038 {
1039  /* If the value is -1, the control is using the system color for the text color. */
1040  COLORREF crColor;
1041  HWND hTree;
1042 
1044  fill_tree(hTree);
1045 
1047 
1048  crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0);
1049  ok(crColor == ~0u, "Default text color reported as 0x%.8x\n", crColor);
1050 
1051  /* Test for black text */
1052  SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, RGB(0,0,0));
1053  crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0);
1054  ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor);
1055 
1056  /* Test for white text */
1057  SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, RGB(255,255,255));
1058  crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0);
1059  ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor);
1060 
1061  /* Reset the default text color */
1063 
1065  "test get set text color", FALSE);
1066 
1068 }
1069 
1070 static void test_get_set_tooltips(void)
1071 {
1072  HWND hTree, tooltips, hwnd;
1073  DWORD style;
1074  int i;
1075 
1076  /* TVS_NOTOOLTIPS */
1078 
1079  tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0);
1080  ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips);
1081 
1082  tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0);
1083  ok(tooltips == NULL, "Unexpected ret value %p.\n", tooltips);
1084 
1085  /* Toggle style */
1088 
1089  tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0);
1090  ok(IsWindow(tooltips), "Unexpected tooltip window %p.\n", tooltips);
1091 
1094 
1095  tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0);
1096  ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips);
1097 
1099 
1100  /* Set some valid window, does not have to be tooltips class. */
1102 
1103  hwnd = CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD, 5, 5, 100, 100, hMainWnd, NULL, NULL, 0);
1104  ok(hwnd != NULL, "Failed to create child window.\n");
1105 
1106  tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0);
1107  ok(tooltips == NULL, "Unexpected ret value %p.\n", tooltips);
1108 
1109  tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0);
1110  ok(tooltips == hwnd, "Unexpected tooltip window %p.\n", tooltips);
1111 
1112  /* Externally set tooltips window, disable style. */
1115 
1116  tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0);
1117  ok(IsWindow(tooltips) && tooltips != hwnd, "Unexpected tooltip window %p.\n", tooltips);
1118  ok(IsWindow(hwnd), "Expected valid window.\n");
1119 
1122  ok(!IsWindow(tooltips), "Unexpected tooltip window %p.\n", tooltips);
1123 
1124  tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0);
1125  ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips);
1126  ok(IsWindow(hwnd), "Expected valid window.\n");
1127 
1129  ok(IsWindow(hwnd), "Expected valid window.\n");
1130 
1131  /* Set window, disable tooltips. */
1133 
1134  tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0);
1135  ok(IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips);
1136 
1139  ok(!IsWindow(hwnd), "Unexpected tooltip window %p.\n", tooltips);
1140  ok(IsWindow(tooltips), "Expected valid window %p.\n", tooltips);
1141 
1143  ok(IsWindow(tooltips), "Expected valid window %p.\n", tooltips);
1144  DestroyWindow(tooltips);
1146 
1147  for (i = 0; i < 2; i++)
1148  {
1149  DWORD style = i == 0 ? 0 : TVS_NOTOOLTIPS;
1150 
1151  hwnd = CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD, 5, 5, 100, 100, hMainWnd, NULL, NULL, 0);
1152  ok(hwnd != NULL, "Failed to create child window.\n");
1153 
1155 
1156  tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0);
1157  ok(style & TVS_NOTOOLTIPS ? tooltips == NULL : IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips);
1158  DestroyWindow(tooltips);
1159 
1160  tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0);
1161  ok(tooltips == hwnd, "Unexpected tooltip window %p.\n", tooltips);
1162 
1163  /* TreeView is destroyed, check if set window is still around. */
1165  ok(!IsWindow(hwnd), "Unexpected window.\n");
1166  }
1167 
1169  fill_tree(hTree);
1170 
1172 
1173  /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */
1174  hwnd = CreateWindowA(WC_TREEVIEWA, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100,
1175  hMainWnd, NULL, NULL, NULL);
1177 
1178  /* Testing setting a NULL ToolTip */
1179  tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0);
1180  ok(IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips);
1181 
1183  ok(hwnd == NULL, "Unexpected tooltip window %p.\n", hwnd);
1184 
1186  "test get set tooltips", TRUE);
1187 
1189  ok(IsWindow(tooltips), "Expected valid window.\n");
1190  DestroyWindow(tooltips);
1191 }
1192 
1194 {
1195  BOOL bPreviousSetting;
1196  BOOL bNewSetting;
1197  HWND hTree;
1198 
1200  fill_tree(hTree);
1201 
1202  /* Check that an invalid format returned by NF_QUERY defaults to ANSI */
1203  bPreviousSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0);
1204  ok(bPreviousSetting == FALSE, "Format should be ANSI.\n");
1205 
1207 
1208  /* Set to Unicode */
1209  bPreviousSetting = SendMessageA(hTree, TVM_SETUNICODEFORMAT, 1, 0);
1210  bNewSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0);
1211  ok(bNewSetting == TRUE, "Unicode setting did not work.\n");
1212 
1213  /* Set to ANSI */
1215  bNewSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0);
1216  ok(bNewSetting == FALSE, "ANSI setting did not work.\n");
1217 
1218  /* Revert to original setting */
1219  SendMessageA(hTree, TVM_SETUNICODEFORMAT, bPreviousSetting, 0);
1220 
1222  "test get set unicode format", FALSE);
1223 
1225 }
1226 
1228 {
1229  static LONG defwndproc_counter = 0;
1230  struct message msg = { 0 };
1231  LRESULT ret;
1232  RECT rect;
1233  HTREEITEM visibleItem;
1234 
1235  msg.message = message;
1236  msg.flags = sent|wparam|lparam;
1237  if (defwndproc_counter) msg.flags |= defwinproc;
1238  msg.wParam = wParam;
1239  msg.lParam = lParam;
1240  if (message == WM_NOTIFY && lParam)
1241  msg.id = ((NMHDR*)lParam)->code;
1242 
1243  /* log system messages, except for painting */
1244  if (message < WM_USER &&
1245  message != WM_PAINT &&
1246  message != WM_ERASEBKGND &&
1247  message != WM_NCPAINT &&
1248  message != WM_NCHITTEST &&
1249  message != WM_GETTEXT &&
1250  message != WM_GETICON &&
1252  {
1254  }
1255 
1256  switch(message) {
1257  case WM_NOTIFYFORMAT:
1258  {
1259  /* Make NF_QUERY return an invalid format to show that it defaults to ANSI */
1260  if (lParam == NF_QUERY) return 0;
1261  break;
1262  }
1263 
1264  case WM_NOTIFY:
1265  {
1266  NMHDR *pHdr = (NMHDR *)lParam;
1267 
1268  ok(pHdr->code != NM_TOOLTIPSCREATED, "Treeview should not send NM_TOOLTIPSCREATED\n");
1269  if (pHdr->idFrom == 100)
1270  {
1271  NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam;
1272  switch(pHdr->code)
1273  {
1274  case TVN_SELCHANGINGA:
1275  AddItem('(');
1276  IdentifyItem(pTreeView->itemOld.hItem);
1277  IdentifyItem(pTreeView->itemNew.hItem);
1278  break;
1279  case TVN_SELCHANGEDA:
1280  AddItem(')');
1281  IdentifyItem(pTreeView->itemOld.hItem);
1282  IdentifyItem(pTreeView->itemNew.hItem);
1283  break;
1284  case TVN_GETDISPINFOA: {
1286  if (disp->item.mask & TVIF_TEXT) {
1287  lstrcpynA(disp->item.pszText, TEST_CALLBACK_TEXT, disp->item.cchTextMax);
1288  }
1289 
1290  if (g_disp_A_to_W && (disp->item.mask & TVIF_TEXT)) {
1291  static const WCHAR testW[] = {'T','E','S','T','2',0};
1292 
1293  disp->hdr.code = TVN_GETDISPINFOW;
1294  memcpy(disp->item.pszText, testW, sizeof(testW));
1295  }
1296 
1298  {
1299  ok(disp->item.mask == TVIF_IMAGE, "got %x\n", disp->item.mask);
1300  /* both masks set here are necessary to change state bits */
1301  disp->item.mask |= TVIF_STATE;
1304  }
1305 
1306  break;
1307  }
1308  case TVN_BEGINLABELEDITA:
1309  {
1311  {
1312  static const char* textA = "<edittextaltered>";
1313  HWND edit;
1314 
1315  edit = (HWND)SendMessageA(pHdr->hwndFrom, TVM_GETEDITCONTROL, 0, 0);
1316  ok(IsWindow(edit), "failed to get edit handle\n");
1317  SetWindowTextA(edit, textA);
1318  }
1319 
1320  break;
1321  }
1322 
1323  case TVN_ENDLABELEDITA: return TRUE;
1324  case TVN_ITEMEXPANDINGA:
1325  {
1326  UINT newmask = pTreeView->itemNew.mask & ~TVIF_CHILDREN;
1327  ok(newmask ==
1329  "got wrong mask %x\n", pTreeView->itemNew.mask);
1330  ok(pTreeView->itemOld.mask == 0,
1331  "got wrong mask %x\n", pTreeView->itemOld.mask);
1332 
1333  if (g_get_from_expand)
1334  {
1338  ok(ret == TRUE, "got %lu\n", ret);
1339  }
1340  break;
1341  }
1342  case TVN_ITEMEXPANDEDA:
1343  ok(pTreeView->itemNew.mask & TVIF_STATE, "got wrong mask %x\n", pTreeView->itemNew.mask);
1345  "got wrong mask %x\n", pTreeView->itemNew.mask);
1346  ok(pTreeView->itemOld.mask == 0,
1347  "got wrong mask %x\n", pTreeView->itemOld.mask);
1348 
1349  if (g_get_from_expand)
1350  {
1354  ok(ret == TRUE, "got %lu\n", ret);
1355  }
1357  {
1358  visibleItem = (HTREEITEM)SendMessageA(pHdr->hwndFrom, TVM_GETNEXTITEM,
1359  TVGN_FIRSTVISIBLE, 0);
1360  ok(pTreeView->itemNew.hItem == visibleItem, "expanded item == first visible item\n");
1361  *(HTREEITEM*)&rect = visibleItem;
1363  "Failed to get rect for first visible item.\n");
1364  visibleItem = (HTREEITEM)SendMessageA(pHdr->hwndFrom, TVM_GETNEXTITEM,
1365  TVGN_NEXTVISIBLE, (LPARAM)visibleItem);
1366  *(HTREEITEM*)&rect = visibleItem;
1367  ok(visibleItem != NULL, "There must be a visible item after the first visisble item.\n");
1369  "Failed to get rect for second visible item.\n");
1370  }
1371  break;
1372  case TVN_DELETEITEMA:
1373  {
1374  struct message item;
1375 
1376  ok(pTreeView->itemNew.mask == 0, "got wrong mask 0x%x\n", pTreeView->itemNew.mask);
1377 
1378  ok(pTreeView->itemOld.mask == (TVIF_HANDLE | TVIF_PARAM), "got wrong mask 0x%x\n", pTreeView->itemOld.mask);
1379  ok(pTreeView->itemOld.hItem != NULL, "got %p\n", pTreeView->itemOld.hItem);
1380 
1381  memset(&item, 0, sizeof(item));
1382  item.lParam = (LPARAM)pTreeView->itemOld.hItem;
1384 
1385  break;
1386  }
1387  case NM_CUSTOMDRAW:
1388  {
1390  COLORREF c0ffee = RGB(0xc0,0xff,0xee), cafe = RGB(0xca,0xfe,0x00);
1391  COLORREF text = GetTextColor(nmcd->nmcd.hdc), bkgnd = GetBkColor(nmcd->nmcd.hdc);
1392 
1393  msg.flags |= custdraw;
1394  msg.stage = nmcd->nmcd.dwDrawStage;
1396 
1397  switch (msg.stage)
1398  {
1399  case CDDS_PREPAINT:
1401  case CDDS_ITEMPREPAINT:
1402  ok(text == nmcd->clrText || (g_v6 && nmcd->clrText == 0xffffffff),
1403  "got %08x vs %08x\n", text, nmcd->clrText);
1404  ok(bkgnd == nmcd->clrTextBk || (g_v6 && nmcd->clrTextBk == 0xffffffff),
1405  "got %08x vs %08x\n", bkgnd, nmcd->clrTextBk);
1406  nmcd->clrText = cafe;
1407  nmcd->clrTextBk = c0ffee;
1408  SetTextColor(nmcd->nmcd.hdc, c0ffee);
1409  SetBkColor(nmcd->nmcd.hdc, cafe);
1410  if (g_customdraw_font)
1413  case CDDS_ITEMPOSTPAINT:
1414  /* at the point of post paint notification colors are already restored */
1415  ok(nmcd->clrText == cafe, "got 0%x\n", nmcd->clrText);
1416  ok(nmcd->clrTextBk == c0ffee, "got 0%x\n", nmcd->clrTextBk);
1417  ok(text != cafe, "got 0%x\n", text);
1418  ok(bkgnd != c0ffee, "got 0%x\n", bkgnd);
1419  if (g_customdraw_font)
1420  ok(GetCurrentObject(nmcd->nmcd.hdc, OBJ_FONT) != g_customdraw_font, "got %p\n",
1421  GetCurrentObject(nmcd->nmcd.hdc, OBJ_FONT));
1422  break;
1423  default:
1424  ;
1425  }
1426  break;
1427  }
1428  case NM_RCLICK:
1429  {
1432  ok(selected == hChild, "child item should still be selected\n");
1433  break;
1434  }
1435  }
1436  }
1437  break;
1438  }
1439 
1440  }
1441 
1442  defwndproc_counter++;
1444  defwndproc_counter--;
1445 
1446  return ret;
1447 }
1448 
1449 static void test_expandinvisible(void)
1450 {
1451  static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"};
1452  TVINSERTSTRUCTA ins;
1453  HTREEITEM node[5];
1454  RECT dummyRect;
1455  BOOL nodeVisible;
1456  LRESULT ret;
1457  HWND hTree;
1458 
1460 
1461  /* The test builds the following tree and expands node 1, while node 0 is collapsed.
1462  *
1463  * 0
1464  * |- 1
1465  * | |- 2
1466  * | |- 3
1467  * |- 4
1468  *
1469  */
1470 
1472  ok(ret == TRUE, "ret\n");
1473  ins.hParent = TVI_ROOT;
1474  ins.hInsertAfter = TVI_ROOT;
1475  U(ins).item.mask = TVIF_TEXT;
1476  U(ins).item.pszText = nodeText[0];
1477  node[0] = TreeView_InsertItemA(hTree, &ins);
1478  ok(node[0] != NULL, "failed to set node[0]\n");
1479 
1480  ins.hInsertAfter = TVI_LAST;
1481  U(ins).item.mask = TVIF_TEXT;
1482  ins.hParent = node[0];
1483 
1484  U(ins).item.pszText = nodeText[1];
1485  node[1] = TreeView_InsertItemA(hTree, &ins);
1486  ok(node[1] != NULL, "failed to set node[1]\n");
1487  U(ins).item.pszText = nodeText[4];
1488  node[4] = TreeView_InsertItemA(hTree, &ins);
1489  ok(node[4] != NULL, "failed to set node[4]\n");
1490 
1491  ins.hParent = node[1];
1492 
1493  U(ins).item.pszText = nodeText[2];
1494  node[2] = TreeView_InsertItemA(hTree, &ins);
1495  ok(node[2] != NULL, "failed to set node[2]\n");
1496  U(ins).item.pszText = nodeText[3];
1497  node[3] = TreeView_InsertItemA(hTree, &ins);
1498  ok(node[3] != NULL, "failed to set node[3]\n");
1499 
1500  *(HTREEITEM *)&dummyRect = node[1];
1501  nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1502  ok(!nodeVisible, "Node 1 should not be visible.\n");
1503  *(HTREEITEM *)&dummyRect = node[2];
1504  nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1505  ok(!nodeVisible, "Node 2 should not be visible.\n");
1506  *(HTREEITEM *)&dummyRect = node[3];
1507  nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1508  ok(!nodeVisible, "Node 3 should not be visible.\n");
1509  *(HTREEITEM *)&dummyRect = node[4];
1510  nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1511  ok(!nodeVisible, "Node 4 should not be visible.\n");
1512 
1513  ok(SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)node[1]), "Expand of node 1 failed.\n");
1514 
1515  *(HTREEITEM *)&dummyRect = node[1];
1516  nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1517  ok(!nodeVisible, "Node 1 should not be visible.\n");
1518  *(HTREEITEM *)&dummyRect = node[2];
1519  nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1520  ok(!nodeVisible, "Node 2 should not be visible.\n");
1521  *(HTREEITEM *)&dummyRect = node[3];
1522  nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1523  ok(!nodeVisible, "Node 3 should not be visible.\n");
1524  *(HTREEITEM *)&dummyRect = node[4];
1525  nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1526  ok(!nodeVisible, "Node 4 should not be visible.\n");
1527 
1529 }
1530 
1531 static void test_expand(void)
1532 {
1533  HTREEITEM first, second, last, child;
1534  TVINSERTSTRUCTA ins;
1535  BOOL visible;
1536  RECT rect;
1537  HWND tv;
1538  int i;
1539 
1540  tv = create_treeview_control(0);
1541 
1542  ins.hParent = TVI_ROOT;
1543  ins.hInsertAfter = TVI_LAST;
1544  U(ins).item.mask = 0;
1545  first = TreeView_InsertItemA(tv, &ins);
1546  ok(first != NULL, "failed to insert first node\n");
1547  second = TreeView_InsertItemA(tv, &ins);
1548  ok(second != NULL, "failed to insert second node\n");
1549  for (i=0; i<100; i++)
1550  {
1551  last = TreeView_InsertItemA(tv, &ins);
1552  ok(last != NULL, "failed to insert %d node\n", i);
1553  }
1554 
1555  ins.hParent = second;
1556  child = TreeView_InsertItemA(tv, &ins);
1557  ok(child != NULL, "failed to insert child node\n");
1558 
1559  ok(SendMessageA(tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)last), "last node selection failed\n");
1560  ok(SendMessageA(tv, TVM_EXPAND, TVE_EXPAND, (LPARAM)second), "expand of second node failed\n");
1561  ok(SendMessageA(tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)first), "first node selection failed\n");
1562 
1563  *(HTREEITEM *)&rect = first;
1564  visible = SendMessageA(tv, TVM_GETITEMRECT, FALSE, (LPARAM)&rect);
1565  ok(visible, "first node should be visible\n");
1566  ok(!rect.left, "rect.left = %d\n", rect.left);
1567  ok(!rect.top, "rect.top = %d\n", rect.top);
1568  ok(rect.right, "rect.right = 0\n");
1569  ok(rect.bottom, "rect.bottom = 0\n");
1570 
1571  DestroyWindow(tv);
1572 }
1573 
1574 static void test_itemedit(void)
1575 {
1576  DWORD r;
1577  HWND edit;
1578  TVITEMA item;
1579  CHAR buffA[20];
1580  HWND hTree;
1581 
1583  fill_tree(hTree);
1584 
1585  /* try with null item */
1586  edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, 0);
1587  ok(!IsWindow(edit), "Expected valid handle\n");
1588 
1589  /* trigger edit */
1591  ok(IsWindow(edit), "Expected valid handle\n");
1592  /* item shouldn't be selected automatically after TVM_EDITLABELA */
1594  expect(0, r);
1595  /* try to cancel with wrong edit handle */
1597  expect(0, r);
1598  ok(IsWindow(edit), "Expected edit control to be valid\n");
1600  expect(0, r);
1601  ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1602  /* try to cancel without creating edit */
1604  expect(0, r);
1605 
1606  /* try to cancel with wrong (not null) handle */
1608  ok(IsWindow(edit), "Expected valid handle\n");
1610  expect(0, r);
1611  ok(IsWindow(edit), "Expected edit control to be valid\n");
1613  expect(0, r);
1614 
1615  /* remove selection after starting edit */
1617  expect(TRUE, r);
1619  ok(IsWindow(edit), "Expected valid handle\n");
1621  expect(TRUE, r);
1622  /* alter text */
1623  strcpy(buffA, "x");
1624  r = SendMessageA(edit, WM_SETTEXT, 0, (LPARAM)buffA);
1625  expect(TRUE, r);
1627  expect(0, r);
1628  ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1629  /* check that text is saved */
1630  item.mask = TVIF_TEXT;
1631  item.hItem = hRoot;
1632  item.pszText = buffA;
1633  item.cchTextMax = ARRAY_SIZE(buffA);
1635  expect(TRUE, r);
1636  ok(!strcmp("x", buffA), "Expected item text to change\n");
1637 
1638  /* try A/W messages */
1640  ok(IsWindow(edit), "Expected valid handle\n");
1641  ok(IsWindowUnicode(edit), "got ansi window\n");
1643  expect(0, r);
1644  ok(!IsWindow(edit), "expected invalid handle\n");
1645 
1647  ok(IsWindow(edit), "Expected valid handle\n");
1648  ok(IsWindowUnicode(edit), "got ansi window\n");
1650  expect(0, r);
1651 
1652  /* alter text during TVM_BEGINLABELEDIT, check that it's preserved */
1653  strcpy(buffA, "<root>");
1654 
1655  item.mask = TVIF_TEXT;
1656  item.hItem = hRoot;
1657  item.pszText = buffA;
1658  item.cchTextMax = 0;
1660  expect(TRUE, r);
1661 
1664  ok(IsWindow(edit), "Expected valid handle\n");
1666 
1667  GetWindowTextA(edit, buffA, ARRAY_SIZE(buffA));
1668  ok(!strcmp(buffA, "<edittextaltered>"), "got string %s\n", buffA);
1669 
1671 }
1672 
1673 static void test_treeview_classinfo(void)
1674 {
1675  WNDCLASSA cls;
1676 
1677  memset(&cls, 0, sizeof(cls));
1678  GetClassInfoA(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls);
1679  ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground);
1680  ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style);
1681  expect(0, cls.cbClsExtra);
1682 }
1683 
1684 static void test_get_linecolor(void)
1685 {
1686  COLORREF clr;
1687  HWND hTree;
1688 
1690 
1691  /* newly created control has default color */
1692  clr = SendMessageA(hTree, TVM_GETLINECOLOR, 0, 0);
1693  if (clr == 0)
1694  win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n");
1695  else
1696  expect(CLR_DEFAULT, clr);
1697 
1699 }
1700 
1701 static void test_get_insertmarkcolor(void)
1702 {
1703  COLORREF clr;
1704  HWND hTree;
1705 
1707 
1708  /* newly created control has default color */
1710  if (clr == 0)
1711  win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n");
1712  else
1713  expect(CLR_DEFAULT, clr);
1714 
1716 }
1717 
1718 static void test_expandnotify(void)
1719 {
1720  HTREEITEM hitem;
1721  HWND hTree;
1722  BOOL ret;
1723  TVITEMA item;
1724 
1726  fill_tree(hTree);
1727 
1728  item.hItem = hRoot;
1729  item.mask = TVIF_STATE;
1730 
1731  item.state = TVIS_EXPANDED;
1733  expect(TRUE, ret);
1734  ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1735 
1736  /* preselect root node here */
1738  expect(TRUE, ret);
1739 
1742  expect(FALSE, ret);
1743  ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "no collapse notifications", FALSE);
1744 
1746  /* expand */
1748  g_item_expanding.state = 0xdeadbeef;
1749  g_item_expanded.state = 0xdeadbeef;
1751  expect(TRUE, ret);
1752  ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1754  ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1756  ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "expand notifications", FALSE);
1758 
1759  /* check that it's expanded */
1760  item.state = TVIS_EXPANDED;
1762  expect(TRUE, ret);
1763  ok((item.state & TVIS_EXPANDED) == TVIS_EXPANDED, "expected expanded\n");
1764 
1765  /* collapse */
1768  expect(TRUE, ret);
1769  item.state = TVIS_EXPANDED;
1771  expect(TRUE, ret);
1772  ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1773  /* all further collapse/expand attempts won't produce any notifications,
1774  the only way is to reset with all children removed */
1775  ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "collapse after expand notifications", FALSE);
1776 
1777  /* try to toggle child that doesn't have children itself */
1780  expect(FALSE, ret);
1781  ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "toggle node without children", FALSE);
1782 
1784 
1785  /* test TVM_GETITEMRECT inside TVN_ITEMEXPANDED notification */
1787  fill_tree(hTree);
1790  expect(TRUE, ret);
1792 
1794 
1795  /* TVE_TOGGLE acts as any other TVM_EXPAND */
1797  fill_tree(hTree);
1798 
1801  expect(TRUE, ret);
1802  ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "toggle node (expand)", FALSE);
1803 
1804  /* toggle again - no notifications */
1807  expect(TRUE, ret);
1808  ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "toggle node (collapse)", FALSE);
1809 
1811 
1812  /* some keyboard events are also translated to expand */
1814  fill_tree(hTree);
1815 
1816  /* preselect root node here */
1818  expect(TRUE, ret);
1819 
1823  expect(FALSE, ret);
1825  ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1827  ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1829 
1832  expect(FALSE, ret);
1834  ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1836  ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1838 
1841  expect(FALSE, ret);
1843  ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1845  ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1847 
1850  expect(FALSE, ret);
1852  ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1855 
1858  expect(FALSE, ret);
1860 
1861  /* go to child */
1863  expect(FALSE, ret);
1864 
1865  /* try to expand child that doesn't have children itself */
1868  expect(FALSE, ret);
1869  ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_empty_kb_seq, "expand node with no children", FALSE);
1870 
1871  /* stay on current selection and set non-zero children count */
1873  ok(hitem != NULL, "got %p\n", hitem);
1874 
1875  item.hItem = hitem;
1876  item.mask = TVIF_CHILDREN;
1877  item.cChildren = 0x80000000;
1878 
1880  expect(TRUE, ret);
1881 
1884  expect(FALSE, ret);
1885  ok_sequence(sequences, PARENT_SEQ_INDEX, parent_collapse_2nd_kb_seq, "expand node with children", FALSE);
1886 
1888 }
1889 
1890 static void test_expandedimage(void)
1891 {
1892  TVITEMEXA item;
1893  HWND hTree;
1894  BOOL ret;
1895 
1897  fill_tree(hTree);
1898 
1899  item.mask = TVIF_EXPANDEDIMAGE;
1900  item.iExpandedImage = 1;
1901  item.hItem = hRoot;
1903  ok(ret, "got %d\n", ret);
1904 
1905  item.mask = TVIF_EXPANDEDIMAGE;
1906  item.iExpandedImage = -1;
1907  item.hItem = hRoot;
1909  ok(ret, "got %d\n", ret);
1910 
1911  if (item.iExpandedImage != 1)
1912  {
1913  win_skip("TVIF_EXPANDEDIMAGE not supported\n");
1915  return;
1916  }
1917 
1918  /* test for default iExpandedImage value */
1919  item.mask = TVIF_EXPANDEDIMAGE;
1920  item.iExpandedImage = -1;
1921  item.hItem = hChild;
1923  ok(ret, "got %d\n", ret);
1924  ok(item.iExpandedImage == (WORD)I_IMAGENONE, "got %d\n", item.iExpandedImage);
1925 
1927 }
1928 
1929 static void test_TVS_SINGLEEXPAND(void)
1930 {
1931  HWND hTree;
1932  HTREEITEM alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india, juliet;
1933  TVINSERTSTRUCTA ins;
1934  char foo[] = "foo";
1935  char context[32];
1936  int i;
1937  BOOL ret;
1938 
1939  /* build a fairly complex tree
1940  * - TVI_ROOT
1941  * - alpha
1942  * - bravo
1943  * - charlie
1944  * - delta
1945  * - echo
1946  * - foxtrot
1947  * - golf
1948  * - hotel
1949  * - india
1950  * - juliet
1951  */
1952  struct
1953  {
1954  HTREEITEM *handle;
1955  HTREEITEM *parent;
1956  UINT final_state;
1957  }
1958  items[] =
1959  {
1960  { &alpha, NULL, TVIS_EXPANDEDONCE },
1961  { &bravo, &alpha, TVIS_EXPANDEDONCE },
1962  { &charlie, &bravo, 0 },
1963  { &delta, &alpha, TVIS_EXPANDEDONCE },
1964  { &echo, &delta, 0 },
1965  { &foxtrot, NULL, TVIS_EXPANDEDONCE|TVIS_EXPANDED },
1966  { &golf, &foxtrot, TVIS_EXPANDEDONCE|TVIS_EXPANDED },
1967  { &hotel, &golf, 0 },
1968  { &india, &golf, TVIS_SELECTED },
1969  { &juliet, &foxtrot, 0 }
1970  };
1971 
1972  struct
1973  {
1974  HTREEITEM *select;
1975  const struct message *sequence;
1976  }
1977  sequence_tests[] =
1978  {
1980  { &bravo, parent_singleexpand_seq1 },
1981  { &delta, parent_singleexpand_seq2 },
1982  { &foxtrot, parent_singleexpand_seq3 },
1984  { &golf, parent_singleexpand_seq5 },
1985  { &hotel, parent_singleexpand_seq6 },
1986  { &india, parent_singleexpand_seq7 },
1987  { &india, empty_seq }
1988  };
1989 
1992  /* to avoid painting related notifications */
1994  for (i = 0; i < ARRAY_SIZE(items); i++)
1995  {
1996  ins.hParent = items[i].parent ? *items[i].parent : TVI_ROOT;
1997  ins.hInsertAfter = TVI_FIRST;
1998  U(ins).item.mask = TVIF_TEXT;
1999  U(ins).item.pszText = foo;
2000  *items[i].handle = TreeView_InsertItemA(hTree, &ins);
2001  }
2002 
2003  for (i = 0; i < ARRAY_SIZE(sequence_tests); i++)
2004  {
2006  ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)(*sequence_tests[i].select));
2007  ok(ret, "got %d\n", ret);
2008  sprintf(context, "singleexpand notifications %d", i);
2010  }
2011 
2012  for (i = 0; i < ARRAY_SIZE(items); i++)
2013  {
2015  ok(ret == items[i].final_state, "singleexpand items[%d]: expected state 0x%x got 0x%x\n",
2016  i, items[i].final_state, ret);
2017  }
2018 
2019  /* a workaround for NT4 that sends expand notifications when nothing is about to expand */
2021  ok(ret, "got %d\n", ret);
2022  fill_tree(hTree);
2024  ok(ret, "got %d\n", ret);
2025 
2027 }
2028 
2029 static void test_WM_PAINT(void)
2030 {
2031  HWND hTree;
2032  COLORREF clr;
2033  LONG ret;
2034  RECT rc;
2035  HDC hdc;
2036 
2038 
2039  clr = SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(255, 0, 0));
2040  ok(clr == ~0u, "got %d, expected -1\n", clr);
2041 
2042  hdc = GetDC(hMainWnd);
2043 
2044  GetClientRect(hMainWnd, &rc);
2046 
2047  clr = GetPixel(hdc, 1, 1);
2048  ok(clr == RGB(0, 0, 0), "got 0x%x\n", clr);
2049 
2051  ok(ret == 0, "got %d\n", ret);
2052 
2053  clr = GetPixel(hdc, 1, 1);
2054  ok(clr == RGB(255, 0, 0) || broken(clr == RGB(0, 0, 0)) /* win98 */,
2055  "got 0x%x\n", clr);
2056 
2058 
2060 }
2061 
2062 static void test_delete_items(void)
2063 {
2064  const struct message *msg;
2065  HWND hTree;
2066  HTREEITEM hItem1, hItem2;
2067  TVINSERTSTRUCTA ins;
2068  INT ret;
2069 
2070  static CHAR item1[] = "Item 1";
2071  static CHAR item2[] = "Item 2";
2072 
2074  fill_tree(hTree);
2075 
2076  /* check delete order */
2079  ok(ret == TRUE, "got %d\n", ret);
2080 
2081  msg = item_sequence[0]->sequence;
2082  ok(item_sequence[0]->count == 2, "expected 2 items, got %d\n", item_sequence[0]->count);
2083 
2084  if (item_sequence[0]->count == 2)
2085  {
2086  ok(msg[0].lParam == (LPARAM)hChild, "expected %p, got 0x%lx\n", hChild, msg[0].lParam);
2087  ok(msg[1].lParam == (LPARAM)hRoot, "expected %p, got 0x%lx\n", hRoot, msg[1].lParam);
2088  }
2089 
2090  ret = SendMessageA(hTree, TVM_GETCOUNT, 0, 0);
2091  ok(ret == 0, "got %d\n", ret);
2092 
2094 
2095  /* Regression test for a crash when deleting the first visible item while bRedraw == false. */
2097 
2099  ok(ret == 0, "got %d\n", ret);
2100 
2101  ins.hParent = TVI_ROOT;
2102  ins.hInsertAfter = TVI_ROOT;
2103  U(ins).item.mask = TVIF_TEXT;
2104  U(ins).item.pszText = item1;
2105  hItem1 = TreeView_InsertItemA(hTree, &ins);
2106  ok(hItem1 != NULL, "InsertItem failed\n");
2107 
2108  ins.hParent = TVI_ROOT;
2109  ins.hInsertAfter = hItem1;
2110  U(ins).item.mask = TVIF_TEXT;
2111  U(ins).item.pszText = item2;
2112  hItem2 = TreeView_InsertItemA(hTree, &ins);
2113  ok(hItem2 != NULL, "InsertItem failed\n");
2114 
2115  ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hItem1);
2116  ok(ret == TRUE, "got %d\n", ret);
2117 
2119  ok(ret == 0, "got %d\n", ret);
2120 
2122 }
2123 
2124 static void test_cchildren(void)
2125 {
2126  HWND hTree;
2127  INT ret;
2128  TVITEMA item;
2129 
2131  fill_tree(hTree);
2132 
2134  expect(TRUE, ret);
2135 
2136  /* check cChildren - automatic mode */
2137  item.hItem = hRoot;
2138  item.mask = TVIF_CHILDREN;
2139 
2141  expect(TRUE, ret);
2142  expect(0, item.cChildren);
2143 
2145 
2146  /* start over */
2148  fill_tree(hTree);
2149 
2150  /* turn off automatic mode by setting cChildren explicitly */
2151  item.hItem = hRoot;
2152  item.mask = TVIF_CHILDREN;
2153 
2155  expect(TRUE, ret);
2156  expect(1, item.cChildren);
2157 
2159  expect(TRUE, ret);
2160 
2162  expect(TRUE, ret);
2163 
2164  /* check cChildren */
2166  expect(TRUE, ret);
2167 todo_wine
2168  expect(1, item.cChildren);
2169 
2171 }
2172 
2174 {
2175  HTREEITEM parent; /* for root value of parent field is unidetified */
2178  void *unk[2];
2182 };
2183 
2185 {
2186  HTREEITEM parent; /* for root value of parent field is unidetified */
2189  void *unk[3];
2193 };
2194 
2195 static void _check_item(HWND hwnd, HTREEITEM item, BOOL is_version_6, int line)
2196 {
2197  struct _ITEM_DATA *data = (struct _ITEM_DATA *)item;
2199  RECT rect;
2200  BOOL ret;
2201 
2206 
2207  *(HTREEITEM*)&rect = item;
2209 
2210  ok_(__FILE__, line)(item == root ? data->parent != NULL : data->parent == parent,
2211  "Unexpected parent item %p, got %p, %p\n", parent, data->parent, hwnd);
2212  ok_(__FILE__, line)(data->nextsibling == nextsibling, "Unexpected sibling %p, got %p\n",
2213  nextsibling, data->nextsibling);
2214  ok_(__FILE__, line)(data->firstchild == firstchild, "Unexpected first child %p, got %p\n",
2215  firstchild, data->firstchild);
2216  if (ret)
2217  {
2218  WORD width;
2219 
2220  if (is_version_6)
2221  {
2222  struct _ITEM_DATA_V6 *data_v6 = (struct _ITEM_DATA_V6 *)item;
2223  width = data_v6->width;
2224  }
2225  else
2226  width = data->width;
2227  todo_wine
2228  ok_(__FILE__, line)(width == (rect.right - rect.left) || broken(is_version_6 && width == 0) /* XP */,
2229  "Width %d, rect width %d.\n", width, rect.right - rect.left);
2230  }
2231 }
2232 
2233 #define CHECK_ITEM(a, b) _check_item(a, b, is_version_6, __LINE__)
2234 
2235 static void test_htreeitem_layout(BOOL is_version_6)
2236 {
2237  TVINSERTSTRUCTA ins;
2239  HWND hTree;
2240 
2242  fill_tree(hTree);
2243 
2244  /* root has some special pointer in parent field */
2247 
2248  ins.hParent = hChild;
2249  ins.hInsertAfter = TVI_FIRST;
2250  U(ins).item.mask = 0;
2251  item1 = TreeView_InsertItemA(hTree, &ins);
2252 
2254 
2255  ins.hParent = hRoot;
2256  ins.hInsertAfter = TVI_FIRST;
2257  U(ins).item.mask = 0;
2258  item2 = TreeView_InsertItemA(hTree, &ins);
2259 
2261 
2263 
2264  /* without children now */
2266 
2268 }
2269 
2270 static void test_TVS_CHECKBOXES(void)
2271 {
2272  HIMAGELIST himl, himl2;
2273  HWND hTree, hTree2;
2274  TVITEMA item;
2275  DWORD ret;
2276  MSG msg;
2277 
2279  fill_tree(hTree);
2280 
2282  ok(himl == NULL, "got %p\n", himl);
2283 
2284  item.hItem = hRoot;
2285  item.mask = TVIF_STATE;
2286  item.state = INDEXTOSTATEIMAGEMASK(1);
2287  item.stateMask = TVIS_STATEIMAGEMASK;
2289  expect(TRUE, ret);
2290  ok(item.state == 0, "got 0x%x\n", item.state);
2291 
2292  /* set some index for a child */
2293  item.hItem = hChild;
2294  item.mask = TVIF_STATE;
2295  item.state = INDEXTOSTATEIMAGEMASK(4);
2296  item.stateMask = TVIS_STATEIMAGEMASK;
2298  expect(TRUE, ret);
2299 
2300  /* enabling check boxes set all items to 1 state image index */
2303  ok(himl != NULL, "got %p\n", himl);
2304 
2306  ok(himl2 != NULL, "got %p\n", himl2);
2307  ok(himl2 == himl, "got %p, expected %p\n", himl2, himl);
2308 
2309  item.hItem = hRoot;
2310  item.mask = TVIF_STATE;
2311  item.state = 0;
2312  item.stateMask = TVIS_STATEIMAGEMASK;
2314  expect(TRUE, ret);
2315  ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2316 
2317  item.hItem = hChild;
2318  item.mask = TVIF_STATE;
2319  item.state = 0;
2320  item.stateMask = TVIS_STATEIMAGEMASK;
2322  expect(TRUE, ret);
2323  ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2324 
2325  /* create another control and check its checkbox list */
2326  hTree2 = create_treeview_control(0);
2327  fill_tree(hTree2);
2328 
2329  /* set some index for a child */
2330  item.hItem = hChild;
2331  item.mask = TVIF_STATE;
2332  item.state = INDEXTOSTATEIMAGEMASK(4);
2333  item.stateMask = TVIS_STATEIMAGEMASK;
2334  ret = SendMessageA(hTree2, TVM_SETITEMA, 0, (LPARAM)&item);
2335  expect(TRUE, ret);
2336 
2337  /* enabling check boxes set all items to 1 state image index */
2339  himl2 = (HIMAGELIST)SendMessageA(hTree2, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2340  ok(himl2 != NULL, "got %p\n", himl2);
2341  ok(himl != himl2, "got %p, expected %p\n", himl2, himl);
2342 
2343  DestroyWindow(hTree2);
2345 
2346  /* the same, but initially created with TVS_CHECKBOXES */
2348  fill_tree(hTree);
2350  ok(himl == NULL, "got %p\n", himl);
2351 
2352  item.hItem = hRoot;
2353  item.mask = TVIF_STATE;
2354  item.state = 0;
2355  item.stateMask = TVIS_STATEIMAGEMASK;
2357  expect(TRUE, ret);
2358  ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2359 
2360  item.hItem = hChild;
2361  item.mask = TVIF_STATE;
2362  item.state = 0;
2363  item.stateMask = TVIS_STATEIMAGEMASK;
2365  expect(TRUE, ret);
2366  ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2367 
2368  item.hItem = hChild;
2369  item.mask = TVIF_STATE;
2370  item.state = INDEXTOSTATEIMAGEMASK(2);
2371  item.stateMask = TVIS_STATEIMAGEMASK;
2373  expect(TRUE, ret);
2374 
2375  item.hItem = hChild;
2376  item.mask = TVIF_STATE;
2377  item.state = 0;
2379  expect(TRUE, ret);
2380  ok(item.state == INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item.state);
2381 
2382  while(GetMessageA(&msg, 0, 0, 0))
2383  {
2386 
2387  if((msg.hwnd == hTree) && (msg.message == WM_PAINT))
2388  break;
2389  }
2390 
2391  item.hItem = hChild;
2392  item.mask = TVIF_STATE;
2393  item.state = 0;
2395  expect(TRUE, ret);
2396  ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2397 
2399  ok(himl != NULL, "got %p\n", himl);
2400 
2402 
2403  /* check what happens if TVSIL_STATE image list is removed */
2405  fill_tree(hTree);
2407  ok(himl == NULL, "got %p\n", himl);
2408 
2411  ok(himl != NULL, "got %p\n", himl);
2412 
2414  ok(himl2 == himl, "got %p\n", himl2);
2415 
2417  ok(himl2 == NULL, "got %p\n", himl2);
2418 
2419  item.hItem = hChild;
2420  item.mask = TVIF_STATE;
2421  item.state = INDEXTOSTATEIMAGEMASK(2);
2422  item.stateMask = TVIS_STATEIMAGEMASK;
2424  expect(TRUE, ret);
2425 
2426  item.hItem = hChild;
2427  item.mask = TVIF_STATE;
2428  item.state = 0;
2430  expect(TRUE, ret);
2431  ok(item.state == INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item.state);
2432 
2433  while(GetMessageA(&msg, 0, 0, 0))
2434  {
2437 
2438  if((msg.hwnd == hTree) && (msg.message == WM_PAINT))
2439  break;
2440  }
2441 
2442  item.hItem = hChild;
2443  item.mask = TVIF_STATE;
2444  item.state = 0;
2446  expect(TRUE, ret);
2447  ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2448 
2450  ok(himl != NULL, "got %p\n", himl);
2451 
2453 }
2454 
2455 static void test_TVM_GETNEXTITEM(void)
2456 {
2457  HTREEITEM item;
2458  HWND hTree;
2459 
2461  fill_tree(hTree);
2462 
2464  ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2465 
2467  ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2468 
2470  ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2471 
2473  ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2474 
2476  ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2477 
2479  ok(item == hChild, "got %p, expected %p\n", item, hChild);
2480 
2482  ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2483 
2485  ok(item == NULL, "got %p\n", item);
2486 
2488  ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2489 
2491 }
2492 
2493 static void test_TVM_HITTEST(void)
2494 {
2495  HWND hTree;
2496  LRESULT ret;
2497  RECT rc;
2498  TVHITTESTINFO ht;
2499 
2501  fill_tree(hTree);
2502 
2503  *(HTREEITEM*)&rc = hRoot;
2505  expect(TRUE, (BOOL)ret);
2506 
2507  ht.pt.x = rc.left-1;
2508  ht.pt.y = rc.top;
2509 
2511  ok((HTREEITEM)ret == hRoot, "got %p, expected %p\n", (HTREEITEM)ret, hRoot);
2512  ok(ht.hItem == hRoot, "got %p, expected %p\n", ht.hItem, hRoot);
2513  ok(ht.flags == TVHT_ONITEMBUTTON, "got %d, expected %d\n", ht.flags, TVHT_ONITEMBUTTON);
2514 
2516  expect(TRUE, (BOOL)ret);
2517 
2518  *(HTREEITEM*)&rc = hChild;
2520  expect(TRUE, (BOOL)ret);
2521 
2522  ht.pt.x = rc.left-1;
2523  ht.pt.y = rc.top;
2524 
2526  ok((HTREEITEM)ret == hChild, "got %p, expected %p\n", (HTREEITEM)ret, hChild);
2527  ok(ht.hItem == hChild, "got %p, expected %p\n", ht.hItem, hChild);
2528  /* Wine returns item button here, but this item has no button */
2529  todo_wine ok(ht.flags == TVHT_ONITEMINDENT, "got %d, expected %d\n", ht.flags, TVHT_ONITEMINDENT);
2530 
2532 }
2533 
2534 static void test_WM_GETDLGCODE(void)
2535 {
2536  DWORD code;
2537  HWND hTree;
2538 
2540 
2542  ok(code == (DLGC_WANTCHARS | DLGC_WANTARROWS), "0x%08x\n", code);
2543 
2545 }
2546 
2547 static void test_customdraw(void)
2548 {
2549  LOGFONTA lf;
2550  HWND hwnd;
2551 
2553  fill_tree(hwnd);
2555 
2556  /* create additional font, custom draw handler will select it */
2557  SystemParametersInfoA(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0);
2558  lf.lfHeight *= 2;
2562  UpdateWindow(hwnd);
2563  ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_cd_seq, "custom draw notifications", FALSE);
2566 
2568 }
2569 
2570 static void test_WM_KEYDOWN(void)
2571 {
2572  static const char *rootA = "root";
2573  TVINSERTSTRUCTA ins;
2574  HTREEITEM hRoot;
2575  HWND hwnd;
2576 
2578 
2579  ins.hParent = TVI_ROOT;
2580  ins.hInsertAfter = TVI_ROOT;
2581  U(ins).item.mask = TVIF_TEXT;
2582  U(ins).item.pszText = (char*)rootA;
2583  hRoot = TreeView_InsertItemA(hwnd, &ins);
2584  ok(hRoot != NULL, "got %p\n", hRoot);
2585 
2588  ok_sequence(sequences, PARENT_SEQ_INDEX, parent_vk_return_seq, "WM_KEYDOWN/VK_RETURN parent notification", TRUE);
2589 
2591 }
2592 
2593 static void test_TVS_FULLROWSELECT(void)
2594 {
2595  DWORD style;
2596  HWND hwnd;
2597 
2598  /* try to create both with TVS_HASLINES and TVS_FULLROWSELECT */
2600 
2602  ok((style & (TVS_FULLROWSELECT | TVS_HASLINES)) == (TVS_FULLROWSELECT | TVS_HASLINES), "got style 0x%08x\n", style);
2603 
2605 
2606  /* create just with TVS_HASLINES, try to enable TVS_FULLROWSELECT later */
2608 
2612  ok(style & TVS_FULLROWSELECT, "got style 0x%08x\n", style);
2613 
2615 }
2616 
2618 {
2619  TVITEMA tvitem = { 0 };
2620  HTREEITEM child;
2621  char name[16];
2622 
2623  if (!item)
2624  {
2626  str[0] = 0;
2627  }
2628 
2630 
2631  tvitem.mask = TVIF_TEXT;
2632  tvitem.hItem = item;
2633  tvitem.pszText = name;
2634  tvitem.cchTextMax = sizeof(name);
2635  SendMessageA(hwnd, TVM_GETITEMA, 0, (LPARAM)&tvitem);
2636  strcat(str, tvitem.pszText);
2637 
2638  while (child != NULL)
2639  {
2642  }
2643 }
2644 
2646 {
2647  static const char *itemnames[] =
2648  {
2649  "root", "Wasp", "Caribou", "Vacuum",
2650  "Ocelot", "Newspaper", "Litter bin"
2651  };
2652 
2653  HTREEITEM root, children[2];
2654  TVINSERTSTRUCTA ins;
2655  unsigned i = 0;
2656 
2658 
2659  /* root, two children, with two children each */
2660  ins.hParent = TVI_ROOT;
2661  ins.hInsertAfter = TVI_ROOT;
2662  U(ins).item.mask = TVIF_TEXT;
2663  U(ins).item.pszText = (char *)itemnames[i++];
2665 
2666  ins.hParent = root;
2667  ins.hInsertAfter = TVI_LAST;
2668  U(ins).item.mask = TVIF_TEXT;
2669  U(ins).item.pszText = (char *)itemnames[i++];
2670  children[0] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2671 
2672  U(ins).item.pszText = (char *)itemnames[i++];
2673  children[1] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2674 
2675  ins.hParent = children[0];
2676  U(ins).item.pszText = (char *)itemnames[i++];
2678 
2679  U(ins).item.pszText = (char *)itemnames[i++];
2681 
2682  ins.hParent = children[1];
2683  U(ins).item.pszText = (char *)itemnames[i++];
2685 
2686  U(ins).item.pszText = (char *)itemnames[i++];
2688 }
2689 
2690 static void test_TVM_SORTCHILDREN(void)
2691 {
2692  static const char *initial_order = "rootWaspVacuumOcelotCaribouNewspaperLitter bin";
2693  static const char *sorted_order = "rootCaribouNewspaperLitter binWaspVacuumOcelot";
2694  TVINSERTSTRUCTA ins;
2695  char buff[256];
2696  HTREEITEM root;
2697  HWND hwnd;
2698  BOOL ret;
2699 
2701 
2702  /* call on empty tree */
2704  ok(!ret, "Unexpected ret value %d\n", ret);
2705 
2707  ok(!ret, "Unexpected ret value %d\n", ret);
2708 
2709  /* add only root, sort from it */
2710  ins.hParent = TVI_ROOT;
2711  ins.hInsertAfter = TVI_ROOT;
2712  U(ins).item.mask = TVIF_TEXT;
2713  U(ins).item.pszText = (char *)"root";
2715  ok(root != NULL, "Expected root node\n");
2716 
2718  ok(!ret, "Unexpected ret value %d\n", ret);
2719 
2721  ok(!ret, "Unexpected ret value %d\n", ret);
2722 
2723  /* root, two children, with two children each */
2726  ok(!strcmp(buff, initial_order), "Wrong initial order %s, expected %s\n", buff, initial_order);
2727 
2728  /* with NULL item nothing is sorted */
2731 todo_wine
2732  ok(ret, "Unexpected ret value %d\n", ret);
2734  ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order);
2735 
2736  /* TVI_ROOT as item */
2739 todo_wine
2740  ok(ret, "Unexpected ret value %d\n", ret);
2742  ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order);
2743 
2744  /* zero WPARAM, item is specified */
2747  ok(root != NULL, "Failed to get root item\n");
2749  ok(ret, "Unexpected ret value %d\n", ret);
2751  ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
2752 
2753  /* non-zero WPARAM, NULL item */
2756 todo_wine
2757  ok(ret, "Unexpected ret value %d\n", ret);
2759  ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
2760 
2761  /* TVI_ROOT as item */
2764 todo_wine
2765  ok(ret, "Unexpected ret value %d\n", ret);
2767  ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
2768 
2769  /* non-zero WPARAM, item is specified */
2772  ok(root != NULL, "Failed to get root item\n");
2774  ok(ret, "Unexpected ret value %d\n", ret);
2776  ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
2777 
2778  /* case insensitive comparison */
2780 
2781  ins.hParent = TVI_ROOT;
2782  ins.hInsertAfter = TVI_ROOT;
2783  U(ins).item.mask = TVIF_TEXT;
2784  U(ins).item.pszText = (char *)"root";
2786  ok(root != NULL, "Expected root node\n");
2787 
2788  ins.hParent = root;
2789  ins.hInsertAfter = TVI_LAST;
2790  U(ins).item.pszText = (char *)"I1";
2792 
2793  ins.hParent = root;
2794  ins.hInsertAfter = TVI_LAST;
2795  U(ins).item.pszText = (char *)"i1";
2797 
2799  ok(ret, "Unexpected ret value %d\n", ret);
2801  ok(!strcmp(buff, "rootI1i1"), "Wrong sorted order %s\n", buff);
2802 
2804 }
2805 
2806 static void test_right_click(void)
2807 {
2808  HWND hTree;
2810  RECT rc;
2811  LRESULT result;
2812  POINT pt, orig_pos;
2813 
2815  fill_tree(hTree);
2816 
2820  ok(selected == hChild, "child item not selected\n");
2821 
2822  *(HTREEITEM *)&rc = hRoot;
2824  ok(result, "TVM_GETITEMRECT failed\n");
2825 
2826  flush_events();
2827 
2828  pt.x = (rc.left + rc.right) / 2;
2829  pt.y = (rc.top + rc.bottom) / 2;
2831  GetCursorPos(&orig_pos);
2832  SetCursorPos(pt.x, pt.y);
2833 
2834  flush_events();
2836 
2839 
2840  flush_events();
2841 
2843  ok_sequence(sequences, PARENT_SEQ_INDEX, parent_right_click_seq, "parent right click sequence", FALSE);
2844 
2846  ok(selected == hChild, "child item should still be selected\n");
2847 
2848  SetCursorPos(orig_pos.x, orig_pos.y);
2850 }
2851 
2852 static void init_functions(void)
2853 {
2854  HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
2855 
2856 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
2858 #undef X
2859 }
2860 
2861 START_TEST(treeview)
2862 {
2863  INITCOMMONCONTROLSEX iccex;
2864  ULONG_PTR ctx_cookie;
2865  HANDLE hCtx;
2866  WNDCLASSA wc;
2867 
2868  init_functions();
2869 
2870  iccex.dwSize = sizeof(iccex);
2871  iccex.dwICC = ICC_TREEVIEW_CLASSES;
2872  pInitCommonControlsEx(&iccex);
2873 
2876 
2877  wc.style = CS_HREDRAW | CS_VREDRAW;
2878  wc.cbClsExtra = 0;
2879  wc.cbWndExtra = 0;
2881  wc.hIcon = NULL;
2884  wc.lpszMenuName = NULL;
2885  wc.lpszClassName = "MyTestWnd";
2887  RegisterClassA(&wc);
2888 
2889  hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
2891 
2892  ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n");
2893  if (!hMainWnd) return;
2894 
2895  test_fillroot();
2896  test_select();
2897  test_getitemtext();
2898  test_focus();
2911  test_callback();
2913  test_itemedit();
2917  test_WM_PAINT();
2919  test_cchildren();
2923  test_TVM_HITTEST();
2925  test_customdraw();
2926  test_WM_KEYDOWN();
2929  test_right_click();
2930 
2931  if (!load_v6_module(&ctx_cookie, &hCtx))
2932  {
2934  return;
2935  }
2936 
2937  /* comctl32 version 6 tests start here */
2938  g_v6 = TRUE;
2939 
2940  test_fillroot();
2941  test_getitemtext();
2952  test_expand();
2953  test_itemedit();
2956  test_cchildren();
2959  test_TVM_HITTEST();
2961  test_customdraw();
2962  test_WM_KEYDOWN();
2965 
2966  unload_v6_module(ctx_cookie, hCtx);
2967 }
#define VK_SUBTRACT
Definition: winuser.h:2206
static const struct message test_right_click_seq[]
Definition: treeview.c:220
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
HGDIOBJ WINAPI GetStockObject(_In_ int)
#define TVM_GETITEMRECT
Definition: commctrl.h:3400
void * unk[2]
Definition: treeview.c:2178
#define WC_STATICA
Definition: commctrl.h:4650
#define TVM_SETSCROLLTIME
Definition: commctrl.h:3555
void * unk[3]
Definition: treeview.c:2189
static int pos
Definition: treeview.c:383
disp
Definition: i386-dis.c:3181
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
static void test_get_set_indent(void)
Definition: treeview.c:836
#define WM_IME_NOTIFY
Definition: winuser.h:1806
GLint GLint GLsizei width
Definition: gl.h:1546
COLORREF WINAPI GetBkColor(_In_ HDC)
Definition: dc.c:954
#define I_IMAGENONE
Definition: commctrl.h:2358
BOOL WINAPI TranslateMessage(_In_ const MSG *)
LRESULT WINAPI DispatchMessageA(_In_ const MSG *)
Definition: tftpd.h:59
#define TVE_TOGGLE
Definition: commctrl.h:3396
static void AddItem(char ch)
Definition: treeview.c:392
namespace GUID const ADDRINFOEXW ADDRINFOEXW struct timeval OVERLAPPED LPLOOKUPSERVICE_COMPLETION_ROUTINE HANDLE * handle
Definition: sock.c:82
static void test_treeview_classinfo(void)
Definition: treeview.c:1673
#define TRUE
Definition: types.h:120
#define MAKEWPARAM(l, h)
Definition: winuser.h:3916
#define DLGC_WANTCHARS
Definition: winuser.h:2572
static const struct message focus_seq[]
Definition: treeview.c:106
DWORD unk2[2]
Definition: treeview.c:2190
TVITEMA itemNew
Definition: commctrl.h:3602
static void test_expandedimage(void)
Definition: treeview.c:1890
HTREEITEM nextsibling
Definition: treeview.c:2187
#define TVM_ENSUREVISIBLE
Definition: commctrl.h:3516
#define TVN_GETDISPINFOA
Definition: commctrl.h:3626
static const struct message parent_singleexpand_seq3[]
Definition: treeview.c:289
int WINAPI GetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount)
Definition: window.c:1296
struct tagNMTREEVIEWA * LPNMTREEVIEWA
long y
Definition: polytest.cpp:48
#define WM_GETDLGCODE
Definition: winuser.h:1671
#define WM_CONTEXTMENU
Definition: richedit.h:64
BOOL WINAPI ClientToScreen(_In_ HWND, _Inout_ LPPOINT)
static TVITEMA g_item_expanded
Definition: treeview.c:39
static void init_functions(void)
Definition: treeview.c:2852
static void test_select(void)
Definition: treeview.c:639
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
BOOL WINAPI IsWindow(_In_opt_ HWND)
#define TVM_GETINSERTMARKCOLOR
Definition: commctrl.h:3561
#define TVM_EXPAND
Definition: commctrl.h:3391
#define TVM_SELECTITEM
Definition: commctrl.h:3450
#define TVM_SORTCHILDREN
Definition: commctrl.h:3513
#define TVIF_EXPANDEDIMAGE
Definition: commctrl.h:3251
long x
Definition: polytest.cpp:48
static void test_get_set_bkcolor(void)
Definition: treeview.c:780
static void test_WM_GETDLGCODE(void)
Definition: treeview.c:2534
#define ok_(x1, x2)
Definition: http.c:6587
#define CDRF_NOTIFYPOSTPAINT
Definition: commctrl.h:259
#define TVM_GETLINECOLOR
Definition: treelist.h:345
HDC WINAPI GetDC(_In_opt_ HWND)
#define TVM_EDITLABELA
Definition: commctrl.h:3471
#define TVM_SETINDENT
Definition: commctrl.h:3409
#define TVGN_CARET
Definition: commctrl.h:3433
UINT stateMask
Definition: commctrl.h:3278
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
POINT last
Definition: font.c:46
static void test_focus(void)
Definition: treeview.c:739
HFONT WINAPI CreateFontIndirectA(_In_ const LOGFONTA *)
static HTREEITEM hChild
Definition: treeview.c:381
#define PARENT_CD_SEQ_INDEX
Definition: treeview.c:51
#define pt(x, y)
Definition: drawing.c:79
#define TVN_DELETEITEMA
Definition: commctrl.h:3679
BOOL WINAPI PostMessageA(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
static void test_callback(void)
Definition: treeview.c:504
#define TVIS_FOCUSED
Definition: treelist.c:125
#define SW_HIDE
Definition: winuser.h:762
#define TVN_ITEMEXPANDEDA
Definition: commctrl.h:3673
static WNDPROC pOldWndProc
Definition: dateandtime.c:14
LRESULT WINAPI SendMessageA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
#define CHECK_ITEM(a, b)
Definition: treeview.c:2233
#define TVIS_SELECTED
Definition: commctrl.h:3252
const WCHAR * text
Definition: package.c:1827
#define WM_NCCALCSIZE
Definition: winuser.h:1667
GLuint GLuint GLsizei count
Definition: gl.h:1545
char CHAR
Definition: xmlstorage.h:175
struct _root root
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1827
#define WM_GETTEXT
Definition: winuser.h:1600
#define TVS_LINESATROOT
Definition: commctrl.h:3221
const GLint * first
Definition: glext.h:5794
static void test_htreeitem_layout(BOOL is_version_6)
Definition: treeview.c:2235
Definition: msg.h:39
#define U(x)
Definition: wordpad.c:44
#define MAKELPARAM(l, h)
Definition: winuser.h:3915
static BOOL g_get_from_expand
Definition: treeview.c:40
#define TVGN_NEXT
Definition: commctrl.h:3425
struct _TREEITEM * HTREEITEM
Definition: commctrl.h:3236
#define WM_CAPTURECHANGED
Definition: winuser.h:1784
GLenum GLuint GLenum GLsizei const GLchar * message
Definition: glext.h:5579
static HFONT g_customdraw_font
Definition: treeview.c:45
#define TVM_HITTEST
Definition: commctrl.h:3484
static const struct message parent_get_dispinfo_seq[]
Definition: treeview.c:345
static HDC
Definition: imagelist.c:92
#define CALLBACK
Definition: compat.h:27
#define WM_SETREDRAW
Definition: winuser.h:1598
static const struct message parent_singleexpand_seq0[]
Definition: treeview.c:257
#define TreeView_GetItemA(hwnd, pitem)
Definition: commctrl.h:88
BOOL WINAPI UpdateWindow(_In_ HWND)
HWND hWnd
Definition: settings.c:17
START_TEST(treeview)
Definition: treeview.c:2861
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:445
static void flush_events(void)
Definition: treeview.c:58
#define VK_ADD
Definition: winuser.h:2204
HANDLE HWND
Definition: compat.h:13
BOOL WINAPI GetMessageA(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT)
#define CDDS_POSTPAINT
Definition: commctrl.h:266
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1497
int cbClsExtra
Definition: winuser.h:3118
#define CDDS_ITEMPREPAINT
Definition: commctrl.h:270
#define CS_HREDRAW
Definition: winuser.h:648
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
LPCSTR lpszMenuName
Definition: winuser.h:3124
static const struct message parent_expand_kb_seq[]
Definition: treeview.c:236
static void test_cchildren(void)
Definition: treeview.c:2124
static void unload_v6_module(ULONG_PTR cookie, HANDLE hCtx)
Definition: v6util.h:63
HWND WINAPI SetFocus(_In_opt_ HWND)
static void _check_item(HWND hwnd, HTREEITEM item, BOOL is_version_6, int line)
Definition: treeview.c:2195
static const struct message parent_vk_return_seq[]
Definition: treeview.c:364
#define WM_NCHITTEST
Definition: winuser.h:1668
static const struct message test_get_set_bkcolor_seq[]
Definition: treeview.c:136
UINT_PTR WPARAM
Definition: windef.h:207
#define VK_TAB
Definition: winuser.h:2153
HBRUSH hbrBackground
Definition: winuser.h:3123
#define TVIS_EXPANDEDONCE
Definition: commctrl.h:3257
#define WS_CHILD
Definition: pedump.c:617
static BOOL(WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX *)
#define TVIF_SELECTEDIMAGE
Definition: commctrl.h:3243
__u16 time
Definition: mkdosfs.c:366
static void test_expandinvisible(void)
Definition: treeview.c:1449
BOOL WINAPI ShowWindow(_In_ HWND, _In_ int)
BOOL WINAPI PeekMessageA(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT, _In_ UINT)
#define TVGN_NEXTVISIBLE
Definition: commctrl.h:3430
static void test_get_set_imagelist(void)
Definition: treeview.c:813
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2635
#define TVM_SETBKCOLOR
Definition: commctrl.h:3547
DWORD GetPixel(LPDIRECTDRAWSURFACE7 Surface, UINT x, UINT y)
Definition: blt.cpp:2
HIMAGELIST himl
BOOL WINAPI DestroyWindow(_In_ HWND)
#define COLOR_WINDOW
Definition: winuser.h:908
int32_t INT
Definition: typedefs.h:56
#define VK_RETURN
Definition: winuser.h:2155
static HWND child
Definition: cursoricon.c:298
& rect
Definition: startmenu.cpp:1413
WPARAM wParam
Definition: combotst.c:138
#define TreeView_SetItemA(hwnd, pitem)
Definition: commctrl.h:95
#define IDC_IBEAM
Definition: winuser.h:683
LRESULT WINAPI CallWindowProcA(_In_ WNDPROC, _In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define TVS_SINGLEEXPAND
Definition: commctrl.h:3229
UINT mask
Definition: commctrl.h:3275
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define TVN_SELCHANGEDA
Definition: commctrl.h:3619
#define TVHT_ONITEMBUTTON
Definition: commctrl.h:3501
UINT code
Definition: winuser.h:3112
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:975
#define sprintf(buf, format,...)
Definition: sprintf.c:55
#define WM_NCPAINT
Definition: winuser.h:1669
static const struct message parent_singleexpand_seq5[]
Definition: treeview.c:315
static const struct message parent_singleexpand_seq1[]
Definition: treeview.c:267
int cbWndExtra
Definition: winuser.h:3119
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ICC_TREEVIEW_CLASSES
Definition: commctrl.h:59
HTREEITEM hParent
Definition: commctrl.h:3356
#define EN_KILLFOCUS
Definition: winuser.h:1986
#define EN_SETFOCUS
Definition: winuser.h:1988
static const struct message empty_seq[]
Definition: treeview.c:350
#define TVIF_CHILDREN
Definition: commctrl.h:3244
LONG WINAPI GetWindowLongA(_In_ HWND, _In_ int)
static void test_get_set_textcolor(void)
Definition: treeview.c:1037
static BOOL load_v6_module(ULONG_PTR *pcookie, HANDLE *hCtx)
Definition: v6util.h:71
#define WM_PARENTNOTIFY
Definition: winuser.h:1779
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
INT WSAAPI select(IN INT s, IN OUT LPFD_SET readfds, IN OUT LPFD_SET writefds, IN OUT LPFD_SET exceptfds, IN CONST struct timeval *timeout)
Definition: select.c:41
static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
Definition: treeview.c:1227
#define WM_SETCURSOR
Definition: winuser.h:1618
static char sequence[256]
Definition: treeview.c:384
LONG lfHeight
Definition: dimm.idl:42
static HTREEITEM hRoot
Definition: treeview.c:381
UINT_PTR idFrom
Definition: winuser.h:3111
static UINT WPARAM LPARAM lparam
Definition: combo.c:716
static char selected[MAX_PATH+1]
Definition: dirdlg.c:7
HINSTANCE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR lpLibFileName)
Definition: loader.c:111