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