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 "precomp.h"
22 
23 static const char *TEST_CALLBACK_TEXT = "callback_text";
24 
25 static TVITEMA g_item_expanding, g_item_expanded;
26 static BOOL g_get_from_expand;
27 static BOOL g_get_rect_in_expand;
28 static BOOL g_disp_A_to_W;
29 static BOOL g_disp_set_stateimage;
30 static BOOL g_beginedit_alter_text;
31 static HFONT g_customdraw_font;
32 static BOOL g_v6;
33 
34 #define NUM_MSG_SEQUENCES   3
35 #define TREEVIEW_SEQ_INDEX  0
36 #define PARENT_SEQ_INDEX    1
37 #define PARENT_CD_SEQ_INDEX 2
38 
39 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
40 
41 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
42 static struct msg_sequence *item_sequence[1];
43 
44 static void flush_events(void)
45 {
46     MSG msg;
47     int diff = 200;
48     int min_timeout = 100;
49     DWORD time = GetTickCount() + diff;
50 
51     while (diff > 0)
52     {
53         if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) break;
54         while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
55         diff = time - GetTickCount();
56     }
57 }
58 
59 static const struct message FillRootSeq[] = {
60     { TVM_INSERTITEMA, sent },
61     { TVM_INSERTITEMA, sent },
62     { 0 }
63 };
64 
65 static const struct message rootnone_select_seq[] = {
66     { TVM_SELECTITEM, sent|wparam, 9 },
67     { TVM_SELECTITEM, sent|wparam, 9 },
68     { TVM_SELECTITEM, sent|wparam, 9 },
69     { TVM_SELECTITEM, sent|wparam, 9 },
70     { TVM_SELECTITEM, sent|wparam, 9 },
71     { TVM_SELECTITEM, sent|wparam, 9 },
72     { 0 }
73 };
74 
75 static const struct message rootchild_select_seq[] = {
76     { TVM_SELECTITEM, sent|wparam, 9 },
77     { TVM_SELECTITEM, sent|wparam, 9 },
78     { TVM_SELECTITEM, sent|wparam, 9 },
79     { TVM_SELECTITEM, sent|wparam, 9 },
80     { TVM_SELECTITEM, sent|wparam, 9 },
81     { TVM_SELECTITEM, sent|wparam, 9 },
82     { 0 }
83 };
84 
85 static const struct message getitemtext_seq[] = {
86     { TVM_INSERTITEMA, sent },
87     { TVM_GETITEMA, sent },
88     { TVM_DELETEITEM, sent },
89     { 0 }
90 };
91 
92 static const struct message focus_seq[] = {
93     { TVM_INSERTITEMA, sent },
94     { TVM_INSERTITEMA, sent },
95     { TVM_SELECTITEM, sent|wparam, 9 },
96     /* The following end up out of order in wine */
97     { WM_WINDOWPOSCHANGING, sent|defwinproc },
98     { WM_NCCALCSIZE, sent|wparam|defwinproc, TRUE },
99     { WM_WINDOWPOSCHANGED, sent|defwinproc },
100     { WM_SIZE, sent|defwinproc },
101     { WM_WINDOWPOSCHANGING, sent|defwinproc|optional },
102     { WM_NCCALCSIZE, sent|wparam|defwinproc|optional, TRUE },
103     { WM_WINDOWPOSCHANGED, sent|defwinproc|optional },
104     { WM_SIZE, sent|defwinproc|optional },
105     { WM_PAINT, sent|defwinproc },
106     { WM_NCPAINT, sent|wparam|defwinproc, 1 },
107     { WM_ERASEBKGND, sent|defwinproc },
108     { TVM_EDITLABELA, sent },
109     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_UPDATE) },
110     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_CHANGE) },
111     { WM_PARENTNOTIFY, sent|wparam|defwinproc, MAKEWPARAM(WM_CREATE, 0) },
112     { WM_KILLFOCUS, sent|defwinproc },
113     { WM_PAINT, sent|defwinproc },
114     { WM_IME_SETCONTEXT, sent|defwinproc|optional },
115     { WM_COMMAND, sent|wparam|defwinproc, MAKEWPARAM(0, EN_SETFOCUS) },
116     { WM_ERASEBKGND, sent|defwinproc|optional },
117     { WM_CTLCOLOREDIT, sent|defwinproc|optional },
118     { WM_CTLCOLOREDIT, sent|defwinproc|optional },
119     { 0 }
120 };
121 
122 static const struct message test_get_set_bkcolor_seq[] = {
123     { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
124     { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0 },
125     { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
126     { TVM_SETBKCOLOR, sent|wparam|lparam, 0, 0x00ffffff },
127     { TVM_GETBKCOLOR, sent|wparam|lparam, 0, 0 },
128     { TVM_SETBKCOLOR, sent|wparam|lparam, 0, -1 },
129     { 0 }
130 };
131 
132 static const struct message test_get_set_imagelist_seq[] = {
133     { TVM_SETIMAGELIST, sent|wparam|lparam, 0, 0 },
134     { TVM_GETIMAGELIST, sent|wparam|lparam, 0, 0 },
135     { 0 }
136 };
137 
138 static const struct message test_get_set_indent_seq[] = {
139     { TVM_SETINDENT, sent|wparam|lparam, 0, 0 },
140     { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
141     /* The actual amount to indent is dependent on the system for this message */
142     { TVM_SETINDENT, sent },
143     { TVM_GETINDENT, sent|wparam|lparam, 0, 0 },
144     { 0 }
145 };
146 
147 static const struct message test_get_set_insertmarkcolor_seq[] = {
148     { TVM_SETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
149     { TVM_GETINSERTMARKCOLOR, sent|wparam|lparam, 0, 0 },
150     { 0 }
151 };
152 
153 static const struct message test_get_set_item_seq[] = {
154     { TVM_GETITEMA, sent },
155     { TVM_SETITEMA, sent },
156     { TVM_GETITEMA, sent },
157     { TVM_SETITEMA, sent },
158     { 0 }
159 };
160 
161 static const struct message test_get_set_itemheight_seq[] = {
162     { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
163     { TVM_SETITEMHEIGHT, sent|wparam|lparam, -1, 0 },
164     { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
165     { TVM_SETITEMHEIGHT, sent|lparam, 0xcccccccc, 0 },
166     { TVM_GETITEMHEIGHT, sent|wparam|lparam|optional, 0, 0 },
167     { TVM_SETITEMHEIGHT, sent|wparam|lparam|optional, 9, 0 },
168     { TVM_GETITEMHEIGHT, sent|wparam|lparam, 0, 0 },
169     { 0 }
170 };
171 
172 static const struct message test_get_set_scrolltime_seq[] = {
173     { TVM_SETSCROLLTIME, sent|wparam|lparam, 20, 0 },
174     { TVM_GETSCROLLTIME, sent|wparam|lparam, 0, 0 },
175     { 0 }
176 };
177 
178 static const struct message test_get_set_textcolor_seq[] = {
179     { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
180     { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
181     { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
182     { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, RGB(255, 255, 255) },
183     { TVM_GETTEXTCOLOR, sent|wparam|lparam, 0, 0 },
184     { TVM_SETTEXTCOLOR, sent|wparam|lparam, 0, CLR_NONE },
185     { 0 }
186 };
187 
188 static const struct message test_get_set_tooltips_seq[] = {
189     { WM_KILLFOCUS,    sent },
190     { WM_IME_SETCONTEXT, sent|optional },
191     { WM_IME_NOTIFY, sent|optional },
192     { TVM_SETTOOLTIPS, sent|wparam|lparam, 0, 0 },
193     { TVM_GETTOOLTIPS, sent|wparam|lparam, 0, 0 },
194     { 0 }
195 };
196 
197 static const struct message test_get_set_unicodeformat_seq[] = {
198     { TVM_SETUNICODEFORMAT, sent|wparam|lparam, TRUE, 0 },
199     { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
200     { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
201     { TVM_GETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
202     { TVM_SETUNICODEFORMAT, sent|wparam|lparam, 0, 0 },
203     { 0 }
204 };
205 
206 static const struct message test_right_click_seq[] = {
207     { WM_RBUTTONDOWN, sent|wparam, MK_RBUTTON },
208     { WM_CAPTURECHANGED, sent|defwinproc },
209     { TVM_GETNEXTITEM, sent|wparam|lparam|defwinproc, TVGN_CARET, 0 },
210     { WM_NCHITTEST, sent|optional },
211     { WM_SETCURSOR, sent|optional },
212     { WM_MOUSEMOVE, sent|optional },
213     { 0 }
214 };
215 
216 static const struct message parent_expand_seq[] = {
217     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
218     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
219     { 0 }
220 };
221 
222 static const struct message parent_expand_kb_seq[] = {
223     { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN },
224     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
225     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
226     { WM_CHANGEUISTATE, sent|optional },
227     { 0 }
228 };
229 
230 static const struct message parent_collapse_2nd_kb_seq[] = {
231     { WM_NOTIFY, sent|id|optional, 0, 0, TVN_KEYDOWN },
232     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
233     { WM_CHANGEUISTATE, sent|optional },
234     { 0 }
235 };
236 
237 static const struct message parent_expand_empty_kb_seq[] = {
238     { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN },
239     { WM_CHANGEUISTATE, sent|optional },
240     { 0 }
241 };
242 
243 static const struct message parent_singleexpand_seq0[] = {
244     /* alpha expands */
245     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
246     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
247     { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
248     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
249     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
250     { 0 }
251 };
252 
253 static const struct message parent_singleexpand_seq1[] = {
254     /* bravo expands */
255     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
256     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
257     { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
258     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
259     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
260     { 0 }
261 };
262 
263 static const struct message parent_singleexpand_seq2[] = {
264     /* delta expands, bravo collapses */
265     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
266     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
267     { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
268     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
269     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
270     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
271     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
272     { 0 }
273 };
274 
275 static const struct message parent_singleexpand_seq3[] = {
276     /* foxtrot expands, alpha and delta collapse */
277     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
278     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
279     { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
280     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
281     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
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_seq4[] = {
290     /* alpha expands, foxtrot collapses */
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     { 0 }
299 };
300 
301 static const struct message parent_singleexpand_seq5[] = {
302     /* foxtrot expands while golf is selected, then golf expands and alpha collapses */
303     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
304     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDINGA },
305     { WM_NOTIFY, sent|id, 0, 0, TVN_ITEMEXPANDEDA },
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_seq6[] = {
316     /* hotel does not expand and india does not collapse because they have no children */
317     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
318     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
319     { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
320     { 0 }
321 };
322 
323 static const struct message parent_singleexpand_seq7[] = {
324     /* india does not expand and hotel does not collapse because they have no children */
325     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGINGA },
326     { WM_NOTIFY, sent|id, 0, 0, TVN_SELCHANGEDA },
327     { WM_NOTIFY, sent|id, 0, 0, TVN_SINGLEEXPAND },
328     { 0 }
329 };
330 
331 static const struct message parent_get_dispinfo_seq[] = {
332     { WM_NOTIFY, sent|id, 0, 0, TVN_GETDISPINFOA },
333     { 0 }
334 };
335 
336 static const struct message empty_seq[] = {
337     { 0 }
338 };
339 
340 static const struct message parent_cd_seq[] = {
341     { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_PREPAINT },
342     { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
343     { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
344     { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPREPAINT },
345     { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_ITEMPOSTPAINT },
346     { WM_NOTIFY, sent|id|custdraw, 0, 0, NM_CUSTOMDRAW, CDDS_POSTPAINT },
347     { 0 }
348 };
349 
350 static const struct message parent_vk_return_seq[] = {
351     { WM_NOTIFY, sent|id, 0, 0, TVN_KEYDOWN },
352     { WM_NOTIFY, sent|id, 0, 0, NM_RETURN },
353     { WM_CHANGEUISTATE, sent|optional },
354     { 0 }
355 };
356 
357 static const struct message parent_right_click_seq[] = {
358     { WM_NOTIFY, sent|id, 0, 0, NM_RCLICK },
359     { WM_CONTEXTMENU, sent },
360     { WM_NOTIFY, sent|optional },
361     { WM_SETCURSOR, sent|optional },
362     { 0 }
363 };
364 
365 static HWND hMainWnd;
366 
367 static HTREEITEM hRoot, hChild;
368 
369 static int pos = 0;
370 static char sequence[256];
371 
372 static void Clear(void)
373 {
374     pos = 0;
375     sequence[0] = '\0';
376 }
377 
378 static void AddItem(char ch)
379 {
380     sequence[pos++] = ch;
381     sequence[pos] = '\0';
382 }
383 
384 static void IdentifyItem(HTREEITEM hItem)
385 {
386     if (hItem == hRoot) {
387         AddItem('R');
388         return;
389     }
390     if (hItem == hChild) {
391         AddItem('C');
392         return;
393     }
394     if (hItem == NULL) {
395         AddItem('n');
396         return;
397     }
398     AddItem('?');
399 }
400 
401 /* This function hooks in and records all messages to the treeview control */
402 static LRESULT WINAPI TreeviewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
403 {
404     static LONG defwndproc_counter = 0;
405     LRESULT ret;
406     WNDPROC lpOldProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
407     struct message msg = { 0 };
408 
409     msg.message = message;
410     msg.flags = sent|wparam|lparam;
411     if (defwndproc_counter) msg.flags |= defwinproc;
412     msg.wParam = wParam;
413     msg.lParam = lParam;
414     add_message(sequences, TREEVIEW_SEQ_INDEX, &msg);
415 
416     defwndproc_counter++;
417     ret = CallWindowProcA(lpOldProc, hwnd, message, wParam, lParam);
418     defwndproc_counter--;
419 
420     return ret;
421 }
422 
423 static HWND create_treeview_control(DWORD style)
424 {
425     WNDPROC pOldWndProc;
426     HWND hTree;
427 
428     hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
429             TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS|TVS_EDITLABELS|style,
430             0, 0, 120, 100, hMainWnd, (HMENU)100, GetModuleHandleA(0), 0);
431 
432     SetFocus(hTree);
433 
434     /* Record the old WNDPROC so we can call it after recording the messages */
435     pOldWndProc = (WNDPROC)SetWindowLongPtrA(hTree, GWLP_WNDPROC, (LONG_PTR)TreeviewWndProc);
436     SetWindowLongPtrA(hTree, GWLP_USERDATA, (LONG_PTR)pOldWndProc);
437 
438     return hTree;
439 }
440 
441 static void fill_tree(HWND hTree)
442 {
443     TVINSERTSTRUCTA ins;
444     static CHAR root[]  = "Root",
445                 child[] = "Child";
446 
447     ins.hParent = TVI_ROOT;
448     ins.hInsertAfter = TVI_ROOT;
449     U(ins).item.mask = TVIF_TEXT;
450     U(ins).item.pszText = root;
451     hRoot = TreeView_InsertItemA(hTree, &ins);
452 
453     ins.hParent = hRoot;
454     ins.hInsertAfter = TVI_FIRST;
455     U(ins).item.mask = TVIF_TEXT;
456     U(ins).item.pszText = child;
457     hChild = TreeView_InsertItemA(hTree, &ins);
458 }
459 
460 static void test_fillroot(void)
461 {
462     TVITEMA tvi;
463     HWND hTree;
464 
465     hTree = create_treeview_control(0);
466 
467     flush_sequences(sequences, NUM_MSG_SEQUENCES);
468 
469     fill_tree(hTree);
470 
471     Clear();
472     AddItem('A');
473     ok(hRoot != NULL, "failed to set root\n");
474     AddItem('B');
475     ok(hChild != NULL, "failed to set child\n");
476     AddItem('.');
477     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, FillRootSeq, "FillRoot", FALSE);
478     ok(!strcmp(sequence, "AB."), "Item creation\n");
479 
480     /* UMLPad 1.15 depends on this being not -1 (I_IMAGECALLBACK) */
481     tvi.hItem = hRoot;
482     tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
483     SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tvi);
484     ok(tvi.iImage == 0, "tvi.iImage=%d\n", tvi.iImage);
485     ok(tvi.iSelectedImage == 0, "tvi.iSelectedImage=%d\n", tvi.iSelectedImage);
486 
487     DestroyWindow(hTree);
488 }
489 
490 static void test_callback(void)
491 {
492     HTREEITEM hRoot;
493     HTREEITEM hItem1, hItem2;
494     TVINSERTSTRUCTA ins;
495     TVITEMA tvi;
496     CHAR test_string[] = "Test_string";
497     static const CHAR test2A[] = "TEST2";
498     CHAR buf[128];
499     HWND hTree;
500     DWORD ret;
501 
502     hTree = create_treeview_control(0);
503 
504     ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
505     expect(TRUE, ret);
506     ins.hParent = TVI_ROOT;
507     ins.hInsertAfter = TVI_ROOT;
508     U(ins).item.mask = TVIF_TEXT;
509     U(ins).item.pszText = LPSTR_TEXTCALLBACKA;
510     hRoot = TreeView_InsertItemA(hTree, &ins);
511     ok(hRoot != NULL, "failed to set root\n");
512 
513     tvi.hItem = hRoot;
514     tvi.mask = TVIF_TEXT;
515     tvi.pszText = buf;
516     tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]);
517     ret = TreeView_GetItemA(hTree, &tvi);
518     expect(TRUE, ret);
519     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n",
520         tvi.pszText, TEST_CALLBACK_TEXT);
521 
522     ins.hParent = hRoot;
523     ins.hInsertAfter = TVI_FIRST;
524     U(ins).item.mask = TVIF_TEXT;
525     U(ins).item.pszText = test_string;
526     hItem1 = TreeView_InsertItemA(hTree, &ins);
527     ok(hItem1 != NULL, "failed to set Item1\n");
528 
529     tvi.hItem = hItem1;
530     ret = TreeView_GetItemA(hTree, &tvi);
531     expect(TRUE, ret);
532     ok(strcmp(tvi.pszText, test_string) == 0, "Item text mismatch %s vs %s\n",
533         tvi.pszText, test_string);
534 
535     /* undocumented: pszText of NULL also means LPSTR_CALLBACK: */
536     tvi.pszText = NULL;
537     ret = TreeView_SetItemA(hTree, &tvi);
538     expect(TRUE, ret);
539     tvi.pszText = buf;
540     ret = TreeView_GetItemA(hTree, &tvi);
541     expect(TRUE, ret);
542     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
543         tvi.pszText, TEST_CALLBACK_TEXT);
544 
545     U(ins).item.pszText = NULL;
546     hItem2 = TreeView_InsertItemA(hTree, &ins);
547     ok(hItem2 != NULL, "failed to set Item2\n");
548     tvi.hItem = hItem2;
549     memset(buf, 0, sizeof(buf));
550     ret = TreeView_GetItemA(hTree, &tvi);
551     expect(TRUE, ret);
552     ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Item text mismatch %s vs %s\n",
553         tvi.pszText, TEST_CALLBACK_TEXT);
554 
555     /* notification handler changed A->W */
556     g_disp_A_to_W = TRUE;
557     tvi.hItem = hItem2;
558     memset(buf, 0, sizeof(buf));
559     ret = TreeView_GetItemA(hTree, &tvi);
560     expect(TRUE, ret);
561     ok(strcmp(tvi.pszText, test2A) == 0, "got %s, expected %s\n",
562         tvi.pszText, test2A);
563     g_disp_A_to_W = FALSE;
564 
565     /* handler changes state image index */
566     SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES);
567 
568     /* clear selection, handler will set selected state */
569     ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);
570     expect(TRUE, ret);
571 
572     flush_sequences(sequences, NUM_MSG_SEQUENCES);
573 
574     tvi.hItem = hRoot;
575     tvi.mask = TVIF_STATE;
576     tvi.state = TVIS_SELECTED;
577     ret = TreeView_GetItemA(hTree, &tvi);
578     expect(TRUE, ret);
579     ok(tvi.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", tvi.state);
580 
581     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq,
582                 "no TVN_GETDISPINFO for a state seq", FALSE);
583 
584     tvi.hItem     = hRoot;
585     tvi.mask      = TVIF_IMAGE | TVIF_STATE;
586     tvi.state     = TVIS_FOCUSED;
587     tvi.stateMask = TVIS_FOCUSED;
588     tvi.iImage    = I_IMAGECALLBACK;
589     ret = TreeView_SetItemA(hTree, &tvi);
590     expect(TRUE, ret);
591 
592     /* ask for item image index through callback - state is also set with state image index */
593     flush_sequences(sequences, NUM_MSG_SEQUENCES);
594 
595     tvi.hItem = hRoot;
596     tvi.mask = TVIF_IMAGE;
597     tvi.state = 0;
598     ret = TreeView_GetItemA(hTree, &tvi);
599     expect(TRUE, ret);
600     ok(tvi.state == (INDEXTOSTATEIMAGEMASK(1) | TVIS_FOCUSED), "got 0x%x\n", tvi.state);
601 
602     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_get_dispinfo_seq,
603                 "callback for state/overlay image index, noop seq", FALSE);
604 
605     /* ask for image again and overwrite state to some value in handler */
606     flush_sequences(sequences, NUM_MSG_SEQUENCES);
607 
608     g_disp_set_stateimage = TRUE;
609     tvi.hItem = hRoot;
610     tvi.mask = TVIF_IMAGE;
611     tvi.state = INDEXTOSTATEIMAGEMASK(1);
612     tvi.stateMask = 0;
613     ret = TreeView_GetItemA(hTree, &tvi);
614     expect(TRUE, ret);
615     /* handler sets TVIS_SELECTED as well */
616     ok(tvi.state == (TVIS_FOCUSED | TVIS_SELECTED | INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3)), "got 0x%x\n", tvi.state);
617     g_disp_set_stateimage = FALSE;
618 
619     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_get_dispinfo_seq,
620                 "callback for state/overlay image index seq", FALSE);
621 
622     DestroyWindow(hTree);
623 }
624 
625 static void test_select(void)
626 {
627     BOOL r;
628     HWND hTree;
629 
630     hTree = create_treeview_control(0);
631     fill_tree(hTree);
632 
633     /* root-none select tests */
634     flush_sequences(sequences, NUM_MSG_SEQUENCES);
635     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);
636     expect(TRUE, r);
637     Clear();
638     AddItem('1');
639     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
640     expect(TRUE, r);
641     AddItem('2');
642     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
643     expect(TRUE, r);
644     AddItem('3');
645     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);
646     expect(TRUE, r);
647     AddItem('4');
648     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);
649     expect(TRUE, r);
650     AddItem('5');
651     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
652     expect(TRUE, r);
653     AddItem('.');
654     ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
655     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootnone_select_seq,
656                 "root-none select seq", FALSE);
657 
658     /* root-child select tests */
659     flush_sequences(sequences, NUM_MSG_SEQUENCES);
660     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);
661     expect(TRUE, r);
662 
663     Clear();
664     AddItem('1');
665     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
666     expect(TRUE, r);
667     AddItem('2');
668     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
669     expect(TRUE, r);
670     AddItem('3');
671     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
672     expect(TRUE, r);
673     AddItem('4');
674     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
675     expect(TRUE, r);
676     AddItem('5');
677     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
678     expect(TRUE, r);
679     AddItem('.');
680     ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
681     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, rootchild_select_seq,
682                 "root-child select seq", FALSE);
683 
684     DestroyWindow(hTree);
685 }
686 
687 static void test_getitemtext(void)
688 {
689     TVINSERTSTRUCTA ins;
690     HTREEITEM hChild;
691     TVITEMA tvi;
692     HWND hTree;
693 
694     CHAR szBuffer[80] = "Blah";
695     int nBufferSize = sizeof(szBuffer)/sizeof(CHAR);
696 
697     hTree = create_treeview_control(0);
698     fill_tree(hTree);
699 
700     flush_sequences(sequences, NUM_MSG_SEQUENCES);
701 
702     /* add an item without TVIF_TEXT mask and pszText == NULL */
703     ins.hParent = hRoot;
704     ins.hInsertAfter = TVI_ROOT;
705     U(ins).item.mask = 0;
706     U(ins).item.pszText = NULL;
707     U(ins).item.cchTextMax = 0;
708     hChild = TreeView_InsertItemA(hTree, &ins);
709     ok(hChild != NULL, "failed to set hChild\n");
710 
711     /* retrieve it with TVIF_TEXT mask */
712     tvi.hItem = hChild;
713     tvi.mask = TVIF_TEXT;
714     tvi.cchTextMax = nBufferSize;
715     tvi.pszText = szBuffer;
716 
717     SendMessageA( hTree, TVM_GETITEMA, 0, (LPARAM)&tvi );
718     ok(!strcmp(szBuffer, ""), "szBuffer=\"%s\", expected \"\"\n", szBuffer);
719     ok(SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild), "DeleteItem failed\n");
720     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, getitemtext_seq, "get item text seq", FALSE);
721 
722     DestroyWindow(hTree);
723 }
724 
725 static void test_focus(void)
726 {
727     TVINSERTSTRUCTA ins;
728     static CHAR child1[]  = "Edit",
729                 child2[]  = "A really long string";
730     HTREEITEM hChild1, hChild2;
731     HWND hTree;
732     HWND hEdit;
733 
734     hTree = create_treeview_control(0);
735     fill_tree(hTree);
736 
737     flush_sequences(sequences, NUM_MSG_SEQUENCES);
738 
739     /* This test verifies that when a label is being edited, scrolling
740      * the treeview does not cause the label to lose focus. To test
741      * this, first some additional entries are added to generate
742      * scrollbars.
743      */
744     ins.hParent = hRoot;
745     ins.hInsertAfter = hChild;
746     U(ins).item.mask = TVIF_TEXT;
747     U(ins).item.pszText = child1;
748     hChild1 = TreeView_InsertItemA(hTree, &ins);
749     ok(hChild1 != NULL, "failed to set hChild1\n");
750     ins.hInsertAfter = hChild1;
751     U(ins).item.mask = TVIF_TEXT;
752     U(ins).item.pszText = child2;
753     hChild2 = TreeView_InsertItemA(hTree, &ins);
754     ok(hChild2 != NULL, "failed to set hChild2\n");
755 
756     ShowWindow(hMainWnd,SW_SHOW);
757     SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
758     hEdit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hChild);
759     ScrollWindowEx(hTree, -10, 0, NULL, NULL, NULL, NULL, SW_SCROLLCHILDREN);
760     ok(GetFocus() == hEdit, "Edit control should have focus\n");
761     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, focus_seq, "focus test", TRUE);
762 
763     DestroyWindow(hTree);
764 }
765 
766 static void test_get_set_bkcolor(void)
767 {
768     COLORREF crColor;
769     HWND hTree;
770 
771     hTree = create_treeview_control(0);
772     fill_tree(hTree);
773 
774     flush_sequences(sequences, NUM_MSG_SEQUENCES);
775 
776     /* If the value is -1, the control is using the system color for the background color. */
777     crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0);
778     ok(crColor == ~0u, "Default background color reported as 0x%.8x\n", crColor);
779 
780     /* Test for black background */
781     SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(0,0,0));
782     crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0);
783     ok(crColor == RGB(0,0,0), "Black background color reported as 0x%.8x\n", crColor);
784 
785     /* Test for white background */
786     SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(255,255,255));
787     crColor = SendMessageA(hTree, TVM_GETBKCOLOR, 0, 0);
788     ok(crColor == RGB(255,255,255), "White background color reported as 0x%.8x\n", crColor);
789 
790     /* Reset the default background */
791     SendMessageA(hTree, TVM_SETBKCOLOR, 0, -1);
792 
793     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_bkcolor_seq,
794         "test get set bkcolor", FALSE);
795 
796     DestroyWindow(hTree);
797 }
798 
799 static void test_get_set_imagelist(void)
800 {
801     HIMAGELIST himl;
802     HWND hTree;
803 
804     hTree = create_treeview_control(0);
805     fill_tree(hTree);
806 
807     flush_sequences(sequences, NUM_MSG_SEQUENCES);
808 
809     /* Test a NULL HIMAGELIST */
810     SendMessageA(hTree, TVM_SETIMAGELIST, TVSIL_NORMAL, 0);
811     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_NORMAL, 0);
812     ok(himl == NULL, "NULL image list, reported as %p, expected 0.\n", himl);
813 
814     /* TODO: Test an actual image list */
815 
816     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_imagelist_seq,
817         "test get imagelist", FALSE);
818 
819     DestroyWindow(hTree);
820 }
821 
822 static void test_get_set_indent(void)
823 {
824     int ulIndent;
825     int ulMinIndent;
826     int ulMoreThanTwiceMin;
827     HWND hTree;
828 
829     hTree = create_treeview_control(0);
830     fill_tree(hTree);
831 
832     flush_sequences(sequences, NUM_MSG_SEQUENCES);
833 
834     /* Finding the minimum indent */
835     SendMessageA(hTree, TVM_SETINDENT, 0, 0);
836     ulMinIndent = SendMessageA(hTree, TVM_GETINDENT, 0, 0);
837 
838     /* Checking an indent that is more than twice the default indent */
839     ulMoreThanTwiceMin = 2*ulMinIndent+1;
840     SendMessageA(hTree, TVM_SETINDENT, ulMoreThanTwiceMin, 0);
841     ulIndent = SendMessageA(hTree, TVM_GETINDENT, 0, 0);
842     ok(ulIndent == ulMoreThanTwiceMin, "Indent reported as %d, expected %d\n", ulIndent, ulMoreThanTwiceMin);
843 
844     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_indent_seq,
845         "test get set indent", FALSE);
846 
847     DestroyWindow(hTree);
848 }
849 
850 static void test_get_set_insertmark(void)
851 {
852     COLORREF crColor = RGB(0,0,0);
853     HWND hTree;
854 
855     hTree = create_treeview_control(0);
856     fill_tree(hTree);
857 
858     flush_sequences(sequences, NUM_MSG_SEQUENCES);
859 
860     SendMessageA(hTree, TVM_SETINSERTMARKCOLOR, 0, crColor);
861     crColor = SendMessageA(hTree, TVM_GETINSERTMARKCOLOR, 0, 0);
862     ok(crColor == RGB(0,0,0), "Insert mark color reported as 0x%.8x, expected 0x00000000\n", crColor);
863 
864     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_insertmarkcolor_seq,
865         "test get set insertmark color", FALSE);
866 
867     DestroyWindow(hTree);
868 }
869 
870 static void test_get_set_item(void)
871 {
872     TVITEMA tviRoot = {0};
873     int nBufferSize = 80;
874     char szBuffer[80] = {0};
875     HWND hTree, hTree2;
876     DWORD ret;
877 
878     hTree = create_treeview_control(0);
879     fill_tree(hTree);
880 
881     tviRoot.hItem = hRoot;
882     tviRoot.mask  = TVIF_STATE;
883     tviRoot.state = TVIS_FOCUSED;
884     tviRoot.stateMask = TVIS_FOCUSED;
885     ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot);
886     expect(TRUE, ret);
887 
888     flush_sequences(sequences, NUM_MSG_SEQUENCES);
889 
890     /* Test the root item, state is set even when not requested */
891     tviRoot.hItem = hRoot;
892     tviRoot.mask = TVIF_TEXT;
893     tviRoot.state = 0;
894     tviRoot.stateMask = 0;
895     tviRoot.cchTextMax = nBufferSize;
896     tviRoot.pszText = szBuffer;
897     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
898     expect(TRUE, ret);
899     ok(!strcmp("Root", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Root\"\n", szBuffer);
900     ok(tviRoot.state == TVIS_FOCUSED, "got 0x%0x\n", tviRoot.state);
901 
902     /* Change the root text */
903     lstrcpynA(szBuffer, "Testing123", nBufferSize);
904     ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot);
905     expect(TRUE, ret);
906     memset(szBuffer, 0, nBufferSize);
907     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
908     expect(TRUE, ret);
909     ok(!strcmp("Testing123", szBuffer), "GetItem: szBuffer=\"%s\", expected \"Testing123\"\n", szBuffer);
910 
911     /* Reset the root text */
912     memset(szBuffer, 0, nBufferSize);
913     lstrcpynA(szBuffer, "Root", nBufferSize);
914     ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&tviRoot);
915     expect(TRUE, ret);
916 
917     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_item_seq,
918         "test get set item", FALSE);
919 
920     /* get item from a different tree */
921     hTree2 = create_treeview_control(0);
922 
923     tviRoot.hItem = hRoot;
924     tviRoot.mask = TVIF_STATE;
925     tviRoot.state = 0;
926     ret = SendMessageA(hTree2, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
927     expect(TRUE, ret);
928     ok(tviRoot.state == TVIS_FOCUSED, "got state 0x%0x\n", tviRoot.state);
929 
930     /* invalid item pointer, nt4 crashes here but later versions just return 0 */
931     tviRoot.hItem = (HTREEITEM)0xdeadbeef;
932     tviRoot.mask = TVIF_STATE;
933     tviRoot.state = 0;
934     ret = SendMessageA(hTree2, TVM_GETITEMA, 0, (LPARAM)&tviRoot);
935     expect(FALSE, ret);
936 
937     DestroyWindow(hTree);
938     DestroyWindow(hTree2);
939 }
940 
941 static void test_get_set_itemheight(void)
942 {
943     int ulOldHeight = 0;
944     int ulNewHeight = 0;
945     HWND hTree;
946 
947     hTree = create_treeview_control(0);
948     fill_tree(hTree);
949 
950     flush_sequences(sequences, NUM_MSG_SEQUENCES);
951 
952     /* Assuming default height to begin with */
953     ulOldHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
954 
955     /* Explicitly setting and getting the default height */
956     SendMessageA(hTree, TVM_SETITEMHEIGHT, -1, 0);
957     ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
958     ok(ulNewHeight == ulOldHeight, "Default height not set properly, reported %d, expected %d\n", ulNewHeight, ulOldHeight);
959 
960     /* Explicitly setting and getting the height of twice the normal */
961     SendMessageA(hTree, TVM_SETITEMHEIGHT, 2*ulOldHeight, 0);
962     ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
963     ok(ulNewHeight == 2*ulOldHeight, "New height not set properly, reported %d, expected %d\n", ulNewHeight, 2*ulOldHeight);
964 
965     /* Assuming tree doesn't have TVS_NONEVENHEIGHT set, so a set of 9 will round down to 8 */
966     SendMessageA(hTree, TVM_SETITEMHEIGHT, 9, 0);
967     ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
968     ok(ulNewHeight == 8, "Uneven height not set properly, reported %d, expected %d\n", ulNewHeight, 8);
969 
970     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_itemheight_seq,
971         "test get set item height", FALSE);
972 
973     /* without TVS_NONEVENHEIGHT */
974     SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) & ~TVS_NONEVENHEIGHT);
975     /* odd value */
976     ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 3, 0);
977     ok(ulOldHeight == 8, "got %d, expected %d\n", ulOldHeight, 8);
978     ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
979     ok(ulNewHeight == 2, "got %d, expected %d\n", ulNewHeight, 2);
980 
981     ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 4, 0);
982     ok(ulOldHeight == 2, "got %d, expected %d\n", ulOldHeight, 2);
983     ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
984     ok(ulNewHeight == 4, "got %d, expected %d\n", ulNewHeight, 4);
985 
986     /* with TVS_NONEVENHEIGHT */
987     SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_NONEVENHEIGHT);
988     /* odd value */
989     ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 3, 0);
990     ok(ulOldHeight == 4, "got %d, expected %d\n", ulOldHeight, 4);
991     ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
992     ok(ulNewHeight == 3, "got %d, expected %d\n", ulNewHeight, 3);
993     /* even value */
994     ulOldHeight = SendMessageA(hTree, TVM_SETITEMHEIGHT, 10, 0);
995     ok(ulOldHeight == 3, "got %d, expected %d\n", ulOldHeight, 3);
996     ulNewHeight = SendMessageA(hTree, TVM_GETITEMHEIGHT, 0, 0);
997     ok(ulNewHeight == 10, "got %d, expected %d\n", ulNewHeight, 10);
998 
999     DestroyWindow(hTree);
1000 }
1001 
1002 static void test_get_set_scrolltime(void)
1003 {
1004     int ulExpectedTime = 20;
1005     int ulTime = 0;
1006     HWND hTree;
1007 
1008     hTree = create_treeview_control(0);
1009     fill_tree(hTree);
1010 
1011     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1012 
1013     SendMessageA(hTree, TVM_SETSCROLLTIME, ulExpectedTime, 0);
1014     ulTime = SendMessageA(hTree, TVM_GETSCROLLTIME, 0, 0);
1015     ok(ulTime == ulExpectedTime, "Scroll time reported as %d, expected %d\n", ulTime, ulExpectedTime);
1016 
1017     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_scrolltime_seq,
1018         "test get set scroll time", FALSE);
1019 
1020     DestroyWindow(hTree);
1021 }
1022 
1023 static void test_get_set_textcolor(void)
1024 {
1025     /* If the value is -1, the control is using the system color for the text color. */
1026     COLORREF crColor;
1027     HWND hTree;
1028 
1029     hTree = create_treeview_control(0);
1030     fill_tree(hTree);
1031 
1032     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1033 
1034     crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0);
1035     ok(crColor == ~0u, "Default text color reported as 0x%.8x\n", crColor);
1036 
1037     /* Test for black text */
1038     SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, RGB(0,0,0));
1039     crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0);
1040     ok(crColor == RGB(0,0,0), "Black text color reported as 0x%.8x\n", crColor);
1041 
1042     /* Test for white text */
1043     SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, RGB(255,255,255));
1044     crColor = SendMessageA(hTree, TVM_GETTEXTCOLOR, 0, 0);
1045     ok(crColor == RGB(255,255,255), "White text color reported as 0x%.8x\n", crColor);
1046 
1047     /* Reset the default text color */
1048     SendMessageA(hTree, TVM_SETTEXTCOLOR, 0, CLR_NONE);
1049 
1050     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_textcolor_seq,
1051         "test get set text color", FALSE);
1052 
1053     DestroyWindow(hTree);
1054 }
1055 
1056 static void test_get_set_tooltips(void)
1057 {
1058     HWND hwndLastToolTip = NULL;
1059     HWND hPopupTreeView;
1060     HWND hTree;
1061 
1062     hTree = create_treeview_control(0);
1063     fill_tree(hTree);
1064 
1065     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1066 
1067     /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */
1068     hPopupTreeView = CreateWindowA(WC_TREEVIEWA, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100,
1069             hMainWnd, NULL, NULL, NULL);
1070     DestroyWindow(hPopupTreeView);
1071 
1072     /* Testing setting a NULL ToolTip */
1073     SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0);
1074     hwndLastToolTip = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0);
1075     ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip);
1076 
1077     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_tooltips_seq,
1078         "test get set tooltips", TRUE);
1079 
1080     /* TODO: Add a test of an actual tooltip */
1081     DestroyWindow(hTree);
1082 }
1083 
1084 static void test_get_set_unicodeformat(void)
1085 {
1086     BOOL bPreviousSetting;
1087     BOOL bNewSetting;
1088     HWND hTree;
1089 
1090     hTree = create_treeview_control(0);
1091     fill_tree(hTree);
1092 
1093     /* Check that an invalid format returned by NF_QUERY defaults to ANSI */
1094     bPreviousSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0);
1095     ok(bPreviousSetting == FALSE, "Format should be ANSI.\n");
1096 
1097     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1098 
1099     /* Set to Unicode */
1100     bPreviousSetting = SendMessageA(hTree, TVM_SETUNICODEFORMAT, 1, 0);
1101     bNewSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0);
1102     ok(bNewSetting == TRUE, "Unicode setting did not work.\n");
1103 
1104     /* Set to ANSI */
1105     SendMessageA(hTree, TVM_SETUNICODEFORMAT, 0, 0);
1106     bNewSetting = SendMessageA(hTree, TVM_GETUNICODEFORMAT, 0, 0);
1107     ok(bNewSetting == FALSE, "ANSI setting did not work.\n");
1108 
1109     /* Revert to original setting */
1110     SendMessageA(hTree, TVM_SETUNICODEFORMAT, bPreviousSetting, 0);
1111 
1112     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_unicodeformat_seq,
1113         "test get set unicode format", FALSE);
1114 
1115     DestroyWindow(hTree);
1116 }
1117 
1118 static LRESULT CALLBACK parent_wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
1119 {
1120     static LONG defwndproc_counter = 0;
1121     struct message msg = { 0 };
1122     LRESULT ret;
1123     RECT rect;
1124     HTREEITEM visibleItem;
1125 
1126     msg.message = message;
1127     msg.flags = sent|wparam|lparam;
1128     if (defwndproc_counter) msg.flags |= defwinproc;
1129     msg.wParam = wParam;
1130     msg.lParam = lParam;
1131     if (message == WM_NOTIFY && lParam)
1132         msg.id = ((NMHDR*)lParam)->code;
1133 
1134     /* log system messages, except for painting */
1135     if (message < WM_USER &&
1136         message != WM_PAINT &&
1137         message != WM_ERASEBKGND &&
1138         message != WM_NCPAINT &&
1139         message != WM_NCHITTEST &&
1140         message != WM_GETTEXT &&
1141         message != WM_GETICON &&
1142         message != WM_DEVICECHANGE)
1143     {
1144         add_message(sequences, PARENT_SEQ_INDEX, &msg);
1145     }
1146 
1147     switch(message) {
1148     case WM_NOTIFYFORMAT:
1149     {
1150         /* Make NF_QUERY return an invalid format to show that it defaults to ANSI */
1151         if (lParam == NF_QUERY) return 0;
1152         break;
1153     }
1154 
1155     case WM_NOTIFY:
1156     {
1157         NMHDR *pHdr = (NMHDR *)lParam;
1158 
1159         ok(pHdr->code != NM_TOOLTIPSCREATED, "Treeview should not send NM_TOOLTIPSCREATED\n");
1160         if (pHdr->idFrom == 100)
1161         {
1162             NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam;
1163             switch(pHdr->code)
1164             {
1165             case TVN_SELCHANGINGA:
1166                 AddItem('(');
1167                 IdentifyItem(pTreeView->itemOld.hItem);
1168                 IdentifyItem(pTreeView->itemNew.hItem);
1169                 break;
1170             case TVN_SELCHANGEDA:
1171                 AddItem(')');
1172                 IdentifyItem(pTreeView->itemOld.hItem);
1173                 IdentifyItem(pTreeView->itemNew.hItem);
1174                 break;
1175             case TVN_GETDISPINFOA: {
1176                 NMTVDISPINFOA *disp = (NMTVDISPINFOA *)lParam;
1177                 if (disp->item.mask & TVIF_TEXT) {
1178                     lstrcpynA(disp->item.pszText, TEST_CALLBACK_TEXT, disp->item.cchTextMax);
1179                 }
1180 
1181                 if (g_disp_A_to_W && (disp->item.mask & TVIF_TEXT)) {
1182                     static const WCHAR testW[] = {'T','E','S','T','2',0};
1183 
1184                     disp->hdr.code = TVN_GETDISPINFOW;
1185                     memcpy(disp->item.pszText, testW, sizeof(testW));
1186                 }
1187 
1188                 if (g_disp_set_stateimage)
1189                 {
1190                     ok(disp->item.mask == TVIF_IMAGE, "got %x\n", disp->item.mask);
1191                     /* both masks set here are necessary to change state bits */
1192                     disp->item.mask |= TVIF_STATE;
1193                     disp->item.state = TVIS_SELECTED | INDEXTOSTATEIMAGEMASK(2) | INDEXTOOVERLAYMASK(3);
1194                     disp->item.stateMask = TVIS_SELECTED | TVIS_OVERLAYMASK | TVIS_STATEIMAGEMASK;
1195                 }
1196 
1197                 break;
1198               }
1199             case TVN_BEGINLABELEDITA:
1200               {
1201                 if (g_beginedit_alter_text)
1202                 {
1203                     static const char* textA = "<edittextaltered>";
1204                     HWND edit;
1205 
1206                     edit = (HWND)SendMessageA(pHdr->hwndFrom, TVM_GETEDITCONTROL, 0, 0);
1207                     ok(IsWindow(edit), "failed to get edit handle\n");
1208                     SetWindowTextA(edit, textA);
1209                 }
1210 
1211                 break;
1212               }
1213 
1214             case TVN_ENDLABELEDITA: return TRUE;
1215             case TVN_ITEMEXPANDINGA:
1216               {
1217                 UINT newmask = pTreeView->itemNew.mask & ~TVIF_CHILDREN;
1218                 ok(newmask ==
1219                    (TVIF_HANDLE | TVIF_SELECTEDIMAGE | TVIF_IMAGE | TVIF_PARAM | TVIF_STATE),
1220                    "got wrong mask %x\n", pTreeView->itemNew.mask);
1221                 ok(pTreeView->itemOld.mask == 0,
1222                    "got wrong mask %x\n", pTreeView->itemOld.mask);
1223 
1224                 if (g_get_from_expand)
1225                 {
1226                   g_item_expanding.mask = TVIF_STATE;
1227                   g_item_expanding.hItem = hRoot;
1228                   ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanding);
1229                   ok(ret == TRUE, "got %lu\n", ret);
1230                 }
1231                 break;
1232               }
1233             case TVN_ITEMEXPANDEDA:
1234                 ok(pTreeView->itemNew.mask & TVIF_STATE, "got wrong mask %x\n", pTreeView->itemNew.mask);
1235                 ok(pTreeView->itemNew.state & (TVIS_EXPANDED|TVIS_EXPANDEDONCE),
1236                    "got wrong mask %x\n", pTreeView->itemNew.mask);
1237                 ok(pTreeView->itemOld.mask == 0,
1238                    "got wrong mask %x\n", pTreeView->itemOld.mask);
1239 
1240                 if (g_get_from_expand)
1241                 {
1242                   g_item_expanded.mask = TVIF_STATE;
1243                   g_item_expanded.hItem = hRoot;
1244                   ret = SendMessageA(pHdr->hwndFrom, TVM_GETITEMA, 0, (LPARAM)&g_item_expanded);
1245                   ok(ret == TRUE, "got %lu\n", ret);
1246                 }
1247                 if (g_get_rect_in_expand)
1248                 {
1249                   visibleItem = (HTREEITEM)SendMessageA(pHdr->hwndFrom, TVM_GETNEXTITEM,
1250                           TVGN_FIRSTVISIBLE, 0);
1251                   ok(pTreeView->itemNew.hItem == visibleItem, "expanded item == first visible item\n");
1252                   *(HTREEITEM*)&rect = visibleItem;
1253                   ok(SendMessageA(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect),
1254                           "Failed to get rect for first visible item.\n");
1255                   visibleItem = (HTREEITEM)SendMessageA(pHdr->hwndFrom, TVM_GETNEXTITEM,
1256                           TVGN_NEXTVISIBLE, (LPARAM)visibleItem);
1257                   *(HTREEITEM*)&rect = visibleItem;
1258                   ok(visibleItem != NULL, "There must be a visible item after the first visisble item.\n");
1259                   ok(SendMessageA(pHdr->hwndFrom, TVM_GETITEMRECT, TRUE, (LPARAM)&rect),
1260                           "Failed to get rect for second visible item.\n");
1261                 }
1262                 break;
1263             case TVN_DELETEITEMA:
1264             {
1265                 struct message item;
1266 
1267                 ok(pTreeView->itemNew.mask == 0, "got wrong mask 0x%x\n", pTreeView->itemNew.mask);
1268 
1269                 ok(pTreeView->itemOld.mask == (TVIF_HANDLE | TVIF_PARAM), "got wrong mask 0x%x\n", pTreeView->itemOld.mask);
1270                 ok(pTreeView->itemOld.hItem != NULL, "got %p\n", pTreeView->itemOld.hItem);
1271 
1272                 memset(&item, 0, sizeof(item));
1273                 item.lParam = (LPARAM)pTreeView->itemOld.hItem;
1274                 add_message(item_sequence, 0, &item);
1275 
1276                 break;
1277             }
1278             case NM_CUSTOMDRAW:
1279             {
1280                 NMTVCUSTOMDRAW *nmcd = (NMTVCUSTOMDRAW*)lParam;
1281                 COLORREF c0ffee = RGB(0xc0,0xff,0xee), cafe = RGB(0xca,0xfe,0x00);
1282                 COLORREF text = GetTextColor(nmcd->nmcd.hdc), bkgnd = GetBkColor(nmcd->nmcd.hdc);
1283 
1284                 msg.flags |= custdraw;
1285                 msg.stage = nmcd->nmcd.dwDrawStage;
1286                 add_message(sequences, PARENT_CD_SEQ_INDEX, &msg);
1287 
1288                 switch (msg.stage)
1289                 {
1290                 case CDDS_PREPAINT:
1291                     return CDRF_NOTIFYITEMDRAW|CDRF_NOTIFYITEMERASE|CDRF_NOTIFYPOSTPAINT;
1292                 case CDDS_ITEMPREPAINT:
1293                     ok(text == nmcd->clrText || (g_v6 && nmcd->clrText == 0xffffffff),
1294                        "got %08x vs %08x\n", text, nmcd->clrText);
1295                     ok(bkgnd == nmcd->clrTextBk || (g_v6 && nmcd->clrTextBk == 0xffffffff),
1296                        "got %08x vs %08x\n", bkgnd, nmcd->clrTextBk);
1297                     nmcd->clrText = cafe;
1298                     nmcd->clrTextBk = c0ffee;
1299                     SetTextColor(nmcd->nmcd.hdc, c0ffee);
1300                     SetBkColor(nmcd->nmcd.hdc, cafe);
1301                     if (g_customdraw_font)
1302                         SelectObject(nmcd->nmcd.hdc, g_customdraw_font);
1303                     return CDRF_NOTIFYPOSTPAINT|CDRF_NEWFONT;
1304                 case CDDS_ITEMPOSTPAINT:
1305                     /* at the point of post paint notification colors are already restored */
1306                     ok(nmcd->clrText == cafe, "got 0%x\n", nmcd->clrText);
1307                     ok(nmcd->clrTextBk == c0ffee, "got 0%x\n", nmcd->clrTextBk);
1308                     ok(text != cafe, "got 0%x\n", text);
1309                     ok(bkgnd != c0ffee, "got 0%x\n", bkgnd);
1310                     if (g_customdraw_font)
1311                         ok(GetCurrentObject(nmcd->nmcd.hdc, OBJ_FONT) != g_customdraw_font, "got %p\n",
1312                            GetCurrentObject(nmcd->nmcd.hdc, OBJ_FONT));
1313                     break;
1314                 default:
1315                     ;
1316                 }
1317                 break;
1318             }
1319             case NM_RCLICK:
1320             {
1321                 HTREEITEM selected = (HTREEITEM)SendMessageA(((NMHDR *)lParam)->hwndFrom,
1322                                                              TVM_GETNEXTITEM, TVGN_CARET, 0);
1323                 ok(selected == hChild, "child item should still be selected\n");
1324                 break;
1325             }
1326             }
1327         }
1328         break;
1329     }
1330 
1331     case WM_DESTROY:
1332         PostQuitMessage(0);
1333         break;
1334     }
1335 
1336     defwndproc_counter++;
1337     ret = DefWindowProcA(hWnd, message, wParam, lParam);
1338     defwndproc_counter--;
1339 
1340     return ret;
1341 }
1342 
1343 static void test_expandinvisible(void)
1344 {
1345     static CHAR nodeText[][5] = {"0", "1", "2", "3", "4"};
1346     TVINSERTSTRUCTA ins;
1347     HTREEITEM node[5];
1348     RECT dummyRect;
1349     BOOL nodeVisible;
1350     LRESULT ret;
1351     HWND hTree;
1352 
1353     hTree = create_treeview_control(0);
1354 
1355     /* The test builds the following tree and expands node 1, while node 0 is collapsed.
1356      *
1357      * 0
1358      * |- 1
1359      * |  |- 2
1360      * |  |- 3
1361      * |- 4
1362      *
1363      */
1364 
1365     ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
1366     ok(ret == TRUE, "ret\n");
1367     ins.hParent = TVI_ROOT;
1368     ins.hInsertAfter = TVI_ROOT;
1369     U(ins).item.mask = TVIF_TEXT;
1370     U(ins).item.pszText = nodeText[0];
1371     node[0] = TreeView_InsertItemA(hTree, &ins);
1372     ok(node[0] != NULL, "failed to set node[0]\n");
1373 
1374     ins.hInsertAfter = TVI_LAST;
1375     U(ins).item.mask = TVIF_TEXT;
1376     ins.hParent = node[0];
1377 
1378     U(ins).item.pszText = nodeText[1];
1379     node[1] = TreeView_InsertItemA(hTree, &ins);
1380     ok(node[1] != NULL, "failed to set node[1]\n");
1381     U(ins).item.pszText = nodeText[4];
1382     node[4] = TreeView_InsertItemA(hTree, &ins);
1383     ok(node[4] != NULL, "failed to set node[4]\n");
1384 
1385     ins.hParent = node[1];
1386 
1387     U(ins).item.pszText = nodeText[2];
1388     node[2] = TreeView_InsertItemA(hTree, &ins);
1389     ok(node[2] != NULL, "failed to set node[2]\n");
1390     U(ins).item.pszText = nodeText[3];
1391     node[3] = TreeView_InsertItemA(hTree, &ins);
1392     ok(node[3] != NULL, "failed to set node[3]\n");
1393 
1394     *(HTREEITEM *)&dummyRect = node[1];
1395     nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1396     ok(!nodeVisible, "Node 1 should not be visible.\n");
1397     *(HTREEITEM *)&dummyRect = node[2];
1398     nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1399     ok(!nodeVisible, "Node 2 should not be visible.\n");
1400     *(HTREEITEM *)&dummyRect = node[3];
1401     nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1402     ok(!nodeVisible, "Node 3 should not be visible.\n");
1403     *(HTREEITEM *)&dummyRect = node[4];
1404     nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1405     ok(!nodeVisible, "Node 4 should not be visible.\n");
1406 
1407     ok(SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)node[1]), "Expand of node 1 failed.\n");
1408 
1409     *(HTREEITEM *)&dummyRect = node[1];
1410     nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1411     ok(!nodeVisible, "Node 1 should not be visible.\n");
1412     *(HTREEITEM *)&dummyRect = node[2];
1413     nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1414     ok(!nodeVisible, "Node 2 should not be visible.\n");
1415     *(HTREEITEM *)&dummyRect = node[3];
1416     nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1417     ok(!nodeVisible, "Node 3 should not be visible.\n");
1418     *(HTREEITEM *)&dummyRect = node[4];
1419     nodeVisible = SendMessageA(hTree, TVM_GETITEMRECT, FALSE, (LPARAM)&dummyRect);
1420     ok(!nodeVisible, "Node 4 should not be visible.\n");
1421 
1422     DestroyWindow(hTree);
1423 }
1424 
1425 static void test_itemedit(void)
1426 {
1427     DWORD r;
1428     HWND edit;
1429     TVITEMA item;
1430     CHAR buffA[20];
1431     HWND hTree;
1432 
1433     hTree = create_treeview_control(0);
1434     fill_tree(hTree);
1435 
1436     /* try with null item */
1437     edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, 0);
1438     ok(!IsWindow(edit), "Expected valid handle\n");
1439 
1440     /* trigger edit */
1441     edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot);
1442     ok(IsWindow(edit), "Expected valid handle\n");
1443     /* item shouldn't be selected automatically after TVM_EDITLABELA */
1444     r = SendMessageA(hTree, TVM_GETITEMSTATE, (WPARAM)hRoot, TVIS_SELECTED);
1445     expect(0, r);
1446     /* try to cancel with wrong edit handle */
1447     r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
1448     expect(0, r);
1449     ok(IsWindow(edit), "Expected edit control to be valid\n");
1450     r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1451     expect(0, r);
1452     ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1453     /* try to cancel without creating edit */
1454     r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), 0);
1455     expect(0, r);
1456 
1457     /* try to cancel with wrong (not null) handle */
1458     edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot);
1459     ok(IsWindow(edit), "Expected valid handle\n");
1460     r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)hTree);
1461     expect(0, r);
1462     ok(IsWindow(edit), "Expected edit control to be valid\n");
1463     r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1464     expect(0, r);
1465 
1466     /* remove selection after starting edit */
1467     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
1468     expect(TRUE, r);
1469     edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot);
1470     ok(IsWindow(edit), "Expected valid handle\n");
1471     r = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);
1472     expect(TRUE, r);
1473     /* alter text */
1474     strcpy(buffA, "x");
1475     r = SendMessageA(edit, WM_SETTEXT, 0, (LPARAM)buffA);
1476     expect(TRUE, r);
1477     r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1478     expect(0, r);
1479     ok(!IsWindow(edit), "Expected edit control to be destroyed\n");
1480     /* check that text is saved */
1481     item.mask = TVIF_TEXT;
1482     item.hItem = hRoot;
1483     item.pszText = buffA;
1484     item.cchTextMax = sizeof(buffA)/sizeof(CHAR);
1485     r = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1486     expect(TRUE, r);
1487     ok(!strcmp("x", buffA), "Expected item text to change\n");
1488 
1489     /* try A/W messages */
1490     edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot);
1491     ok(IsWindow(edit), "Expected valid handle\n");
1492     ok(IsWindowUnicode(edit), "got ansi window\n");
1493     r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1494     expect(0, r);
1495     ok(!IsWindow(edit), "expected invalid handle\n");
1496 
1497     edit = (HWND)SendMessageA(hTree, TVM_EDITLABELW, 0, (LPARAM)hRoot);
1498     ok(IsWindow(edit), "Expected valid handle\n");
1499     ok(IsWindowUnicode(edit), "got ansi window\n");
1500     r = SendMessageA(hTree, WM_COMMAND, MAKEWPARAM(0, EN_KILLFOCUS), (LPARAM)edit);
1501     expect(0, r);
1502 
1503     /* alter text during TVM_BEGINLABELEDIT, check that it's preserved */
1504     strcpy(buffA, "<root>");
1505 
1506     item.mask = TVIF_TEXT;
1507     item.hItem = hRoot;
1508     item.pszText = buffA;
1509     item.cchTextMax = 0;
1510     r = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
1511     expect(TRUE, r);
1512 
1513     g_beginedit_alter_text = TRUE;
1514     edit = (HWND)SendMessageA(hTree, TVM_EDITLABELA, 0, (LPARAM)hRoot);
1515     ok(IsWindow(edit), "Expected valid handle\n");
1516     g_beginedit_alter_text = FALSE;
1517 
1518     GetWindowTextA(edit, buffA, sizeof(buffA)/sizeof(CHAR));
1519     ok(!strcmp(buffA, "<edittextaltered>"), "got string %s\n", buffA);
1520 
1521     DestroyWindow(hTree);
1522 }
1523 
1524 static void test_treeview_classinfo(void)
1525 {
1526     WNDCLASSA cls;
1527 
1528     memset(&cls, 0, sizeof(cls));
1529     GetClassInfoA(GetModuleHandleA("comctl32.dll"), WC_TREEVIEWA, &cls);
1530     ok(cls.hbrBackground == NULL, "Expected NULL background brush, got %p\n", cls.hbrBackground);
1531     ok(cls.style == (CS_GLOBALCLASS | CS_DBLCLKS), "Expected got %x\n", cls.style);
1532     expect(0, cls.cbClsExtra);
1533 }
1534 
1535 static void test_get_linecolor(void)
1536 {
1537     COLORREF clr;
1538     HWND hTree;
1539 
1540     hTree = create_treeview_control(0);
1541 
1542     /* newly created control has default color */
1543     clr = SendMessageA(hTree, TVM_GETLINECOLOR, 0, 0);
1544     if (clr == 0)
1545         win_skip("TVM_GETLINECOLOR is not supported on comctl32 < 5.80\n");
1546     else
1547         expect(CLR_DEFAULT, clr);
1548 
1549     DestroyWindow(hTree);
1550 }
1551 
1552 static void test_get_insertmarkcolor(void)
1553 {
1554     COLORREF clr;
1555     HWND hTree;
1556 
1557     hTree = create_treeview_control(0);
1558 
1559     /* newly created control has default color */
1560     clr = SendMessageA(hTree, TVM_GETINSERTMARKCOLOR, 0, 0);
1561     if (clr == 0)
1562         win_skip("TVM_GETINSERTMARKCOLOR is not supported on comctl32 < 5.80\n");
1563     else
1564         expect(CLR_DEFAULT, clr);
1565 
1566     DestroyWindow(hTree);
1567 }
1568 
1569 static void test_expandnotify(void)
1570 {
1571     HTREEITEM hitem;
1572     HWND hTree;
1573     BOOL ret;
1574     TVITEMA item;
1575 
1576     hTree = create_treeview_control(0);
1577     fill_tree(hTree);
1578 
1579     item.hItem = hRoot;
1580     item.mask = TVIF_STATE;
1581 
1582     item.state = TVIS_EXPANDED;
1583     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1584     expect(TRUE, ret);
1585     ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1586 
1587     /* preselect root node here */
1588     ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
1589     expect(TRUE, ret);
1590 
1591     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1592     ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot);
1593     expect(FALSE, ret);
1594     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "no collapse notifications", FALSE);
1595 
1596     g_get_from_expand = TRUE;
1597     /* expand */
1598     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1599     g_item_expanding.state = 0xdeadbeef;
1600     g_item_expanded.state = 0xdeadbeef;
1601     ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot);
1602     expect(TRUE, ret);
1603     ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1604        g_item_expanding.state);
1605     ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1606        g_item_expanded.state);
1607     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "expand notifications", FALSE);
1608     g_get_from_expand = FALSE;
1609 
1610     /* check that it's expanded */
1611     item.state = TVIS_EXPANDED;
1612     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1613     expect(TRUE, ret);
1614     ok((item.state & TVIS_EXPANDED) == TVIS_EXPANDED, "expected expanded\n");
1615 
1616     /* collapse */
1617     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1618     ret = SendMessageA(hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)hRoot);
1619     expect(TRUE, ret);
1620     item.state = TVIS_EXPANDED;
1621     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1622     expect(TRUE, ret);
1623     ok((item.state & TVIS_EXPANDED) == 0, "expected collapsed\n");
1624     /* all further collapse/expand attempts won't produce any notifications,
1625        the only way is to reset with all children removed */
1626     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "collapse after expand notifications", FALSE);
1627 
1628     /* try to toggle child that doesn't have children itself */
1629     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1630     ret = SendMessageA(hTree, TVM_EXPAND, TVE_TOGGLE, (LPARAM)hChild);
1631     expect(FALSE, ret);
1632     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "toggle node without children", FALSE);
1633 
1634     DestroyWindow(hTree);
1635 
1636     /* test TVM_GETITEMRECT inside TVN_ITEMEXPANDED notification */
1637     hTree = create_treeview_control(0);
1638     fill_tree(hTree);
1639     g_get_rect_in_expand = TRUE;
1640     ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
1641     expect(TRUE, ret);
1642     g_get_rect_in_expand = FALSE;
1643 
1644     DestroyWindow(hTree);
1645 
1646     /* TVE_TOGGLE acts as any other TVM_EXPAND */
1647     hTree = create_treeview_control(0);
1648     fill_tree(hTree);
1649 
1650     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1651     ret = SendMessageA(hTree, TVM_EXPAND, TVE_TOGGLE, (LPARAM)hRoot);
1652     expect(TRUE, ret);
1653     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_seq, "toggle node (expand)", FALSE);
1654 
1655     /* toggle again - no notifications */
1656     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1657     ret = SendMessageA(hTree, TVM_EXPAND, TVE_TOGGLE, (LPARAM)hRoot);
1658     expect(TRUE, ret);
1659     ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "toggle node (collapse)", FALSE);
1660 
1661     DestroyWindow(hTree);
1662 
1663     /* some keyboard events are also translated to expand */
1664     hTree = create_treeview_control(0);
1665     fill_tree(hTree);
1666 
1667     /* preselect root node here */
1668     ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hRoot);
1669     expect(TRUE, ret);
1670 
1671     g_get_from_expand = TRUE;
1672     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1673     ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0);
1674     expect(FALSE, ret);
1675     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node", FALSE);
1676     ok(g_item_expanding.state == TVIS_SELECTED, "got state on TVN_ITEMEXPANDING 0x%08x\n",
1677        g_item_expanding.state);
1678     ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1679        g_item_expanded.state);
1680 
1681     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1682     ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0);
1683     expect(FALSE, ret);
1684     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node again", FALSE);
1685     ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1686        g_item_expanding.state);
1687     ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1688        g_item_expanded.state);
1689 
1690     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1691     ret = SendMessageA(hTree, WM_KEYDOWN, VK_SUBTRACT, 0);
1692     expect(FALSE, ret);
1693     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "collapse node", FALSE);
1694     ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1695        g_item_expanding.state);
1696     ok(g_item_expanded.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDED 0x%08x\n",
1697        g_item_expanded.state);
1698 
1699     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1700     ret = SendMessageA(hTree, WM_KEYDOWN, VK_SUBTRACT, 0);
1701     expect(FALSE, ret);
1702     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_collapse_2nd_kb_seq, "collapse node again", FALSE);
1703     ok(g_item_expanding.state == (TVIS_SELECTED|TVIS_EXPANDEDONCE), "got state on TVN_ITEMEXPANDING 0x%08x\n",
1704        g_item_expanding.state);
1705     g_get_from_expand = FALSE;
1706 
1707     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1708     ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0);
1709     expect(FALSE, ret);
1710     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_kb_seq, "expand node", FALSE);
1711 
1712     /* go to child */
1713     ret = SendMessageA(hTree, WM_KEYDOWN, VK_RIGHT, 0);
1714     expect(FALSE, ret);
1715 
1716     /* try to expand child that doesn't have children itself */
1717     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1718     ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0);
1719     expect(FALSE, ret);
1720     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_expand_empty_kb_seq, "expand node with no children", FALSE);
1721 
1722     /* stay on current selection and set non-zero children count */
1723     hitem = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0);
1724     ok(hitem != NULL, "got %p\n", hitem);
1725 
1726     item.hItem = hitem;
1727     item.mask = TVIF_CHILDREN;
1728     item.cChildren = 0x80000000;
1729 
1730     ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
1731     expect(TRUE, ret);
1732 
1733     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1734     ret = SendMessageA(hTree, WM_KEYDOWN, VK_ADD, 0);
1735     expect(FALSE, ret);
1736     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_collapse_2nd_kb_seq, "expand node with children", FALSE);
1737 
1738     DestroyWindow(hTree);
1739 }
1740 
1741 static void test_expandedimage(void)
1742 {
1743     TVITEMEXA item;
1744     HWND hTree;
1745     BOOL ret;
1746 
1747     hTree = create_treeview_control(0);
1748     fill_tree(hTree);
1749 
1750     item.mask = TVIF_EXPANDEDIMAGE;
1751     item.iExpandedImage = 1;
1752     item.hItem = hRoot;
1753     ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
1754     ok(ret, "got %d\n", ret);
1755 
1756     item.mask = TVIF_EXPANDEDIMAGE;
1757     item.iExpandedImage = -1;
1758     item.hItem = hRoot;
1759     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1760     ok(ret, "got %d\n", ret);
1761 
1762     if (item.iExpandedImage != 1)
1763     {
1764         win_skip("TVIF_EXPANDEDIMAGE not supported\n");
1765         DestroyWindow(hTree);
1766         return;
1767     }
1768 
1769     /* test for default iExpandedImage value */
1770     item.mask = TVIF_EXPANDEDIMAGE;
1771     item.iExpandedImage = -1;
1772     item.hItem = hChild;
1773     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1774     ok(ret, "got %d\n", ret);
1775     ok(item.iExpandedImage == (WORD)I_IMAGENONE, "got %d\n", item.iExpandedImage);
1776 
1777     DestroyWindow(hTree);
1778 }
1779 
1780 static void test_TVS_SINGLEEXPAND(void)
1781 {
1782     HWND hTree;
1783     HTREEITEM alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india, juliet;
1784     TVINSERTSTRUCTA ins;
1785     char foo[] = "foo";
1786     char context[32];
1787     int i;
1788     BOOL ret;
1789 
1790     /* build a fairly complex tree
1791      * - TVI_ROOT
1792      *   - alpha
1793      *     - bravo
1794      *       - charlie
1795      *     - delta
1796      *       - echo
1797      *   - foxtrot
1798      *     - golf
1799      *       - hotel
1800      *       - india
1801      *     - juliet
1802      */
1803     struct
1804     {
1805         HTREEITEM *handle;
1806         HTREEITEM *parent;
1807         UINT final_state;
1808     }
1809     items[] =
1810     {
1811         { &alpha,    NULL,      TVIS_EXPANDEDONCE               },
1812         { &bravo,    &alpha,    TVIS_EXPANDEDONCE               },
1813         { &charlie,  &bravo,    0                               },
1814         { &delta,    &alpha,    TVIS_EXPANDEDONCE               },
1815         { &echo,     &delta,    0                               },
1816         { &foxtrot,  NULL,      TVIS_EXPANDEDONCE|TVIS_EXPANDED },
1817         { &golf,     &foxtrot,  TVIS_EXPANDEDONCE|TVIS_EXPANDED },
1818         { &hotel,    &golf,     0                               },
1819         { &india,    &golf,     TVIS_SELECTED                   },
1820         { &juliet,   &foxtrot,  0                               }
1821     };
1822 
1823     struct
1824     {
1825         HTREEITEM *select;
1826         const struct message *sequence;
1827     }
1828     sequence_tests[] =
1829     {
1830         { &alpha,    parent_singleexpand_seq0 },
1831         { &bravo,    parent_singleexpand_seq1 },
1832         { &delta,    parent_singleexpand_seq2 },
1833         { &foxtrot,  parent_singleexpand_seq3 },
1834         { &alpha,    parent_singleexpand_seq4 },
1835         { &golf,     parent_singleexpand_seq5 },
1836         { &hotel,    parent_singleexpand_seq6 },
1837         { &india,    parent_singleexpand_seq7 },
1838         { &india,    empty_seq }
1839     };
1840 
1841     hTree = create_treeview_control(0);
1842     SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_SINGLEEXPAND);
1843     /* to avoid painting related notifications */
1844     ShowWindow(hTree, SW_HIDE);
1845     for (i = 0; i < sizeof(items)/sizeof(items[0]); i++)
1846     {
1847         ins.hParent = items[i].parent ? *items[i].parent : TVI_ROOT;
1848         ins.hInsertAfter = TVI_FIRST;
1849         U(ins).item.mask = TVIF_TEXT;
1850         U(ins).item.pszText = foo;
1851         *items[i].handle = TreeView_InsertItemA(hTree, &ins);
1852     }
1853 
1854     for (i = 0; i < sizeof(sequence_tests)/sizeof(sequence_tests[0]); i++)
1855     {
1856         flush_sequences(sequences, NUM_MSG_SEQUENCES);
1857         ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)(*sequence_tests[i].select));
1858         ok(ret, "got %d\n", ret);
1859         sprintf(context, "singleexpand notifications %d", i);
1860         ok_sequence(sequences, PARENT_SEQ_INDEX, sequence_tests[i].sequence, context, FALSE);
1861     }
1862 
1863     for (i = 0; i < sizeof(items)/sizeof(items[0]); i++)
1864     {
1865         ret = SendMessageA(hTree, TVM_GETITEMSTATE, (WPARAM)(*items[i].handle), 0xFFFF);
1866         ok(ret == items[i].final_state, "singleexpand items[%d]: expected state 0x%x got 0x%x\n",
1867            i, items[i].final_state, ret);
1868     }
1869 
1870     /* a workaround for NT4 that sends expand notifications when nothing is about to expand */
1871     ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
1872     ok(ret, "got %d\n", ret);
1873     fill_tree(hTree);
1874     ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, 0);
1875     ok(ret, "got %d\n", ret);
1876 
1877     DestroyWindow(hTree);
1878 }
1879 
1880 static void test_WM_PAINT(void)
1881 {
1882     HWND hTree;
1883     COLORREF clr;
1884     LONG ret;
1885     RECT rc;
1886     HDC hdc;
1887 
1888     hTree = create_treeview_control(0);
1889 
1890     clr = SendMessageA(hTree, TVM_SETBKCOLOR, 0, RGB(255, 0, 0));
1891     ok(clr == ~0u, "got %d, expected -1\n", clr);
1892 
1893     hdc = GetDC(hMainWnd);
1894 
1895     GetClientRect(hMainWnd, &rc);
1896     FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
1897 
1898     clr = GetPixel(hdc, 1, 1);
1899     ok(clr == RGB(0, 0, 0), "got 0x%x\n", clr);
1900 
1901     ret = SendMessageA(hTree, WM_PAINT, (WPARAM)hdc, 0);
1902     ok(ret == 0, "got %d\n", ret);
1903 
1904     clr = GetPixel(hdc, 1, 1);
1905     ok(clr == RGB(255, 0, 0) || broken(clr == RGB(0, 0, 0)) /* win98 */,
1906         "got 0x%x\n", clr);
1907 
1908     ReleaseDC(hMainWnd, hdc);
1909 
1910     DestroyWindow(hTree);
1911 }
1912 
1913 static void test_delete_items(void)
1914 {
1915     const struct message *msg;
1916     HWND hTree;
1917     HTREEITEM hItem1, hItem2;
1918     TVINSERTSTRUCTA ins;
1919     INT ret;
1920 
1921     static CHAR item1[] = "Item 1";
1922     static CHAR item2[] = "Item 2";
1923 
1924     hTree = create_treeview_control(0);
1925     fill_tree(hTree);
1926 
1927     /* check delete order */
1928     flush_sequences(item_sequence, 1);
1929     ret = SendMessageA(hTree, TVM_DELETEITEM, 0, 0);
1930     ok(ret == TRUE, "got %d\n", ret);
1931 
1932     msg = item_sequence[0]->sequence;
1933     ok(item_sequence[0]->count == 2, "expected 2 items, got %d\n", item_sequence[0]->count);
1934 
1935     if (item_sequence[0]->count == 2)
1936     {
1937       ok(msg[0].lParam == (LPARAM)hChild, "expected %p, got 0x%lx\n", hChild, msg[0].lParam);
1938       ok(msg[1].lParam == (LPARAM)hRoot, "expected %p, got 0x%lx\n", hRoot, msg[1].lParam);
1939     }
1940 
1941     ret = SendMessageA(hTree, TVM_GETCOUNT, 0, 0);
1942     ok(ret == 0, "got %d\n", ret);
1943 
1944     DestroyWindow(hTree);
1945 
1946     /* Regression test for a crash when deleting the first visible item while bRedraw == false. */
1947     hTree = create_treeview_control(0);
1948 
1949     ret = SendMessageA(hTree, WM_SETREDRAW, FALSE, 0);
1950     ok(ret == 0, "got %d\n", ret);
1951 
1952     ins.hParent = TVI_ROOT;
1953     ins.hInsertAfter = TVI_ROOT;
1954     U(ins).item.mask = TVIF_TEXT;
1955     U(ins).item.pszText = item1;
1956     hItem1 = TreeView_InsertItemA(hTree, &ins);
1957     ok(hItem1 != NULL, "InsertItem failed\n");
1958 
1959     ins.hParent = TVI_ROOT;
1960     ins.hInsertAfter = hItem1;
1961     U(ins).item.mask = TVIF_TEXT;
1962     U(ins).item.pszText = item2;
1963     hItem2 = TreeView_InsertItemA(hTree, &ins);
1964     ok(hItem2 != NULL, "InsertItem failed\n");
1965 
1966     ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hItem1);
1967     ok(ret == TRUE, "got %d\n", ret);
1968 
1969     ret = SendMessageA(hTree, WM_SETREDRAW, TRUE, 0);
1970     ok(ret == 0, "got %d\n", ret);
1971 
1972     DestroyWindow(hTree);
1973 }
1974 
1975 static void test_cchildren(void)
1976 {
1977     HWND hTree;
1978     INT ret;
1979     TVITEMA item;
1980 
1981     hTree = create_treeview_control(0);
1982     fill_tree(hTree);
1983 
1984     ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild);
1985     expect(TRUE, ret);
1986 
1987     /* check cChildren - automatic mode */
1988     item.hItem = hRoot;
1989     item.mask = TVIF_CHILDREN;
1990 
1991     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
1992     expect(TRUE, ret);
1993     expect(0, item.cChildren);
1994 
1995     DestroyWindow(hTree);
1996 
1997     /* start over */
1998     hTree = create_treeview_control(0);
1999     fill_tree(hTree);
2000 
2001     /* turn off automatic mode by setting cChildren explicitly */
2002     item.hItem = hRoot;
2003     item.mask = TVIF_CHILDREN;
2004 
2005     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2006     expect(TRUE, ret);
2007     expect(1, item.cChildren);
2008 
2009     ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
2010     expect(TRUE, ret);
2011 
2012     ret = SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild);
2013     expect(TRUE, ret);
2014 
2015     /* check cChildren */
2016     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2017     expect(TRUE, ret);
2018 todo_wine
2019     expect(1, item.cChildren);
2020 
2021     DestroyWindow(hTree);
2022 }
2023 
2024 struct _ITEM_DATA
2025 {
2026     HTREEITEM  parent; /* for root value of parent field is unidetified */
2027     HTREEITEM  nextsibling;
2028     HTREEITEM  firstchild;
2029 };
2030 
2031 static void _check_item(HTREEITEM item, HTREEITEM parent, HTREEITEM nextsibling, HTREEITEM firstchild, int line)
2032 {
2033     struct _ITEM_DATA *data = (struct _ITEM_DATA*)item;
2034 
2035     ok_(__FILE__, line)(data->parent == parent, "parent %p, got %p\n", parent, data->parent);
2036     ok_(__FILE__, line)(data->nextsibling == nextsibling, "sibling %p, got %p\n", nextsibling, data->nextsibling);
2037     ok_(__FILE__, line)(data->firstchild == firstchild, "firstchild %p, got %p\n", firstchild, data->firstchild);
2038 }
2039 
2040 #define check_item(a, b, c, d) _check_item(a, b, c, d, __LINE__)
2041 
2042 static void test_htreeitem_layout(void)
2043 {
2044     TVINSERTSTRUCTA ins;
2045     HTREEITEM item1, item2;
2046     HWND hTree;
2047 
2048     hTree = create_treeview_control(0);
2049     fill_tree(hTree);
2050 
2051     /* root has some special pointer in parent field */
2052     check_item(hRoot, ((struct _ITEM_DATA*)hRoot)->parent, 0, hChild);
2053     check_item(hChild, hRoot, 0, 0);
2054 
2055     ins.hParent = hChild;
2056     ins.hInsertAfter = TVI_FIRST;
2057     U(ins).item.mask = 0;
2058     item1 = TreeView_InsertItemA(hTree, &ins);
2059 
2060     check_item(item1, hChild, 0, 0);
2061 
2062     ins.hParent = hRoot;
2063     ins.hInsertAfter = TVI_FIRST;
2064     U(ins).item.mask = 0;
2065     item2 = TreeView_InsertItemA(hTree, &ins);
2066 
2067     check_item(item2, hRoot, hChild, 0);
2068 
2069     SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild);
2070 
2071     /* without children now */
2072     check_item(hRoot, ((struct _ITEM_DATA*)hRoot)->parent, 0, item2);
2073 
2074     DestroyWindow(hTree);
2075 }
2076 
2077 static void test_TVS_CHECKBOXES(void)
2078 {
2079     HIMAGELIST himl, himl2;
2080     HWND hTree, hTree2;
2081     TVITEMA item;
2082     DWORD ret;
2083     MSG msg;
2084 
2085     hTree = create_treeview_control(0);
2086     fill_tree(hTree);
2087 
2088     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2089     ok(himl == NULL, "got %p\n", himl);
2090 
2091     item.hItem = hRoot;
2092     item.mask = TVIF_STATE;
2093     item.state = INDEXTOSTATEIMAGEMASK(1);
2094     item.stateMask = TVIS_STATEIMAGEMASK;
2095     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2096     expect(TRUE, ret);
2097     ok(item.state == 0, "got 0x%x\n", item.state);
2098 
2099     /* set some index for a child */
2100     item.hItem = hChild;
2101     item.mask = TVIF_STATE;
2102     item.state = INDEXTOSTATEIMAGEMASK(4);
2103     item.stateMask = TVIS_STATEIMAGEMASK;
2104     ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
2105     expect(TRUE, ret);
2106 
2107     /* enabling check boxes set all items to 1 state image index */
2108     SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES);
2109     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2110     ok(himl != NULL, "got %p\n", himl);
2111 
2112     himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2113     ok(himl2 != NULL, "got %p\n", himl2);
2114     ok(himl2 == himl, "got %p, expected %p\n", himl2, himl);
2115 
2116     item.hItem = hRoot;
2117     item.mask = TVIF_STATE;
2118     item.state = 0;
2119     item.stateMask = TVIS_STATEIMAGEMASK;
2120     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2121     expect(TRUE, ret);
2122     ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2123 
2124     item.hItem = hChild;
2125     item.mask = TVIF_STATE;
2126     item.state = 0;
2127     item.stateMask = TVIS_STATEIMAGEMASK;
2128     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2129     expect(TRUE, ret);
2130     ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2131 
2132     /* create another control and check its checkbox list */
2133     hTree2 = create_treeview_control(0);
2134     fill_tree(hTree2);
2135 
2136     /* set some index for a child */
2137     item.hItem = hChild;
2138     item.mask = TVIF_STATE;
2139     item.state = INDEXTOSTATEIMAGEMASK(4);
2140     item.stateMask = TVIS_STATEIMAGEMASK;
2141     ret = SendMessageA(hTree2, TVM_SETITEMA, 0, (LPARAM)&item);
2142     expect(TRUE, ret);
2143 
2144     /* enabling check boxes set all items to 1 state image index */
2145     SetWindowLongA(hTree2, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES);
2146     himl2 = (HIMAGELIST)SendMessageA(hTree2, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2147     ok(himl2 != NULL, "got %p\n", himl2);
2148     ok(himl != himl2, "got %p, expected %p\n", himl2, himl);
2149 
2150     DestroyWindow(hTree2);
2151     DestroyWindow(hTree);
2152 
2153     /* the same, but initially created with TVS_CHECKBOXES */
2154     hTree = create_treeview_control(TVS_CHECKBOXES);
2155     fill_tree(hTree);
2156     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2157     ok(himl == NULL, "got %p\n", himl);
2158 
2159     item.hItem = hRoot;
2160     item.mask = TVIF_STATE;
2161     item.state = 0;
2162     item.stateMask = TVIS_STATEIMAGEMASK;
2163     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2164     expect(TRUE, ret);
2165     ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2166 
2167     item.hItem = hChild;
2168     item.mask = TVIF_STATE;
2169     item.state = 0;
2170     item.stateMask = TVIS_STATEIMAGEMASK;
2171     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2172     expect(TRUE, ret);
2173     ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2174 
2175     item.hItem = hChild;
2176     item.mask = TVIF_STATE;
2177     item.state = INDEXTOSTATEIMAGEMASK(2);
2178     item.stateMask = TVIS_STATEIMAGEMASK;
2179     ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
2180     expect(TRUE, ret);
2181 
2182     item.hItem = hChild;
2183     item.mask = TVIF_STATE;
2184     item.state = 0;
2185     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2186     expect(TRUE, ret);
2187     ok(item.state == INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item.state);
2188 
2189     while(GetMessageA(&msg, 0, 0, 0))
2190     {
2191         TranslateMessage(&msg);
2192         DispatchMessageA(&msg);
2193 
2194         if((msg.hwnd == hTree) && (msg.message == WM_PAINT))
2195             break;
2196     }
2197 
2198     item.hItem = hChild;
2199     item.mask = TVIF_STATE;
2200     item.state = 0;
2201     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2202     expect(TRUE, ret);
2203     ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2204 
2205     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2206     ok(himl != NULL, "got %p\n", himl);
2207 
2208     DestroyWindow(hTree);
2209 
2210     /* check what happens if TVSIL_STATE image list is removed */
2211     hTree = create_treeview_control(0);
2212     fill_tree(hTree);
2213     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2214     ok(himl == NULL, "got %p\n", himl);
2215 
2216     SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_CHECKBOXES);
2217     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2218     ok(himl != NULL, "got %p\n", himl);
2219 
2220     himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_SETIMAGELIST, TVSIL_STATE, 0);
2221     ok(himl2 == himl, "got %p\n", himl2);
2222 
2223     himl2 = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2224     ok(himl2 == NULL, "got %p\n", himl2);
2225 
2226     item.hItem = hChild;
2227     item.mask = TVIF_STATE;
2228     item.state = INDEXTOSTATEIMAGEMASK(2);
2229     item.stateMask = TVIS_STATEIMAGEMASK;
2230     ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
2231     expect(TRUE, ret);
2232 
2233     item.hItem = hChild;
2234     item.mask = TVIF_STATE;
2235     item.state = 0;
2236     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2237     expect(TRUE, ret);
2238     ok(item.state == INDEXTOSTATEIMAGEMASK(2), "got 0x%x\n", item.state);
2239 
2240     while(GetMessageA(&msg, 0, 0, 0))
2241     {
2242         TranslateMessage(&msg);
2243         DispatchMessageA(&msg);
2244 
2245         if((msg.hwnd == hTree) && (msg.message == WM_PAINT))
2246             break;
2247     }
2248 
2249     item.hItem = hChild;
2250     item.mask = TVIF_STATE;
2251     item.state = 0;
2252     ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
2253     expect(TRUE, ret);
2254     ok(item.state == INDEXTOSTATEIMAGEMASK(1), "got 0x%x\n", item.state);
2255 
2256     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
2257     ok(himl != NULL, "got %p\n", himl);
2258 
2259     DestroyWindow(hTree);
2260 }
2261 
2262 static void test_TVM_GETNEXTITEM(void)
2263 {
2264     HTREEITEM item;
2265     HWND hTree;
2266 
2267     hTree = create_treeview_control(0);
2268     fill_tree(hTree);
2269 
2270     item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, 0);
2271     ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2272 
2273     item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)TVI_ROOT);
2274     ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2275 
2276     item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)hRoot);
2277     ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2278 
2279     item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)hChild);
2280     ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2281 
2282     item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, 0);
2283     ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2284 
2285     item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)hRoot);
2286     ok(item == hChild, "got %p, expected %p\n", item, hChild);
2287 
2288     item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)TVI_ROOT);
2289     ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2290 
2291     item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_PARENT, 0);
2292     ok(item == NULL, "got %p\n", item);
2293 
2294     item = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)hChild);
2295     ok(item == hRoot, "got %p, expected %p\n", item, hRoot);
2296 
2297     DestroyWindow(hTree);
2298 }
2299 
2300 static void test_TVM_HITTEST(void)
2301 {
2302     HWND hTree;
2303     LRESULT ret;
2304     RECT rc;
2305     TVHITTESTINFO ht;
2306 
2307     hTree = create_treeview_control(0);
2308     fill_tree(hTree);
2309 
2310     *(HTREEITEM*)&rc = hRoot;
2311     ret = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc);
2312     expect(TRUE, (BOOL)ret);
2313 
2314     ht.pt.x = rc.left-1;
2315     ht.pt.y = rc.top;
2316 
2317     ret = SendMessageA(hTree, TVM_HITTEST, 0, (LPARAM)&ht);
2318     ok((HTREEITEM)ret == hRoot, "got %p, expected %p\n", (HTREEITEM)ret, hRoot);
2319     ok(ht.hItem == hRoot, "got %p, expected %p\n", ht.hItem, hRoot);
2320     ok(ht.flags == TVHT_ONITEMBUTTON, "got %d, expected %d\n", ht.flags, TVHT_ONITEMBUTTON);
2321 
2322     ret = SendMessageA(hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)hRoot);
2323     expect(TRUE, (BOOL)ret);
2324 
2325     *(HTREEITEM*)&rc = hChild;
2326     ret = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc);
2327     expect(TRUE, (BOOL)ret);
2328 
2329     ht.pt.x = rc.left-1;
2330     ht.pt.y = rc.top;
2331 
2332     ret = SendMessageA(hTree, TVM_HITTEST, 0, (LPARAM)&ht);
2333     ok((HTREEITEM)ret == hChild, "got %p, expected %p\n", (HTREEITEM)ret, hChild);
2334     ok(ht.hItem == hChild, "got %p, expected %p\n", ht.hItem, hChild);
2335     /* Wine returns item button here, but this item has no button */
2336     todo_wine ok(ht.flags == TVHT_ONITEMINDENT, "got %d, expected %d\n", ht.flags, TVHT_ONITEMINDENT);
2337 
2338     DestroyWindow(hTree);
2339 }
2340 
2341 static void test_WM_GETDLGCODE(void)
2342 {
2343     DWORD code;
2344     HWND hTree;
2345 
2346     hTree = create_treeview_control(0);
2347 
2348     code = SendMessageA(hTree, WM_GETDLGCODE, VK_TAB, 0);
2349     ok(code == (DLGC_WANTCHARS | DLGC_WANTARROWS), "0x%08x\n", code);
2350 
2351     DestroyWindow(hTree);
2352 }
2353 
2354 static void test_customdraw(void)
2355 {
2356     LOGFONTA lf;
2357     HWND hwnd;
2358 
2359     hwnd = create_treeview_control(0);
2360     fill_tree(hwnd);
2361     SendMessageA(hwnd, TVM_EXPAND, TVE_EXPAND, (WPARAM)hRoot);
2362 
2363     /* create additional font, custom draw handler will select it */
2364     SystemParametersInfoA(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0);
2365     lf.lfHeight *= 2;
2366     g_customdraw_font = CreateFontIndirectA(&lf);
2367     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2368     InvalidateRect(hwnd, NULL, TRUE);
2369     UpdateWindow(hwnd);
2370     ok_sequence(sequences, PARENT_CD_SEQ_INDEX, parent_cd_seq, "custom draw notifications", FALSE);
2371     DeleteObject(g_customdraw_font);
2372     g_customdraw_font = NULL;
2373 
2374     DestroyWindow(hwnd);
2375 }
2376 
2377 static void test_WM_KEYDOWN(void)
2378 {
2379     static const char *rootA = "root";
2380     TVINSERTSTRUCTA ins;
2381     HTREEITEM hRoot;
2382     HWND hwnd;
2383 
2384     hwnd = create_treeview_control(0);
2385 
2386     ins.hParent = TVI_ROOT;
2387     ins.hInsertAfter = TVI_ROOT;
2388     U(ins).item.mask = TVIF_TEXT;
2389     U(ins).item.pszText = (char*)rootA;
2390     hRoot = TreeView_InsertItemA(hwnd, &ins);
2391     ok(hRoot != NULL, "got %p\n", hRoot);
2392 
2393     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2394     SendMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0);
2395     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_vk_return_seq, "WM_KEYDOWN/VK_RETURN parent notification", TRUE);
2396 
2397     DestroyWindow(hwnd);
2398 }
2399 
2400 static void test_TVS_FULLROWSELECT(void)
2401 {
2402     DWORD style;
2403     HWND hwnd;
2404 
2405     /* try to create both with TVS_HASLINES and TVS_FULLROWSELECT */
2406     hwnd = create_treeview_control(TVS_FULLROWSELECT);
2407 
2408     style = GetWindowLongA(hwnd, GWL_STYLE);
2409     ok((style & (TVS_FULLROWSELECT | TVS_HASLINES)) == (TVS_FULLROWSELECT | TVS_HASLINES), "got style 0x%08x\n", style);
2410 
2411     DestroyWindow(hwnd);
2412 
2413     /* create just with TVS_HASLINES, try to enable TVS_FULLROWSELECT later */
2414     hwnd = create_treeview_control(0);
2415 
2416     style = GetWindowLongA(hwnd, GWL_STYLE);
2417     SetWindowLongA(hwnd, GWL_STYLE, style | TVS_FULLROWSELECT);
2418     style = GetWindowLongA(hwnd, GWL_STYLE);
2419     ok(style & TVS_FULLROWSELECT, "got style 0x%08x\n", style);
2420 
2421     DestroyWindow(hwnd);
2422 }
2423 
2424 static void get_item_names_string(HWND hwnd, HTREEITEM item, char *str)
2425 {
2426     TVITEMA tvitem = { 0 };
2427     HTREEITEM child;
2428     char name[16];
2429 
2430     if (!item)
2431     {
2432         item = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0);
2433         str[0] = 0;
2434     }
2435 
2436     child = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)item);
2437 
2438     tvitem.mask = TVIF_TEXT;
2439     tvitem.hItem = item;
2440     tvitem.pszText = name;
2441     tvitem.cchTextMax = sizeof(name);
2442     SendMessageA(hwnd, TVM_GETITEMA, 0, (LPARAM)&tvitem);
2443     strcat(str, tvitem.pszText);
2444 
2445     while (child != NULL)
2446     {
2447         get_item_names_string(hwnd, child, str);
2448         child = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)child);
2449     }
2450 }
2451 
2452 static void fill_treeview_sort_test(HWND hwnd)
2453 {
2454     static const char *itemnames[] =
2455     {
2456         "root", "Wasp", "Caribou", "Vacuum",
2457         "Ocelot", "Newspaper", "Litter bin"
2458     };
2459 
2460     HTREEITEM root, children[2];
2461     TVINSERTSTRUCTA ins;
2462     unsigned i = 0;
2463 
2464     SendMessageA(hwnd, TVM_DELETEITEM, 0, 0);
2465 
2466     /* root, two children, with two children each */
2467     ins.hParent = TVI_ROOT;
2468     ins.hInsertAfter = TVI_ROOT;
2469     U(ins).item.mask = TVIF_TEXT;
2470     U(ins).item.pszText = (char *)itemnames[i++];
2471     root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2472 
2473     ins.hParent = root;
2474     ins.hInsertAfter = TVI_LAST;
2475     U(ins).item.mask = TVIF_TEXT;
2476     U(ins).item.pszText = (char *)itemnames[i++];
2477     children[0] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2478 
2479     U(ins).item.pszText = (char *)itemnames[i++];
2480     children[1] = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2481 
2482     ins.hParent = children[0];
2483     U(ins).item.pszText = (char *)itemnames[i++];
2484     SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2485 
2486     U(ins).item.pszText = (char *)itemnames[i++];
2487     SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2488 
2489     ins.hParent = children[1];
2490     U(ins).item.pszText = (char *)itemnames[i++];
2491     SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2492 
2493     U(ins).item.pszText = (char *)itemnames[i++];
2494     SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2495 }
2496 
2497 static void test_TVM_SORTCHILDREN(void)
2498 {
2499     static const char *initial_order = "rootWaspVacuumOcelotCaribouNewspaperLitter bin";
2500     static const char *sorted_order = "rootCaribouNewspaperLitter binWaspVacuumOcelot";
2501     TVINSERTSTRUCTA ins;
2502     char buff[256];
2503     HTREEITEM root;
2504     HWND hwnd;
2505     BOOL ret;
2506 
2507     hwnd = create_treeview_control(0);
2508 
2509     /* call on empty tree */
2510     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, 0);
2511     ok(!ret, "Unexpected ret value %d\n", ret);
2512 
2513     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)TVI_ROOT);
2514     ok(!ret, "Unexpected ret value %d\n", ret);
2515 
2516     /* add only root, sort from it */
2517     ins.hParent = TVI_ROOT;
2518     ins.hInsertAfter = TVI_ROOT;
2519     U(ins).item.mask = TVIF_TEXT;
2520     U(ins).item.pszText = (char *)"root";
2521     root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2522     ok(root != NULL, "Expected root node\n");
2523 
2524     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)root);
2525     ok(!ret, "Unexpected ret value %d\n", ret);
2526 
2527     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root);
2528     ok(!ret, "Unexpected ret value %d\n", ret);
2529 
2530     /* root, two children, with two children each */
2531     fill_treeview_sort_test(hwnd);
2532     get_item_names_string(hwnd, NULL, buff);
2533     ok(!strcmp(buff, initial_order), "Wrong initial order %s, expected %s\n", buff, initial_order);
2534 
2535     /* with NULL item nothing is sorted */
2536     fill_treeview_sort_test(hwnd);
2537     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, 0);
2538 todo_wine
2539     ok(ret, "Unexpected ret value %d\n", ret);
2540     get_item_names_string(hwnd, NULL, buff);
2541     ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order);
2542 
2543     /* TVI_ROOT as item */
2544     fill_treeview_sort_test(hwnd);
2545     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)TVI_ROOT);
2546 todo_wine
2547     ok(ret, "Unexpected ret value %d\n", ret);
2548     get_item_names_string(hwnd, NULL, buff);
2549     ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, initial_order);
2550 
2551     /* zero WPARAM, item is specified */
2552     fill_treeview_sort_test(hwnd);
2553     root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0);
2554     ok(root != NULL, "Failed to get root item\n");
2555     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, 0, (LPARAM)root);
2556     ok(ret, "Unexpected ret value %d\n", ret);
2557     get_item_names_string(hwnd, NULL, buff);
2558     ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
2559 
2560     /* non-zero WPARAM, NULL item */
2561     fill_treeview_sort_test(hwnd);
2562     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, 0);
2563 todo_wine
2564     ok(ret, "Unexpected ret value %d\n", ret);
2565     get_item_names_string(hwnd, NULL, buff);
2566     ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
2567 
2568     /* TVI_ROOT as item */
2569     fill_treeview_sort_test(hwnd);
2570     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)TVI_ROOT);
2571 todo_wine
2572     ok(ret, "Unexpected ret value %d\n", ret);
2573     get_item_names_string(hwnd, NULL, buff);
2574     ok(!strcmp(buff, initial_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
2575 
2576     /* non-zero WPARAM, item is specified */
2577     fill_treeview_sort_test(hwnd);
2578     root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0);
2579     ok(root != NULL, "Failed to get root item\n");
2580     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root);
2581     ok(ret, "Unexpected ret value %d\n", ret);
2582     get_item_names_string(hwnd, NULL, buff);
2583     ok(!strcmp(buff, sorted_order), "Wrong sorted order %s, expected %s\n", buff, sorted_order);
2584 
2585     /* case insensitive comparison */
2586     SendMessageA(hwnd, TVM_DELETEITEM, 0, 0);
2587 
2588     ins.hParent = TVI_ROOT;
2589     ins.hInsertAfter = TVI_ROOT;
2590     U(ins).item.mask = TVIF_TEXT;
2591     U(ins).item.pszText = (char *)"root";
2592     root = (HTREEITEM)SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2593     ok(root != NULL, "Expected root node\n");
2594 
2595     ins.hParent = root;
2596     ins.hInsertAfter = TVI_LAST;
2597     U(ins).item.pszText = (char *)"I1";
2598     SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2599 
2600     ins.hParent = root;
2601     ins.hInsertAfter = TVI_LAST;
2602     U(ins).item.pszText = (char *)"i1";
2603     SendMessageA(hwnd, TVM_INSERTITEMA, 0, (LPARAM)&ins);
2604 
2605     ret = SendMessageA(hwnd, TVM_SORTCHILDREN, TRUE, (LPARAM)root);
2606     ok(ret, "Unexpected ret value %d\n", ret);
2607     get_item_names_string(hwnd, NULL, buff);
2608     ok(!strcmp(buff, "rootI1i1"), "Wrong sorted order %s\n", buff);
2609 
2610     DestroyWindow(hwnd);
2611 }
2612 
2613 static void test_right_click(void)
2614 {
2615     HWND hTree;
2616     HTREEITEM selected;
2617     RECT rc;
2618     LRESULT result;
2619     POINT pt;
2620 
2621     hTree = create_treeview_control(0);
2622     fill_tree(hTree);
2623 
2624     SendMessageA(hTree, TVM_ENSUREVISIBLE, 0, (LPARAM)hChild);
2625     SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hChild);
2626     selected = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0);
2627     ok(selected == hChild, "child item not selected\n");
2628 
2629     *(HTREEITEM *)&rc = hRoot;
2630     result = SendMessageA(hTree, TVM_GETITEMRECT, TRUE, (LPARAM)&rc);
2631     ok(result, "TVM_GETITEMRECT failed\n");
2632 
2633     flush_events();
2634 
2635     pt.x = (rc.left + rc.right) / 2;
2636     pt.y = (rc.top + rc.bottom) / 2;
2637     ClientToScreen(hMainWnd, &pt);
2638 
2639     flush_events();
2640     flush_sequences(sequences, NUM_MSG_SEQUENCES);
2641 
2642     PostMessageA(hTree, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(pt.x, pt.y));
2643     PostMessageA(hTree, WM_RBUTTONUP, 0, MAKELPARAM(pt.x, pt.y));
2644 
2645     flush_events();
2646 
2647     ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_right_click_seq, "right click sequence", FALSE);
2648     ok_sequence(sequences, PARENT_SEQ_INDEX, parent_right_click_seq, "parent right click sequence", FALSE);
2649 
2650     selected = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0);
2651     ok(selected == hChild, "child item should still be selected\n");
2652 
2653     DestroyWindow(hTree);
2654 }
2655 
2656 START_TEST(treeview)
2657 {
2658     HMODULE hComctl32;
2659     BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
2660     WNDCLASSA wc;
2661     MSG msg;
2662 
2663     ULONG_PTR ctx_cookie;
2664     HANDLE hCtx;
2665 
2666     hComctl32 = GetModuleHandleA("comctl32.dll");
2667     pInitCommonControlsEx = (void*)GetProcAddress(hComctl32, "InitCommonControlsEx");
2668     if (pInitCommonControlsEx)
2669     {
2670         INITCOMMONCONTROLSEX iccex;
2671         iccex.dwSize = sizeof(iccex);
2672         iccex.dwICC  = ICC_TREEVIEW_CLASSES;
2673         pInitCommonControlsEx(&iccex);
2674     }
2675     else
2676         InitCommonControls();
2677 
2678     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
2679     init_msg_sequences(item_sequence, 1);
2680 
2681     wc.style = CS_HREDRAW | CS_VREDRAW;
2682     wc.cbClsExtra = 0;
2683     wc.cbWndExtra = 0;
2684     wc.hInstance = GetModuleHandleA(NULL);
2685     wc.hIcon = NULL;
2686     wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_IBEAM);
2687     wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
2688     wc.lpszMenuName = NULL;
2689     wc.lpszClassName = "MyTestWnd";
2690     wc.lpfnWndProc = parent_wnd_proc;
2691     RegisterClassA(&wc);
2692 
2693     hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW,
2694       CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
2695 
2696     ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n");
2697     if (!hMainWnd) return;
2698 
2699     test_fillroot();
2700     test_select();
2701     test_getitemtext();
2702     test_focus();
2703     test_get_set_bkcolor();
2704     test_get_set_imagelist();
2705     test_get_set_indent();
2706     test_get_set_insertmark();
2707     test_get_set_item();
2708     test_get_set_itemheight();
2709     test_get_set_scrolltime();
2710     test_get_set_textcolor();
2711     test_get_linecolor();
2712     test_get_insertmarkcolor();
2713     test_get_set_tooltips();
2714     test_get_set_unicodeformat();
2715     test_callback();
2716     test_expandinvisible();
2717     test_itemedit();
2718     test_treeview_classinfo();
2719     test_expandnotify();
2720     test_TVS_SINGLEEXPAND();
2721     test_WM_PAINT();
2722     test_delete_items();
2723     test_cchildren();
2724     test_htreeitem_layout();
2725     test_TVS_CHECKBOXES();
2726     test_TVM_GETNEXTITEM();
2727     test_TVM_HITTEST();
2728     test_WM_GETDLGCODE();
2729     test_customdraw();
2730     test_WM_KEYDOWN();
2731     test_TVS_FULLROWSELECT();
2732     test_TVM_SORTCHILDREN();
2733     test_right_click();
2734 
2735     if (!load_v6_module(&ctx_cookie, &hCtx))
2736     {
2737         DestroyWindow(hMainWnd);
2738         return;
2739     }
2740 
2741     /* comctl32 version 6 tests start here */
2742     g_v6 = TRUE;
2743     test_expandedimage();
2744     test_htreeitem_layout();
2745     test_WM_GETDLGCODE();
2746 
2747     unload_v6_module(ctx_cookie, hCtx);
2748 
2749     PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
2750     while(GetMessageA(&msg, 0, 0, 0))
2751     {
2752         TranslateMessage(&msg);
2753         DispatchMessageA(&msg);
2754     }
2755 }
2756