From b413a937933027f3c87a3f2950762c2b44b41981 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 1 Feb 2018 10:09:03 +0300 Subject: [PATCH] comctl32/treeview: Fix tooltip window leak. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/comctl32/tests/treeview.c | 114 ++++++++++++++++++++++++++++++--- dlls/comctl32/treeview.c | 3 +- 2 files changed, 106 insertions(+), 11 deletions(-) diff --git a/dlls/comctl32/tests/treeview.c b/dlls/comctl32/tests/treeview.c index 64fb1ebcd5e..45bcb740a08 100644 --- a/dlls/comctl32/tests/treeview.c +++ b/dlls/comctl32/tests/treeview.c @@ -1069,9 +1069,101 @@ static void test_get_set_textcolor(void) static void test_get_set_tooltips(void) { - HWND hwndLastToolTip = NULL; - HWND hPopupTreeView; - HWND hTree; + HWND hTree, tooltips, hwnd; + DWORD style; + int i; + + /* TVS_NOTOOLTIPS */ + hTree = create_treeview_control(TVS_NOTOOLTIPS); + + tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); + ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips); + + tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0); + ok(tooltips == NULL, "Unexpected ret value %p.\n", tooltips); + + /* Toggle style */ + style = GetWindowLongA(hTree, GWL_STYLE); + SetWindowLongA(hTree, GWL_STYLE, style & ~TVS_NOTOOLTIPS); + + tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); + ok(IsWindow(tooltips), "Unexpected tooltip window %p.\n", tooltips); + + style = GetWindowLongA(hTree, GWL_STYLE); + SetWindowLongA(hTree, GWL_STYLE, style | TVS_NOTOOLTIPS); + + tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); + ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips); + + DestroyWindow(hTree); + + /* Set some valid window, does not have to be tooltips class. */ + hTree = create_treeview_control(TVS_NOTOOLTIPS); + + hwnd = CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD, 5, 5, 100, 100, hMainWnd, NULL, NULL, 0); + ok(hwnd != NULL, "Failed to create child window.\n"); + + tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0); + ok(tooltips == NULL, "Unexpected ret value %p.\n", tooltips); + + tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); + ok(tooltips == hwnd, "Unexpected tooltip window %p.\n", tooltips); + + /* Externally set tooltips window, disable style. */ + style = GetWindowLongA(hTree, GWL_STYLE); + SetWindowLongA(hTree, GWL_STYLE, style & ~TVS_NOTOOLTIPS); + + tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); + ok(IsWindow(tooltips) && tooltips != hwnd, "Unexpected tooltip window %p.\n", tooltips); + ok(IsWindow(hwnd), "Expected valid window.\n"); + + style = GetWindowLongA(hTree, GWL_STYLE); + SetWindowLongA(hTree, GWL_STYLE, style | TVS_NOTOOLTIPS); + ok(!IsWindow(tooltips), "Unexpected tooltip window %p.\n", tooltips); + + tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); + ok(tooltips == NULL, "Unexpected tooltip window %p.\n", tooltips); + ok(IsWindow(hwnd), "Expected valid window.\n"); + + DestroyWindow(hTree); + ok(IsWindow(hwnd), "Expected valid window.\n"); + + /* Set window, disable tooltips. */ + hTree = create_treeview_control(0); + + tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0); + ok(IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips); + + style = GetWindowLongA(hTree, GWL_STYLE); + SetWindowLongA(hTree, GWL_STYLE, style | TVS_NOTOOLTIPS); + ok(!IsWindow(hwnd), "Unexpected tooltip window %p.\n", tooltips); + ok(IsWindow(tooltips), "Expected valid window %p.\n", tooltips); + + DestroyWindow(hTree); + ok(IsWindow(tooltips), "Expected valid window %p.\n", tooltips); + DestroyWindow(tooltips); + DestroyWindow(hwnd); + + for (i = 0; i < 2; i++) + { + DWORD style = i == 0 ? 0 : TVS_NOTOOLTIPS; + + hwnd = CreateWindowA(WC_STATICA, "Test", WS_VISIBLE|WS_CHILD, 5, 5, 100, 100, hMainWnd, NULL, NULL, 0); + ok(hwnd != NULL, "Failed to create child window.\n"); + + hTree = create_treeview_control(style); + + tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, (WPARAM)hwnd, 0); + ok(style & TVS_NOTOOLTIPS ? tooltips == NULL : IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips); + DestroyWindow(tooltips); + + tooltips = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); + ok(tooltips == hwnd, "Unexpected tooltip window %p.\n", tooltips); + + /* TreeView is destroyed, check if set window is still around. */ + DestroyWindow(hTree); + ok(!IsWindow(hwnd), "Unexpected window.\n"); + } hTree = create_treeview_control(0); fill_tree(hTree); @@ -1079,20 +1171,23 @@ static void test_get_set_tooltips(void) flush_sequences(sequences, NUM_MSG_SEQUENCES); /* show even WS_POPUP treeview don't send NM_TOOLTIPSCREATED */ - hPopupTreeView = CreateWindowA(WC_TREEVIEWA, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, + hwnd = CreateWindowA(WC_TREEVIEWA, NULL, WS_POPUP|WS_VISIBLE, 0, 0, 100, 100, hMainWnd, NULL, NULL, NULL); - DestroyWindow(hPopupTreeView); + DestroyWindow(hwnd); /* Testing setting a NULL ToolTip */ - SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0); - hwndLastToolTip = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); - ok(hwndLastToolTip == NULL, "NULL tool tip, reported as 0x%p, expected 0.\n", hwndLastToolTip); + tooltips = (HWND)SendMessageA(hTree, TVM_SETTOOLTIPS, 0, 0); + ok(IsWindow(tooltips), "Unexpected ret value %p.\n", tooltips); + + hwnd = (HWND)SendMessageA(hTree, TVM_GETTOOLTIPS, 0, 0); + ok(hwnd == NULL, "Unexpected tooltip window %p.\n", hwnd); ok_sequence(sequences, TREEVIEW_SEQ_INDEX, test_get_set_tooltips_seq, "test get set tooltips", TRUE); - /* TODO: Add a test of an actual tooltip */ DestroyWindow(hTree); + ok(IsWindow(tooltips), "Expected valid window.\n"); + DestroyWindow(tooltips); } static void test_get_set_unicodeformat(void) @@ -2754,6 +2849,7 @@ START_TEST(treeview) test_expandedimage(); test_htreeitem_layout(); test_WM_GETDLGCODE(); + test_get_set_tooltips(); unload_v6_module(ctx_cookie, hCtx); } diff --git a/dlls/comctl32/treeview.c b/dlls/comctl32/treeview.c index 9a37cf331b4..7713efb70ca 100644 --- a/dlls/comctl32/treeview.c +++ b/dlls/comctl32/treeview.c @@ -5188,8 +5188,6 @@ TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr) TREEVIEW_FreeItem(infoPtr, infoPtr->root); DPA_Destroy(infoPtr->items); - /* tool tip is automatically destroyed: we are its owner */ - /* Restore original wndproc */ if (infoPtr->hwndEdit) SetWindowLongPtrW(infoPtr->hwndEdit, GWLP_WNDPROC, @@ -5204,6 +5202,7 @@ TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr) DeleteObject(infoPtr->hBoldFont); DeleteObject(infoPtr->hUnderlineFont); DeleteObject(infoPtr->hBoldUnderlineFont); + DestroyWindow(infoPtr->hwndToolTip); Free(infoPtr); return 0;