1 /*
2  * Copyright 2005 Dmitry Timoshkov
3  * Copyright 2008 Jason Edmeades
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include <windows.h>
21 #include <commctrl.h>
22 
23 #include "resources.h"
24 
25 #include "wine/test.h"
26 
27 #include "v6util.h"
28 #include "msg.h"
29 
30 #define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
31 
32 enum seq_index
33 {
34     PARENT_SEQ_INDEX = 0,
35     NUM_MSG_SEQUENCES
36 };
37 
38 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
39 
40 static void test_create_tooltip(BOOL is_v6)
41 {
42     HWND parent, hwnd;
43     DWORD style, exp_style;
44 
45     parent = CreateWindowExA(0, "static", NULL, WS_POPUP,
46                           0, 0, 0, 0,
47                           NULL, NULL, NULL, 0);
48     ok(parent != NULL, "failed to create parent wnd\n");
49 
50     hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0x7fffffff | WS_POPUP,
51                           10, 10, 300, 100,
52                           parent, NULL, NULL, 0);
53     ok(hwnd != NULL, "failed to create tooltip wnd\n");
54 
55     style = GetWindowLongA(hwnd, GWL_STYLE);
56     exp_style = 0x7fffffff | WS_POPUP;
57     exp_style &= ~(WS_CHILD | WS_MAXIMIZE | WS_BORDER | WS_DLGFRAME);
58     ok(style == exp_style || broken(style == (exp_style | WS_BORDER)), /* nt4 */
59        "wrong style %08x/%08x\n", style, exp_style);
60 
61     DestroyWindow(hwnd);
62 
63     hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
64                           10, 10, 300, 100,
65                           parent, NULL, NULL, 0);
66     ok(hwnd != NULL, "failed to create tooltip wnd\n");
67 
68     style = GetWindowLongA(hwnd, GWL_STYLE);
69     exp_style = WS_POPUP | WS_CLIPSIBLINGS;
70     if (!is_v6)
71         exp_style |= WS_BORDER;
72 todo_wine_if(is_v6)
73     ok(style == exp_style || broken(style == (exp_style | WS_BORDER)) /* XP */,
74         "Unexpected window style %#x.\n", style);
75 
76     DestroyWindow(hwnd);
77 
78     DestroyWindow(parent);
79 }
80 
81 /* try to make sure pending X events have been processed before continuing */
82 static void flush_events(int waitTime)
83 {
84     MSG msg;
85     int diff = waitTime;
86     DWORD time = GetTickCount() + waitTime;
87 
88     while (diff > 0)
89     {
90         if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(100,diff), QS_ALLEVENTS) == WAIT_TIMEOUT) break;
91         while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
92         diff = time - GetTickCount();
93     }
94 }
95 
96 static int CD_Stages;
97 static LRESULT CD_Result;
98 static HWND g_hwnd;
99 
100 #define TEST_CDDS_PREPAINT           0x00000001
101 #define TEST_CDDS_POSTPAINT          0x00000002
102 #define TEST_CDDS_PREERASE           0x00000004
103 #define TEST_CDDS_POSTERASE          0x00000008
104 #define TEST_CDDS_ITEMPREPAINT       0x00000010
105 #define TEST_CDDS_ITEMPOSTPAINT      0x00000020
106 #define TEST_CDDS_ITEMPREERASE       0x00000040
107 #define TEST_CDDS_ITEMPOSTERASE      0x00000080
108 #define TEST_CDDS_SUBITEM            0x00000100
109 
110 static LRESULT CALLBACK custom_draw_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
111 {
112     switch(msg) {
113 
114     case WM_DESTROY:
115         PostQuitMessage(0);
116         break;
117 
118     case WM_NOTIFY:
119         if (((NMHDR *)lParam)->code == NM_CUSTOMDRAW) {
120             NMTTCUSTOMDRAW *ttcd = (NMTTCUSTOMDRAW*) lParam;
121             ok(ttcd->nmcd.hdr.hwndFrom == g_hwnd, "Unexpected hwnd source %p (%p)\n",
122                  ttcd->nmcd.hdr.hwndFrom, g_hwnd);
123             ok(ttcd->nmcd.hdr.idFrom == 0x1234ABCD, "Unexpected id %x\n", (int)ttcd->nmcd.hdr.idFrom);
124 
125             switch (ttcd->nmcd.dwDrawStage) {
126             case CDDS_PREPAINT     : CD_Stages |= TEST_CDDS_PREPAINT; break;
127             case CDDS_POSTPAINT    : CD_Stages |= TEST_CDDS_POSTPAINT; break;
128             case CDDS_PREERASE     : CD_Stages |= TEST_CDDS_PREERASE; break;
129             case CDDS_POSTERASE    : CD_Stages |= TEST_CDDS_POSTERASE; break;
130             case CDDS_ITEMPREPAINT : CD_Stages |= TEST_CDDS_ITEMPREPAINT; break;
131             case CDDS_ITEMPOSTPAINT: CD_Stages |= TEST_CDDS_ITEMPOSTPAINT; break;
132             case CDDS_ITEMPREERASE : CD_Stages |= TEST_CDDS_ITEMPREERASE; break;
133             case CDDS_ITEMPOSTERASE: CD_Stages |= TEST_CDDS_ITEMPOSTERASE; break;
134             case CDDS_SUBITEM      : CD_Stages |= TEST_CDDS_SUBITEM; break;
135             default: CD_Stages = -1;
136             }
137 
138             if (ttcd->nmcd.dwDrawStage == CDDS_PREPAINT) return CD_Result;
139         }
140         /* drop through */
141 
142     default:
143         return DefWindowProcA(hWnd, msg, wParam, lParam);
144     }
145 
146     return 0L;
147 }
148 
149 static void test_customdraw(void) {
150     static struct {
151         LRESULT FirstReturnValue;
152         int ExpectedCalls;
153     } expectedResults[] = {
154         /* Valid notification responses */
155         {CDRF_DODEFAULT, TEST_CDDS_PREPAINT},
156         {CDRF_SKIPDEFAULT, TEST_CDDS_PREPAINT},
157         {CDRF_NOTIFYPOSTPAINT, TEST_CDDS_PREPAINT | TEST_CDDS_POSTPAINT},
158 
159         /* Invalid notification responses */
160         {CDRF_NOTIFYITEMDRAW, TEST_CDDS_PREPAINT},
161         {CDRF_NOTIFYPOSTERASE, TEST_CDDS_PREPAINT},
162         {CDRF_NEWFONT, TEST_CDDS_PREPAINT}
163     };
164 
165    DWORD       iterationNumber;
166    WNDCLASSA wc;
167    POINT orig_pos;
168    LRESULT ret;
169 
170    /* Create a class to use the custom draw wndproc */
171    wc.style = CS_HREDRAW | CS_VREDRAW;
172    wc.cbClsExtra = 0;
173    wc.cbWndExtra = 0;
174    wc.hInstance = GetModuleHandleA(NULL);
175    wc.hIcon = NULL;
176    wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
177    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
178    wc.lpszMenuName = NULL;
179    wc.lpszClassName = "CustomDrawClass";
180    wc.lpfnWndProc = custom_draw_wnd_proc;
181    RegisterClassA(&wc);
182 
183    GetCursorPos(&orig_pos);
184 
185    for (iterationNumber = 0;
186         iterationNumber < ARRAY_SIZE(expectedResults);
187         iterationNumber++) {
188 
189        HWND parent, hwndTip;
190        RECT rect;
191        TTTOOLINFOA toolInfo = { 0 };
192 
193        /* Create a main window */
194        parent = CreateWindowExA(0, "CustomDrawClass", NULL,
195                                WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
196                                WS_MAXIMIZEBOX | WS_VISIBLE,
197                                50, 50,
198                                300, 300,
199                                NULL, NULL, NULL, 0);
200        ok(parent != NULL, "%d: Creation of main window failed\n", iterationNumber);
201 
202        /* Make it show */
203        ShowWindow(parent, SW_SHOWNORMAL);
204        flush_events(100);
205 
206        /* Create Tooltip */
207        hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
208                                 NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
209                                 CW_USEDEFAULT, CW_USEDEFAULT,
210                                 CW_USEDEFAULT, CW_USEDEFAULT,
211                                 parent, NULL, GetModuleHandleA(NULL), 0);
212        ok(hwndTip != NULL, "%d: Creation of tooltip window failed\n", iterationNumber);
213 
214        /* Set up parms for the wndproc to handle */
215        CD_Stages = 0;
216        CD_Result = expectedResults[iterationNumber].FirstReturnValue;
217        g_hwnd    = hwndTip;
218 
219        /* Make it topmost, as per the MSDN */
220        SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
221              SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
222 
223        /* Create a tool */
224        toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
225        toolInfo.hwnd = parent;
226        toolInfo.hinst = GetModuleHandleA(NULL);
227        toolInfo.uFlags = TTF_SUBCLASS;
228        toolInfo.uId = 0x1234ABCD;
229        toolInfo.lpszText = (LPSTR)"This is a test tooltip";
230        toolInfo.lParam = 0xdeadbeef;
231        GetClientRect (parent, &toolInfo.rect);
232        ret = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
233        ok(ret, "%d: Failed to add the tool.\n", iterationNumber);
234 
235        /* Make tooltip appear quickly */
236        SendMessageA(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
237 
238        /* Put cursor inside window, tooltip will appear immediately */
239        GetWindowRect( parent, &rect );
240        SetCursorPos( (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 );
241        flush_events(200);
242 
243        if (CD_Stages)
244        {
245            /* Check CustomDraw results */
246            ok(CD_Stages == expectedResults[iterationNumber].ExpectedCalls ||
247               broken(CD_Stages == (expectedResults[iterationNumber].ExpectedCalls & ~TEST_CDDS_POSTPAINT)), /* nt4 */
248               "%d: CustomDraw stages %x, expected %x\n", iterationNumber, CD_Stages,
249               expectedResults[iterationNumber].ExpectedCalls);
250        }
251 
252        ret = SendMessageA(hwndTip, TTM_GETCURRENTTOOLA, 0, 0);
253        ok(ret, "%d: Failed to get current tool %#lx.\n", iterationNumber, ret);
254 
255        memset(&toolInfo, 0xcc, sizeof(toolInfo));
256        toolInfo.cbSize = sizeof(toolInfo);
257        toolInfo.lpszText = NULL;
258        toolInfo.lpReserved = (void *)0xdeadbeef;
259        SendMessageA(hwndTip, TTM_GETCURRENTTOOLA, 0, (LPARAM)&toolInfo);
260        ok(toolInfo.hwnd == parent, "%d: Unexpected hwnd %p.\n", iterationNumber, toolInfo.hwnd);
261        ok(toolInfo.hinst == GetModuleHandleA(NULL), "%d: Unexpected hinst %p.\n", iterationNumber, toolInfo.hinst);
262        ok(toolInfo.uId == 0x1234abcd, "%d: Unexpected uId %lx.\n", iterationNumber, toolInfo.uId);
263        ok(toolInfo.lParam == 0, "%d: Unexpected lParam %lx.\n", iterationNumber, toolInfo.lParam);
264        ok(toolInfo.lpReserved == (void *)0xdeadbeef, "%d: Unexpected lpReserved %p.\n", iterationNumber, toolInfo.lpReserved);
265 
266        /* Clean up */
267        DestroyWindow(hwndTip);
268        DestroyWindow(parent);
269    }
270 
271    SetCursorPos(orig_pos.x, orig_pos.y);
272 }
273 
274 static const CHAR testcallbackA[]  = "callback";
275 
276 static RECT g_ttip_rect;
277 static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
278 {
279     static LONG defwndproc_counter = 0;
280     struct message msg;
281     LRESULT ret;
282 
283     if (message == WM_NOTIFY && lParam)
284     {
285         NMTTDISPINFOA *ttnmdi = (NMTTDISPINFOA*)lParam;
286         NMHDR *hdr = (NMHDR *)lParam;
287         RECT rect;
288 
289         if (hdr->code != NM_CUSTOMDRAW)
290         {
291             msg.message = message;
292             msg.flags = sent|wparam|lparam;
293             if (defwndproc_counter) msg.flags |= defwinproc;
294             msg.wParam = wParam;
295             msg.lParam = lParam;
296             msg.id = hdr->code;
297             add_message(sequences, PARENT_SEQ_INDEX, &msg);
298         }
299 
300         switch (hdr->code)
301         {
302         case TTN_GETDISPINFOA:
303             lstrcpyA(ttnmdi->lpszText, testcallbackA);
304             break;
305         case TTN_SHOW:
306             GetWindowRect(hdr->hwndFrom, &rect);
307             ok(!EqualRect(&g_ttip_rect, &rect), "Unexpected window rectangle.\n");
308             break;
309         }
310     }
311 
312     defwndproc_counter++;
313     if (IsWindowUnicode(hwnd))
314         ret = DefWindowProcW(hwnd, message, wParam, lParam);
315     else
316         ret = DefWindowProcA(hwnd, message, wParam, lParam);
317     defwndproc_counter--;
318 
319     return ret;
320 }
321 
322 static void register_parent_wnd_class(void)
323 {
324     WNDCLASSA cls;
325     BOOL ret;
326 
327     cls.style = 0;
328     cls.lpfnWndProc = parent_wnd_proc;
329     cls.cbClsExtra = 0;
330     cls.cbWndExtra = 0;
331     cls.hInstance = GetModuleHandleA(NULL);
332     cls.hIcon = 0;
333     cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
334     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
335     cls.lpszMenuName = NULL;
336     cls.lpszClassName = "Tooltips test parent class";
337     ret = RegisterClassA(&cls);
338     ok(ret, "Failed to register test parent class.\n");
339 }
340 
341 static HWND create_parent_window(void)
342 {
343     return CreateWindowExA(0, "Tooltips test parent class",
344                           "Tooltips test parent window",
345                           WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
346                           WS_MAXIMIZEBOX | WS_VISIBLE,
347                           0, 0, 100, 100,
348                           GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
349 }
350 
351 static void test_gettext(void)
352 {
353     static const CHAR testtip2A[] = "testtip\ttest2";
354     static const CHAR testtipA[] = "testtip";
355     HWND hwnd, notify;
356     TTTOOLINFOA toolinfoA;
357     TTTOOLINFOW toolinfoW;
358     LRESULT r;
359     CHAR bufA[16] = "";
360     WCHAR bufW[10] = { 0 };
361     DWORD length, style;
362 
363     notify = create_parent_window();
364     ok(notify != NULL, "Expected notification window to be created\n");
365 
366     /* For bug 14790 - lpszText is NULL */
367     hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
368                            10, 10, 300, 100,
369                            NULL, NULL, NULL, 0);
370     ok(hwnd != NULL, "failed to create tooltip wnd\n");
371 
372     /* use sizeof(TTTOOLINFOA) instead of TTTOOLINFOA_V1_SIZE so that adding it fails on Win9x */
373     /* otherwise it crashes on the NULL lpszText */
374     toolinfoA.cbSize = sizeof(TTTOOLINFOA);
375     toolinfoA.hwnd = NULL;
376     toolinfoA.hinst = GetModuleHandleA(NULL);
377     toolinfoA.uFlags = 0;
378     toolinfoA.uId = 0x1234ABCD;
379     toolinfoA.lpszText = NULL;
380     toolinfoA.lParam = 0xdeadbeef;
381     GetClientRect(hwnd, &toolinfoA.rect);
382     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
383     ok(r, "got %ld\n", r);
384 
385     toolinfoA.hwnd = NULL;
386     toolinfoA.uId = 0x1234abcd;
387     toolinfoA.lpszText = bufA;
388     r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
389     ok(!r, "got %ld\n", r);
390     ok(!*toolinfoA.lpszText, "lpszText should be empty, got %s\n", toolinfoA.lpszText);
391 
392     toolinfoA.lpszText = bufA;
393     r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
394 todo_wine
395     ok(!r, "got %ld\n", r);
396     ok(toolinfoA.lpszText == NULL, "expected NULL, got %p\n", toolinfoA.lpszText);
397 
398     /* NULL hinst, valid resource id for text */
399     toolinfoA.cbSize = sizeof(TTTOOLINFOA);
400     toolinfoA.hwnd = NULL;
401     toolinfoA.hinst = NULL;
402     toolinfoA.uFlags = 0;
403     toolinfoA.uId = 0x1233abcd;
404     toolinfoA.lpszText = MAKEINTRESOURCEA(IDS_TBADD1);
405     toolinfoA.lParam = 0xdeadbeef;
406     GetClientRect(hwnd, &toolinfoA.rect);
407     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
408     ok(r, "failed to add a tool\n");
409 
410     toolinfoA.hwnd = NULL;
411     toolinfoA.uId = 0x1233abcd;
412     toolinfoA.lpszText = bufA;
413     r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
414     ok(!r, "got %ld\n", r);
415     ok(!strcmp(toolinfoA.lpszText, "abc"), "got wrong text, %s\n", toolinfoA.lpszText);
416 
417     toolinfoA.hinst = (HINSTANCE)0xdeadbee;
418     r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
419 todo_wine
420     ok(!r, "got %ld\n", r);
421     ok(toolinfoA.hinst == NULL, "expected NULL, got %p\n", toolinfoA.hinst);
422 
423     r = SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&toolinfoA);
424     ok(!r, "got %ld\n", r);
425 
426     /* add another tool with text */
427     toolinfoA.cbSize = sizeof(TTTOOLINFOA);
428     toolinfoA.hwnd = NULL;
429     toolinfoA.hinst = GetModuleHandleA(NULL);
430     toolinfoA.uFlags = 0;
431     toolinfoA.uId = 0x1235ABCD;
432     strcpy(bufA, testtipA);
433     toolinfoA.lpszText = bufA;
434     toolinfoA.lParam = 0xdeadbeef;
435     GetClientRect(hwnd, &toolinfoA.rect);
436     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
437     ok(r, "Adding the tool to the tooltip failed\n");
438 
439     length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
440     ok(length == 0, "Expected 0, got %d\n", length);
441 
442     toolinfoA.hwnd = NULL;
443     toolinfoA.uId = 0x1235abcd;
444     toolinfoA.lpszText = bufA;
445     r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
446     ok(!r, "got %ld\n", r);
447     ok(!strcmp(toolinfoA.lpszText, testtipA), "expected %s, got %p\n", testtipA, toolinfoA.lpszText);
448 
449     memset(bufA, 0x1f, sizeof(bufA));
450     toolinfoA.lpszText = bufA;
451     r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
452 todo_wine
453     ok(!r, "got %ld\n", r);
454     ok(!strcmp(toolinfoA.lpszText, testtipA), "expected %s, got %p\n", testtipA, toolinfoA.lpszText);
455 
456     length = SendMessageA(hwnd, WM_GETTEXTLENGTH, 0, 0);
457     ok(length == 0, "Expected 0, got %d\n", length);
458 
459     /* add another with callback text */
460     toolinfoA.cbSize = sizeof(TTTOOLINFOA);
461     toolinfoA.hwnd = notify;
462     toolinfoA.hinst = GetModuleHandleA(NULL);
463     toolinfoA.uFlags = 0;
464     toolinfoA.uId = 0x1236ABCD;
465     toolinfoA.lpszText = LPSTR_TEXTCALLBACKA;
466     toolinfoA.lParam = 0xdeadbeef;
467     GetClientRect(hwnd, &toolinfoA.rect);
468     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
469     ok(r, "Adding the tool to the tooltip failed\n");
470 
471     toolinfoA.hwnd = notify;
472     toolinfoA.uId = 0x1236abcd;
473     toolinfoA.lpszText = bufA;
474     r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
475     ok(!r, "got %ld\n", r);
476     ok(!strcmp(toolinfoA.lpszText, testcallbackA), "lpszText should be an (%s) string\n", testcallbackA);
477 
478     toolinfoA.lpszText = bufA;
479     r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
480 todo_wine
481     ok(!r, "got %ld\n", r);
482     ok(toolinfoA.lpszText == LPSTR_TEXTCALLBACKA, "expected LPSTR_TEXTCALLBACKA, got %p\n", toolinfoA.lpszText);
483 
484     DestroyWindow(hwnd);
485     DestroyWindow(notify);
486 
487     hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
488                            10, 10, 300, 100,
489                            NULL, NULL, NULL, 0);
490     ok(hwnd != NULL, "failed to create tooltip wnd\n");
491 
492     toolinfoW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
493     toolinfoW.hwnd = NULL;
494     toolinfoW.hinst = GetModuleHandleA(NULL);
495     toolinfoW.uFlags = 0;
496     toolinfoW.uId = 0x1234ABCD;
497     toolinfoW.lpszText = NULL;
498     toolinfoW.lParam = 0xdeadbeef;
499     GetClientRect(hwnd, &toolinfoW.rect);
500     r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&toolinfoW);
501     /* Wine currently checks for V3 structure size, which matches what V6 control does.
502        Older implementation was never updated to support lpReserved field. */
503 todo_wine
504     ok(!r, "Adding the tool to the tooltip succeeded!\n");
505 
506     if (0)  /* crashes on NT4 */
507     {
508         toolinfoW.hwnd = NULL;
509         toolinfoW.uId = 0x1234ABCD;
510         toolinfoW.lpszText = bufW;
511         SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
512         ok(toolinfoW.lpszText[0] == 0, "lpszText should be an empty string\n");
513     }
514 
515     /* text with embedded tabs */
516     toolinfoA.cbSize = sizeof(TTTOOLINFOA);
517     toolinfoA.hwnd = NULL;
518     toolinfoA.hinst = GetModuleHandleA(NULL);
519     toolinfoA.uFlags = 0;
520     toolinfoA.uId = 0x1235abce;
521     strcpy(bufA, testtip2A);
522     toolinfoA.lpszText = bufA;
523     toolinfoA.lParam = 0xdeadbeef;
524     GetClientRect(hwnd, &toolinfoA.rect);
525     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
526     ok(r, "got %ld\n", r);
527 
528     toolinfoA.hwnd = NULL;
529     toolinfoA.uId = 0x1235abce;
530     toolinfoA.lpszText = bufA;
531     r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
532     ok(!r, "got %ld\n", r);
533     ok(!strcmp(toolinfoA.lpszText, testtipA), "expected %s, got %s\n", testtipA, toolinfoA.lpszText);
534 
535     /* enable TTS_NOPREFIX, original text is retained */
536     style = GetWindowLongA(hwnd, GWL_STYLE);
537     SetWindowLongA(hwnd, GWL_STYLE, style | TTS_NOPREFIX);
538 
539     toolinfoA.hwnd = NULL;
540     toolinfoA.uId = 0x1235abce;
541     toolinfoA.lpszText = bufA;
542     r = SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
543     ok(!r, "got %ld\n", r);
544     ok(!strcmp(toolinfoA.lpszText, testtip2A), "expected %s, got %s\n", testtip2A, toolinfoA.lpszText);
545 
546     DestroyWindow(hwnd);
547 }
548 
549 static void test_ttm_gettoolinfo(void)
550 {
551     TTTOOLINFOA ti;
552     TTTOOLINFOW tiW;
553     HWND hwnd;
554     DWORD r;
555 
556     hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, 10, 10, 300, 100, NULL, NULL, NULL, 0);
557     ok(hwnd != NULL, "Failed to create tooltip control.\n");
558 
559     ti.cbSize = TTTOOLINFOA_V2_SIZE;
560     ti.hwnd = NULL;
561     ti.hinst = GetModuleHandleA(NULL);
562     ti.uFlags = 0;
563     ti.uId = 0x1234ABCD;
564     ti.lpszText = NULL;
565     ti.lParam = 0x1abe11ed;
566     GetClientRect(hwnd, &ti.rect);
567     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
568     ok(r, "Adding the tool to the tooltip failed\n");
569 
570     ti.cbSize = TTTOOLINFOA_V2_SIZE;
571     ti.lParam = 0xaaaaaaaa;
572     r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
573     ok(r, "Getting tooltip info failed\n");
574     ok(0x1abe11ed == ti.lParam ||
575        broken(0x1abe11ed != ti.lParam), /* comctl32 < 5.81 */
576        "Expected 0x1abe11ed, got %lx\n", ti.lParam);
577 
578     tiW.cbSize = TTTOOLINFOW_V2_SIZE;
579     tiW.hwnd = NULL;
580     tiW.uId = 0x1234ABCD;
581     tiW.lParam = 0xaaaaaaaa;
582     tiW.lpszText = NULL;
583     r = SendMessageA(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&tiW);
584     ok(r, "Getting tooltip info failed\n");
585     ok(0x1abe11ed == tiW.lParam ||
586        broken(0x1abe11ed != tiW.lParam), /* comctl32 < 5.81 */
587        "Expected 0x1abe11ed, got %lx\n", tiW.lParam);
588 
589     ti.cbSize = TTTOOLINFOA_V2_SIZE;
590     ti.uId = 0x1234ABCD;
591     ti.lParam = 0x55555555;
592     SendMessageA(hwnd, TTM_SETTOOLINFOA, 0, (LPARAM)&ti);
593 
594     ti.cbSize = TTTOOLINFOA_V2_SIZE;
595     ti.lParam = 0xdeadbeef;
596     r = SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&ti);
597     ok(r, "Getting tooltip info failed\n");
598     ok(0x55555555 == ti.lParam ||
599        broken(0x55555555 != ti.lParam), /* comctl32 < 5.81 */
600        "Expected 0x55555555, got %lx\n", ti.lParam);
601 
602     DestroyWindow(hwnd);
603 
604     /* 1. test size parameter validation rules (ansi messages) */
605     hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
606                            10, 10, 300, 100,
607                            NULL, NULL, NULL, 0);
608 
609     ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
610     ti.hwnd = NULL;
611     ti.hinst = GetModuleHandleA(NULL);
612     ti.uFlags = 0;
613     ti.uId = 0x1234ABCD;
614     ti.lpszText = NULL;
615     ti.lParam = 0xdeadbeef;
616     GetClientRect(hwnd, &ti.rect);
617     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
618     ok(r, "Adding the tool to the tooltip failed\n");
619     r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
620     expect(1, r);
621 
622     ti.cbSize = TTTOOLINFOA_V1_SIZE - 1;
623     ti.hwnd = NULL;
624     ti.uId = 0x1234ABCD;
625     SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
626     r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
627     expect(0, r);
628 
629     ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
630     ti.hwnd = NULL;
631     ti.hinst = GetModuleHandleA(NULL);
632     ti.uFlags = 0;
633     ti.uId = 0x1234ABCD;
634     ti.lpszText = NULL;
635     ti.lParam = 0xdeadbeef;
636     GetClientRect(hwnd, &ti.rect);
637     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
638     ok(r, "Adding the tool to the tooltip failed\n");
639     r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
640     expect(1, r);
641 
642     ti.cbSize = TTTOOLINFOA_V2_SIZE - 1;
643     ti.hwnd = NULL;
644     ti.uId = 0x1234ABCD;
645     SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
646     r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
647     expect(0, r);
648 
649     ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
650     ti.hwnd = NULL;
651     ti.hinst = GetModuleHandleA(NULL);
652     ti.uFlags = 0;
653     ti.uId = 0x1234ABCD;
654     ti.lpszText = NULL;
655     ti.lParam = 0xdeadbeef;
656     GetClientRect(hwnd, &ti.rect);
657     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
658     ok(r, "Adding the tool to the tooltip failed\n");
659     r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
660     expect(1, r);
661 
662     ti.cbSize = TTTOOLINFOA_V2_SIZE + 1;
663     ti.hwnd = NULL;
664     ti.uId = 0x1234ABCD;
665     SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
666     r = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
667     expect(0, r);
668 
669     DestroyWindow(hwnd);
670 
671     /* 2. test size parameter validation rules (w-messages) */
672     hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
673                            10, 10, 300, 100,
674                            NULL, NULL, NULL, 0);
675     ok(hwnd != NULL, "Failed to create tooltip window.\n");
676 
677     tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
678     tiW.hwnd = NULL;
679     tiW.hinst = GetModuleHandleA(NULL);
680     tiW.uFlags = 0;
681     tiW.uId = 0x1234ABCD;
682     tiW.lpszText = NULL;
683     tiW.lParam = 0xdeadbeef;
684     GetClientRect(hwnd, &tiW.rect);
685     r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
686     ok(r, "Adding the tool to the tooltip failed\n");
687     r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
688     expect(1, r);
689 
690     tiW.cbSize = TTTOOLINFOW_V1_SIZE - 1;
691     tiW.hwnd = NULL;
692     tiW.uId = 0x1234ABCD;
693     SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
694     r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
695     expect(0, r);
696 
697     tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
698     tiW.hwnd = NULL;
699     tiW.hinst = GetModuleHandleA(NULL);
700     tiW.uFlags = 0;
701     tiW.uId = 0x1234ABCD;
702     tiW.lpszText = NULL;
703     tiW.lParam = 0xdeadbeef;
704     GetClientRect(hwnd, &tiW.rect);
705     r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
706     ok(r, "Adding the tool to the tooltip failed\n");
707     r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
708     expect(1, r);
709 
710     tiW.cbSize = TTTOOLINFOW_V2_SIZE - 1;
711     tiW.hwnd = NULL;
712     tiW.uId = 0x1234ABCD;
713     SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
714     r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
715     expect(0, r);
716 
717     tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
718     tiW.hwnd = NULL;
719     tiW.hinst = GetModuleHandleA(NULL);
720     tiW.uFlags = 0;
721     tiW.uId = 0x1234ABCD;
722     tiW.lpszText = NULL;
723     tiW.lParam = 0xdeadbeef;
724     GetClientRect(hwnd, &tiW.rect);
725     r = SendMessageW(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&tiW);
726     ok(r, "Adding the tool to the tooltip failed\n");
727     r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
728     expect(1, r);
729     /* looks like TTM_DELTOOLW doesn't work with invalid size */
730     tiW.cbSize = TTTOOLINFOW_V2_SIZE + 1;
731     tiW.hwnd = NULL;
732     tiW.uId = 0x1234ABCD;
733     SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
734     r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
735     expect(1, r);
736 
737     tiW.cbSize = TTTOOLINFOW_V2_SIZE;
738     tiW.hwnd = NULL;
739     tiW.uId = 0x1234ABCD;
740     SendMessageW(hwnd, TTM_DELTOOLW, 0, (LPARAM)&tiW);
741     r = SendMessageW(hwnd, TTM_GETTOOLCOUNT, 0, 0);
742     expect(0, r);
743 
744     DestroyWindow(hwnd);
745 }
746 
747 static void test_longtextA(void)
748 {
749     static const char longtextA[] =
750         "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
751         "80 chars including null. In fact, the buffer is not null-terminated.";
752     HWND hwnd;
753     TTTOOLINFOA toolinfoA = { 0 };
754     CHAR bufA[256];
755     LRESULT r;
756 
757     hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
758                            10, 10, 300, 100,
759                            NULL, NULL, NULL, 0);
760     toolinfoA.cbSize = sizeof(TTTOOLINFOA);
761     toolinfoA.hwnd = NULL;
762     toolinfoA.hinst = GetModuleHandleA(NULL);
763     toolinfoA.uFlags = 0;
764     toolinfoA.uId = 0x1234ABCD;
765     strcpy(bufA, longtextA);
766     toolinfoA.lpszText = bufA;
767     toolinfoA.lParam = 0xdeadbeef;
768     GetClientRect(hwnd, &toolinfoA.rect);
769     r = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA);
770     if (r)
771     {
772         int textlen;
773         memset(bufA, 0, sizeof(bufA));
774         toolinfoA.hwnd = NULL;
775         toolinfoA.uId = 0xABCD1234;
776         toolinfoA.lpszText = bufA;
777         SendMessageA(hwnd, TTM_ENUMTOOLSA, 0, (LPARAM)&toolinfoA);
778         textlen = lstrlenA(toolinfoA.lpszText);
779         ok(textlen == 80, "lpszText has %d chars\n", textlen);
780         ok(toolinfoA.uId == 0x1234ABCD,
781            "uId should be retrieved, got %p\n", (void*)toolinfoA.uId);
782 
783         memset(bufA, 0, sizeof(bufA));
784         toolinfoA.hwnd = NULL;
785         toolinfoA.uId = 0x1234ABCD;
786         toolinfoA.lpszText = bufA;
787         SendMessageA(hwnd, TTM_GETTOOLINFOA, 0, (LPARAM)&toolinfoA);
788         textlen = lstrlenA(toolinfoA.lpszText);
789         ok(textlen == 80, "lpszText has %d chars\n", textlen);
790 
791         memset(bufA, 0, sizeof(bufA));
792         toolinfoA.hwnd = NULL;
793         toolinfoA.uId = 0x1234ABCD;
794         toolinfoA.lpszText = bufA;
795         SendMessageA(hwnd, TTM_GETTEXTA, 0, (LPARAM)&toolinfoA);
796         textlen = lstrlenA(toolinfoA.lpszText);
797         ok(textlen == 80, "lpszText has %d chars\n", textlen);
798     }
799 
800     DestroyWindow(hwnd);
801 }
802 
803 static void test_longtextW(void)
804 {
805     static const char longtextA[] =
806         "According to MSDN, TTM_ENUMTOOLS claims that TOOLINFO's lpszText is maximum "
807         "80 chars including null. Actually, this is not applied for wide version.";
808     HWND hwnd;
809     TTTOOLINFOW toolinfoW = { 0 };
810     WCHAR bufW[256];
811     LRESULT r;
812     int lenW;
813 
814     hwnd = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0,
815                            10, 10, 300, 100,
816                            NULL, NULL, NULL, 0);
817     ok(hwnd != NULL, "Failed to create tooltip window.\n");
818 
819     toolinfoW.cbSize = TTTOOLINFOW_V2_SIZE;
820     toolinfoW.hwnd = NULL;
821     toolinfoW.hinst = GetModuleHandleW(NULL);
822     toolinfoW.uFlags = 0;
823     toolinfoW.uId = 0x1234ABCD;
824     MultiByteToWideChar(CP_ACP, 0, longtextA, -1, bufW, ARRAY_SIZE(bufW));
825     lenW = lstrlenW(bufW);
826     toolinfoW.lpszText = bufW;
827     toolinfoW.lParam = 0xdeadbeef;
828     GetClientRect(hwnd, &toolinfoW.rect);
829     r = SendMessageW(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&toolinfoW);
830     if (r)
831     {
832         int textlen;
833         memset(bufW, 0, sizeof(bufW));
834         toolinfoW.hwnd = NULL;
835         toolinfoW.uId = 0xABCD1234;
836         toolinfoW.lpszText = bufW;
837         SendMessageW(hwnd, TTM_ENUMTOOLSW, 0, (LPARAM)&toolinfoW);
838         textlen = lstrlenW(toolinfoW.lpszText);
839         ok(textlen == lenW, "lpszText has %d chars\n", textlen);
840         ok(toolinfoW.uId == 0x1234ABCD,
841            "uId should be retrieved, got %p\n", (void*)toolinfoW.uId);
842 
843         memset(bufW, 0, sizeof(bufW));
844         toolinfoW.hwnd = NULL;
845         toolinfoW.uId = 0x1234ABCD;
846         toolinfoW.lpszText = bufW;
847         SendMessageW(hwnd, TTM_GETTOOLINFOW, 0, (LPARAM)&toolinfoW);
848         textlen = lstrlenW(toolinfoW.lpszText);
849         ok(textlen == lenW, "lpszText has %d chars\n", textlen);
850 
851         memset(bufW, 0, sizeof(bufW));
852         toolinfoW.hwnd = NULL;
853         toolinfoW.uId = 0x1234ABCD;
854         toolinfoW.lpszText = bufW;
855         SendMessageW(hwnd, TTM_GETTEXTW, 0, (LPARAM)&toolinfoW);
856         textlen = lstrlenW(toolinfoW.lpszText);
857         ok(textlen == lenW ||
858            broken(textlen == 0 && toolinfoW.lpszText == NULL), /* nt4, kb186177 */
859            "lpszText has %d chars\n", textlen);
860     }
861 
862     DestroyWindow(hwnd);
863 }
864 
865 static BOOL almost_eq(int a, int b)
866 {
867     return a-5<b && a+5>b;
868 }
869 
870 static void test_track(void)
871 {
872     WCHAR textW[] = {'t','e','x','t',0};
873     TTTOOLINFOW info = { 0 };
874     HWND parent, tt;
875     LRESULT res;
876     RECT pos;
877 
878     parent = CreateWindowExW(0, WC_STATICW, NULL, WS_CAPTION | WS_VISIBLE,
879             50, 50, 300, 300, NULL, NULL, NULL, 0);
880     ok(parent != NULL, "creation of parent window failed\n");
881 
882     ShowWindow(parent, SW_SHOWNORMAL);
883     flush_events(100);
884 
885     tt = CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW, NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
886             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
887             parent, NULL, GetModuleHandleW(NULL), 0);
888     ok(tt != NULL, "creation of tooltip window failed\n");
889 
890     info.cbSize = TTTOOLINFOW_V1_SIZE;
891     info.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
892     info.hwnd = parent;
893     info.hinst = GetModuleHandleW(NULL);
894     info.lpszText = textW;
895     info.uId = (UINT_PTR)parent;
896     GetClientRect(parent, &info.rect);
897 
898     res = SendMessageW(tt, TTM_ADDTOOLW, 0, (LPARAM)&info);
899     ok(res, "adding the tool to the tooltip failed\n");
900 
901     SendMessageW(tt, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0));
902     SendMessageW(tt, TTM_TRACKACTIVATE, (WPARAM)TRUE, (LPARAM)&info);
903     SendMessageW(tt, TTM_TRACKPOSITION, 0, MAKELPARAM(10, 10));
904 
905     GetWindowRect(tt, &pos);
906     ok(almost_eq(pos.left, 10), "pos.left = %d\n", pos.left);
907     ok(almost_eq(pos.top, 10), "pos.top = %d\n", pos.top);
908 
909     info.uFlags = TTF_IDISHWND | TTF_ABSOLUTE;
910     SendMessageW(tt, TTM_SETTOOLINFOW, 0, (LPARAM)&info);
911     SendMessageW(tt, TTM_TRACKPOSITION, 0, MAKELPARAM(10, 10));
912 
913     GetWindowRect(tt, &pos);
914     ok(!almost_eq(pos.left, 10), "pos.left = %d\n", pos.left);
915     ok(!almost_eq(pos.top, 10), "pos.top = %d\n", pos.top);
916 
917     DestroyWindow(tt);
918     DestroyWindow(parent);
919 }
920 
921 static LRESULT CALLBACK info_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
922 {
923     switch(msg) {
924 
925     case WM_DESTROY:
926         PostQuitMessage(0);
927         break;
928 
929     default:
930         return DefWindowProcA(hWnd, msg, wParam, lParam);
931     }
932     return 0;
933 }
934 
935 static void test_setinfo(BOOL is_v6)
936 {
937    WNDCLASSA wc;
938    LRESULT   lResult;
939    HWND parent, parent2, hwndTip, hwndTip2;
940    TTTOOLINFOA toolInfo = { 0 };
941    TTTOOLINFOA toolInfo2 = { 0 };
942    WNDPROC wndProc;
943 
944    /* Create a class to use the custom draw wndproc */
945    wc.style = CS_HREDRAW | CS_VREDRAW;
946    wc.cbClsExtra = 0;
947    wc.cbWndExtra = 0;
948    wc.hInstance = GetModuleHandleA(NULL);
949    wc.hIcon = NULL;
950    wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
951    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
952    wc.lpszMenuName = NULL;
953    wc.lpszClassName = "SetInfoClass";
954    wc.lpfnWndProc = info_wnd_proc;
955    RegisterClassA(&wc);
956 
957    /* Create a main window */
958    parent = CreateWindowExA(0, "SetInfoClass", NULL,
959                            WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
960                            WS_MAXIMIZEBOX | WS_VISIBLE,
961                            50, 50,
962                            300, 300,
963                            NULL, NULL, NULL, 0);
964    ok(parent != NULL, "Creation of main window failed\n");
965 
966    parent2 = CreateWindowExA(0, "SetInfoClass", NULL,
967                            WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
968                            WS_MAXIMIZEBOX | WS_VISIBLE,
969                            50, 50,
970                            300, 300,
971                            NULL, NULL, NULL, 0);
972    ok(parent2 != NULL, "Creation of main window failed\n");
973 
974    /* Make it show */
975    ShowWindow(parent2, SW_SHOWNORMAL);
976    flush_events(100);
977 
978    /* Create Tooltip */
979    hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
980                             NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
981                             CW_USEDEFAULT, CW_USEDEFAULT,
982                             CW_USEDEFAULT, CW_USEDEFAULT,
983                             parent, NULL, GetModuleHandleA(NULL), 0);
984    ok(hwndTip != NULL, "Creation of tooltip window failed\n");
985 
986    hwndTip2 = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA,
987                             NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
988                             CW_USEDEFAULT, CW_USEDEFAULT,
989                             CW_USEDEFAULT, CW_USEDEFAULT,
990                             parent, NULL, GetModuleHandleA(NULL), 0);
991    ok(hwndTip2 != NULL, "Creation of tooltip window failed\n");
992 
993 
994    /* Make it topmost, as per the MSDN */
995    SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0,
996          SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
997 
998    /* Create a tool */
999    toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
1000    toolInfo.hwnd = parent;
1001    toolInfo.hinst = GetModuleHandleA(NULL);
1002    toolInfo.uFlags = TTF_SUBCLASS;
1003    toolInfo.uId = 0x1234ABCD;
1004    toolInfo.lpszText = (LPSTR)"This is a test tooltip";
1005    toolInfo.lParam = 0xdeadbeef;
1006    GetClientRect (parent, &toolInfo.rect);
1007    lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
1008    ok(lResult, "Adding the tool to the tooltip failed\n");
1009 
1010    toolInfo.cbSize = TTTOOLINFOA_V1_SIZE;
1011    toolInfo.hwnd = parent2;
1012    toolInfo.hinst = GetModuleHandleA(NULL);
1013    toolInfo.uFlags = 0;
1014    toolInfo.uId = 0x1234ABCE;
1015    toolInfo.lpszText = (LPSTR)"This is a test tooltip";
1016    toolInfo.lParam = 0xdeadbeef;
1017    GetClientRect (parent, &toolInfo.rect);
1018    lResult = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolInfo);
1019    ok(lResult, "Adding the tool to the tooltip failed\n");
1020 
1021    /* Try to Remove Subclass */
1022    toolInfo2.cbSize = TTTOOLINFOA_V1_SIZE;
1023    toolInfo2.hwnd = parent;
1024    toolInfo2.uId = 0x1234ABCD;
1025    lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1026    ok(lResult, "GetToolInfo failed\n");
1027    ok(toolInfo2.uFlags & TTF_SUBCLASS || broken(is_v6 && !(toolInfo2.uFlags & TTF_SUBCLASS)) /* XP */,
1028        "uFlags does not have subclass\n");
1029    wndProc = (WNDPROC)GetWindowLongPtrA(parent, GWLP_WNDPROC);
1030    ok (wndProc != info_wnd_proc, "Window Proc is wrong\n");
1031 
1032    toolInfo2.uFlags &= ~TTF_SUBCLASS;
1033    SendMessageA(hwndTip, TTM_SETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1034    lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1035    ok(lResult, "GetToolInfo failed\n");
1036    ok(!(toolInfo2.uFlags & TTF_SUBCLASS), "uFlags has subclass\n");
1037    wndProc = (WNDPROC)GetWindowLongPtrA(parent, GWLP_WNDPROC);
1038    ok (wndProc != info_wnd_proc, "Window Proc is wrong\n");
1039 
1040    /* Try to Add Subclass */
1041 
1042    /* Make it topmost, as per the MSDN */
1043    SetWindowPos(hwndTip2, HWND_TOPMOST, 0, 0, 0, 0,
1044          SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1045 
1046    toolInfo2.cbSize = TTTOOLINFOA_V1_SIZE;
1047    toolInfo2.hwnd = parent2;
1048    toolInfo2.uId = 0x1234ABCE;
1049    lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1050    ok(lResult, "GetToolInfo failed\n");
1051    ok(!(toolInfo2.uFlags & TTF_SUBCLASS), "uFlags has subclass\n");
1052    wndProc = (WNDPROC)GetWindowLongPtrA(parent2, GWLP_WNDPROC);
1053    ok (wndProc == info_wnd_proc, "Window Proc is wrong\n");
1054 
1055    toolInfo2.uFlags |= TTF_SUBCLASS;
1056    SendMessageA(hwndTip, TTM_SETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1057    lResult = SendMessageA(hwndTip, TTM_GETTOOLINFOA, 0, (LPARAM)&toolInfo2);
1058    ok(lResult, "GetToolInfo failed\n");
1059    ok(toolInfo2.uFlags & TTF_SUBCLASS, "uFlags does not have subclass\n");
1060    wndProc = (WNDPROC)GetWindowLongPtrA(parent2, GWLP_WNDPROC);
1061    ok (wndProc == info_wnd_proc, "Window Proc is wrong\n");
1062 
1063    /* Clean up */
1064    DestroyWindow(hwndTip);
1065    DestroyWindow(hwndTip2);
1066    DestroyWindow(parent);
1067    DestroyWindow(parent2);
1068 }
1069 
1070 static void test_margin(void)
1071 {
1072     RECT r, r1;
1073     HWND hwnd;
1074     DWORD ret;
1075 
1076     hwnd = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0,
1077                            10, 10, 300, 100,
1078                            NULL, NULL, NULL, 0);
1079     ok(hwnd != NULL, "failed to create tooltip wnd\n");
1080 
1081     ret = SendMessageA(hwnd, TTM_SETMARGIN, 0, 0);
1082     ok(!ret, "got %d\n", ret);
1083 
1084     SetRect(&r, -1, -1, 1, 1);
1085     ret = SendMessageA(hwnd, TTM_SETMARGIN, 0, (LPARAM)&r);
1086     ok(!ret, "got %d\n", ret);
1087 
1088     SetRectEmpty(&r1);
1089     ret = SendMessageA(hwnd, TTM_GETMARGIN, 0, (LPARAM)&r1);
1090     ok(!ret, "got %d\n", ret);
1091     ok(EqualRect(&r, &r1), "got %s, was %s\n", wine_dbgstr_rect(&r1), wine_dbgstr_rect(&r));
1092 
1093     ret = SendMessageA(hwnd, TTM_SETMARGIN, 0, 0);
1094     ok(!ret, "got %d\n", ret);
1095 
1096     SetRectEmpty(&r1);
1097     ret = SendMessageA(hwnd, TTM_GETMARGIN, 0, (LPARAM)&r1);
1098     ok(!ret, "got %d\n", ret);
1099     ok(EqualRect(&r, &r1), "got %s, was %s\n", wine_dbgstr_rect(&r1), wine_dbgstr_rect(&r));
1100 
1101     ret = SendMessageA(hwnd, TTM_GETMARGIN, 0, 0);
1102     ok(!ret, "got %d\n", ret);
1103 
1104     DestroyWindow(hwnd);
1105 }
1106 
1107 static void test_TTM_ADDTOOL(BOOL is_v6)
1108 {
1109     static const WCHAR testW[] = {'T','e','s','t',0};
1110     TTTOOLINFOW tiW;
1111     TTTOOLINFOA ti;
1112     int ret, size;
1113     HWND hwnd, parent;
1114     UINT max_size;
1115 
1116     parent = CreateWindowExA(0, "Static", NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, NULL, 0);
1117     ok(parent != NULL, "failed to create parent wnd\n");
1118 
1119     hwnd = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA, NULL, TTS_NOPREFIX | TTS_ALWAYSTIP,
1120         0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), 0);
1121     ok(hwnd != NULL, "Failed to create tooltip window.\n");
1122 
1123     for (size = 0; size <= TTTOOLINFOW_V3_SIZE + 1; size++)
1124     {
1125         ti.cbSize = size;
1126         ti.hwnd = NULL;
1127         ti.hinst = GetModuleHandleA(NULL);
1128         ti.uFlags = 0;
1129         ti.uId = 0x1234abce;
1130         ti.lpszText = (LPSTR)"Test";
1131         ti.lParam = 0xdeadbeef;
1132         GetClientRect(hwnd, &ti.rect);
1133 
1134         ret = SendMessageA(hwnd, TTM_ADDTOOLA, 0, (LPARAM)&ti);
1135         ok(ret, "Failed to add a tool, size %d.\n", size);
1136 
1137         ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1138         ok(ret == 1, "Unexpected tool count %d, size %d.\n", ret, size);
1139 
1140         ret = SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&ti);
1141         ok(!ret, "Unexpected ret value %d.\n", ret);
1142 
1143         ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1144         ok(ret == 0, "Unexpected tool count %d, size %d.\n", ret, size);
1145     }
1146 
1147     /* W variant checks cbSize. */
1148     max_size = is_v6 ? TTTOOLINFOW_V3_SIZE : TTTOOLINFOW_V2_SIZE;
1149     for (size = 0; size <= max_size + 1; size++)
1150     {
1151         tiW.cbSize = size;
1152         tiW.hwnd = NULL;
1153         tiW.hinst = GetModuleHandleA(NULL);
1154         tiW.uFlags = 0;
1155         tiW.uId = 0x1234abce;
1156         tiW.lpszText = (LPWSTR)testW;
1157         tiW.lParam = 0xdeadbeef;
1158         GetClientRect(hwnd, &tiW.rect);
1159 
1160         ret = SendMessageA(hwnd, TTM_ADDTOOLW, 0, (LPARAM)&tiW);
1161     todo_wine_if(!is_v6 && size > max_size)
1162         ok(size <= max_size ? ret : !ret, "%d: Unexpected ret value %d, size %d, max size %d.\n", is_v6, ret, size, max_size);
1163         if (ret)
1164         {
1165             ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1166             ok(ret == 1, "Unexpected tool count %d.\n", ret);
1167 
1168             ret = SendMessageA(hwnd, TTM_DELTOOLA, 0, (LPARAM)&tiW);
1169             ok(!ret, "Unexpected ret value %d.\n", ret);
1170 
1171             ret = SendMessageA(hwnd, TTM_GETTOOLCOUNT, 0, 0);
1172             ok(ret == 0, "Unexpected tool count %d.\n", ret);
1173         }
1174     }
1175 
1176     DestroyWindow(hwnd);
1177 }
1178 
1179 static const struct message ttn_show_parent_seq[] =
1180 {
1181     { WM_NOTIFY, sent|id, 0, 0, TTN_SHOW },
1182     { 0 }
1183 };
1184 
1185 static void test_TTN_SHOW(void)
1186 {
1187     HWND hwndTip, hwnd;
1188     TTTOOLINFOA ti;
1189     RECT rect;
1190     BOOL ret;
1191 
1192     hwnd = create_parent_window();
1193     ok(hwnd != NULL, "Failed to create parent window.\n");
1194 
1195     /* Put cursor outside the window */
1196     GetWindowRect(hwnd, &rect);
1197     SetCursorPos(rect.right + 200, 0);
1198 
1199     ShowWindow(hwnd, SW_SHOWNORMAL);
1200     flush_events(100);
1201 
1202     /* Create tooltip */
1203     hwndTip = CreateWindowExA(WS_EX_TOPMOST, TOOLTIPS_CLASSA, NULL, TTS_ALWAYSTIP, 10, 10, 300, 300,
1204         hwnd, NULL, NULL, 0);
1205     ok(hwndTip != NULL, "Failed to create tooltip window.\n");
1206 
1207     SetWindowPos(hwndTip, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1208 
1209     ti.cbSize = sizeof(TTTOOLINFOA);
1210     ti.hwnd = hwnd;
1211     ti.hinst = GetModuleHandleA(NULL);
1212     ti.uFlags = TTF_SUBCLASS;
1213     ti.uId = 0x1234abcd;
1214     ti.lpszText = (LPSTR)"This is a test tooltip";
1215     ti.lParam = 0xdeadbeef;
1216     GetClientRect(hwnd, &ti.rect);
1217     ret = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&ti);
1218     ok(ret, "Failed to add a tool.\n");
1219 
1220     /* Make tooltip appear quickly */
1221     SendMessageA(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1, 0));
1222 
1223     flush_sequences(sequences, NUM_MSG_SEQUENCES);
1224 
1225     /* Put cursor inside window, tooltip will appear immediately */
1226     GetWindowRect(hwnd, &rect);
1227     SetCursorPos((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2);
1228     flush_events(200);
1229 
1230     ok_sequence(sequences, PARENT_SEQ_INDEX, ttn_show_parent_seq, "TTN_SHOW parent seq", FALSE);
1231 
1232     DestroyWindow(hwndTip);
1233     DestroyWindow(hwnd);
1234 }
1235 
1236 START_TEST(tooltips)
1237 {
1238     ULONG_PTR ctx_cookie;
1239     HANDLE hCtx;
1240 
1241     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
1242 
1243     LoadLibraryA("comctl32.dll");
1244 
1245     register_parent_wnd_class();
1246 
1247     test_create_tooltip(FALSE);
1248     test_customdraw();
1249     test_gettext();
1250     test_ttm_gettoolinfo();
1251     test_longtextA();
1252     test_longtextW();
1253     test_track();
1254     test_setinfo(FALSE);
1255     test_margin();
1256     test_TTM_ADDTOOL(FALSE);
1257     test_TTN_SHOW();
1258 
1259     if (!load_v6_module(&ctx_cookie, &hCtx))
1260         return;
1261 
1262     test_create_tooltip(TRUE);
1263     test_customdraw();
1264     test_longtextW();
1265     test_track();
1266     test_setinfo(TRUE);
1267     test_margin();
1268     test_TTM_ADDTOOL(TRUE);
1269     test_TTN_SHOW();
1270 
1271     unload_v6_module(ctx_cookie, hCtx);
1272 }
1273