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