[Bug 17370] Notepad++ 5.2 crashes when triggering tooltip over macro record toolbar button (user32.RealChildWindowFromPoint needs to pass CWP_SKIPINVISIBLE to skip hidden windows)

wine-bugs at winehq.org wine-bugs at winehq.org
Sun Jan 15 17:24:07 CST 2012


http://bugs.winehq.org/show_bug.cgi?id=17370

Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |focht at gmx.net
          Component|-unknown                    |user32
            Summary|Notepad++ 5.2 crashes when  |Notepad++ 5.2 crashes when
                   |triggering tooltip over     |triggering tooltip over
                   |macro record toolbar button |macro record toolbar button
                   |                            |(user32.RealChildWindowFrom
                   |                            |Point needs to pass
                   |                            |CWP_SKIPINVISIBLE to skip
                   |                            |hidden windows)

--- Comment #4 from Anastasius Focht <focht at gmx.net> 2012-01-15 17:24:07 CST ---
Hello,

hmm interesting ... brain damage at its best ;-)

--- snip ---
0024:Call user32.CreateWindowExW(00000010,004b4d20 L"Notepad++",004b6b4c
L"Notepad++",02cf0000,00000000,00000000,00000000,00000000,00000000,00000000,00400000,002e574c)
ret=00447451
0024:trace:win:WIN_CreateWindowEx L"Notepad++" L"Notepad++" ex=00000010
style=02cf0000 0,0 0x0 parent=(nil) menu=(nil) inst=0x400000 params=0x2e574c
0024:trace:win:dump_window_styles style: WS_CLIPCHILDREN WS_CAPTION WS_SYSMENU
WS_THICKFRAME WS_MINIMIZEBOX WS_MAXIMIZEBOX
0024:trace:win:dump_window_styles exstyle: WS_EX_ACCEPTFILES 
...
0024:trace:win:WIN_CreateWindowEx hwnd 0x1007a cs 0,0 112x27 
...
0024:trace:tooltips:TOOLTIPS_WindowProc hwnd=0x10020a msg=113 wparam=1 lParam=0
0024:trace:tooltips:TOOLTIPS_Timer timer 1 (0x10020a) expired! 
...
0024:Call window proc 0x68267ea8
(hwnd=0x10020a,msg=TTM_WINDOWFROMPOINT,wp=00000000,lp=002e5388) 
...
0024:Ret  window proc 0x68267ea8
(hwnd=0x10020a,msg=TTM_WINDOWFROMPOINT,wp=00000000,lp=002e5388) retval=000201f2
0024:Ret  user32.SendMessageW() retval=000201f2 ret=68264e2f
0024:Call user32.ScreenToClient(000201f2,002e5388) ret=68264e57
0024:Ret  user32.ScreenToClient() retval=00000001 ret=68264e57 
...
0024:trace:tooltips:TOOLTIPS_Show Show tooltip pre 30! (0x10020a)
0024:trace:tooltips:TOOLTIPS_GetDispInfoW hdr.idFrom = 56b8 
...
0024:trace:toolbar:ToolbarWindowProc hwnd=0x201f2 msg=4e wparam=56b8
lparam=2e5134
0024:trace:toolbar:TOOLBAR_GetButtonIndex command=22200 index=38
0024:trace:toolbar:TOOLBAR_TTGetDispInfo button index = 38 
...
0024:trace:toolbar:TOOLBAR_SendNotify to window 0x1007a, code=fffffd32, via
ANSI 
...
0024:trace:msg:WINPROC_CallProcWtoA
(hwnd=0x1007a,msg=WM_NOTIFY,wp=00000000,lp=002e4d7c) 
...
0024:trace:toolbar:ToolbarWindowProc hwnd=0x201f2 msg=401 wparam=a411 lparam=0
0024:trace:toolbar:TOOLBAR_GetButtonIndex command=42001 index=8
0024:trace:toolbar:TOOLBAR_EnableButton hwnd=0x201f2, btn id=42001,
lParam=0x00000000 
...
0024:trace:toolbar:TOOLBAR_TTGetDispInfo Sending tooltip notification to
0x1007a
...
0024:trace:toolbar:ToolbarWindowProc hwnd=0x201f2 msg=401 wparam=a430 lparam=1
0024:trace:toolbar:TOOLBAR_GetButtonIndex command=42032 index=32
0024:trace:toolbar:TOOLBAR_EnableButton hwnd=0x201f2, btn id=42032,
lParam=0x00000001
0024:Ret  window proc 0x68260e97
(hwnd=0x201f2,msg=TB_ENABLEBUTTON,wp=0000a430,lp=00000001) retval=00000001
0024:Ret  user32.SendMessageW() retval=00000001 ret=0042bf24
0024:Call user32.GetCursorPos(002e1ef0) ret=0043ee5b
0024:Ret  user32.GetCursorPos() retval=00000001 ret=0043ee5b
0024:Call user32.ScreenToClient(0001007a,002e1ef0) ret=0043ee6a
0024:Ret  user32.ScreenToClient() retval=00000001 ret=0043ee6a
0024:Call user32.RealChildWindowFromPoint(0001007a,00000302,0000000b)
ret=0043ee7e
0024:Ret  user32.RealChildWindowFromPoint() retval=000100ae ret=0043ee7e 
...
0024:Call user32.SendMessageW(000100ae,0000133c,000056b8,002e1eb4) ret=0041536b
0024:Call hook proc 0x412cd0 (id=WH_CALLWNDPROC,code=0,wp=00000001,lp=002e1d4c)
0024:Call user32.GetWindowLongW(000100be,ffffffeb) ret=00412cf5
0024:Ret  user32.GetWindowLongW() retval=002e5968 ret=00412cf5
0024:Call user32.CallNextHookEx(000100fa,00000000,00000001,002e1d4c)
ret=00412dd0
0024:Ret  user32.CallNextHookEx() retval=00000000 ret=00412dd0
0024:Ret  hook proc 0x412cd0 (id=WH_CALLWNDPROC,code=0,wp=00000001,lp=002e1d4c)
retval=00000000
0024:Call window proc 0x473540
(hwnd=0x100ae,msg=TCM_GETITEMW,wp=000056b8,lp=002e1eb4)
0024:Call user32.GetWindowLongW(000100ae,ffffffeb) ret=0047355d
0024:Ret  user32.GetWindowLongW() retval=002e5d80 ret=0047355d
0024:Call user32.CallWindowProcW(6824c2e7,000100ae,0000133c,000056b8,002e1eb4)
ret=0047321a
0024:Call window proc 0x6824c2e7
(hwnd=0x100ae,msg=TCM_GETITEMW,wp=000056b8,lp=002e1eb4)
0024:Call user32.GetWindowLongW(000100ae,00000000) ret=6824c30c
0024:Ret  user32.GetWindowLongW() retval=00147e10 ret=6824c30c
0024:Ret  window proc 0x6824c2e7
(hwnd=0x100ae,msg=TCM_GETITEMW,wp=000056b8,lp=002e1eb4) retval=00000000
0024:Ret  user32.CallWindowProcW() retval=00000000 ret=0047321a
0024:Ret  window proc 0x473540
(hwnd=0x100ae,msg=TCM_GETITEMW,wp=000056b8,lp=002e1eb4) retval=00000000
0024:Ret  user32.SendMessageW() retval=00000000 ret=0041536b
0024:trace:seh:raise_exception code=c0000005 flags=0 addr=0x4029d0 ip=004029d0
tid=0024
0024:trace:seh:raise_exception  info[0]=00000000
0024:trace:seh:raise_exception  info[1]=0000008a
0024:trace:seh:raise_exception  eax=0000008a ebx=0010020a ecx=004e3fec
edx=00000000 esi=0000008a edi=0000008c
0024:trace:seh:raise_exception  ebp=002e574c esp=002e1ec8 cs=0023 ds=002b
es=002b fs=0063 gs=006b flags=00010202
0024:trace:seh:call_stack_handlers calling handler at 0x4aca61 code=c0000005
flags=0 
--- snip ---

I found the place in Notepad++ 5.2 sources that matches this trace log pretty
nicely:

"Notepad_plus.cpp":

--- snip ---
BOOL Notepad_plus::notify(SCNotification *notification)
{
    //Important, keep track of which element generated the message
    bool isFromPrimary = (_mainEditView.getHSelf() ==
notification->nmhdr.hwndFrom || _mainDocTab.getHSelf() ==
notification->nmhdr.hwndFrom);
    bool isFromSecondary = !isFromPrimary && (_subEditView.getHSelf() ==
notification->nmhdr.hwndFrom || _subDocTab.getHSelf() ==
notification->nmhdr.hwndFrom);
    ScintillaEditView * notifyView =
isFromPrimary?&_mainEditView:&_subEditView;
    DocTabView *notifyDocTab = isFromPrimary?&_mainDocTab:&_subDocTab;
    TBHDR * tabNotification = (TBHDR*) notification;
...

    case TTN_GETDISPINFO:
    { 
        LPTOOLTIPTEXT lpttt; 

        lpttt = (LPTOOLTIPTEXT)notification; 
        lpttt->hinst = _hInst; 

    POINT p;
    ::GetCursorPos(&p);
    ::ScreenToClient(_hSelf, &p);
    HWND hWin = ::RealChildWindowFromPoint(_hSelf, p);

    static generic_string tip;
    int id = int(lpttt->hdr.idFrom);
    if (hWin == _rebarTop.getHSelf())
    {
        getNameStrFromCmd(id, tip);
    }
    else if (hWin == _mainDocTab.getHSelf())
    {
        BufferID idd = _mainDocTab.getBufferByIndex(id);
        Buffer * buf = MainFileManager->getBufferByID(idd);
        tip = buf->getFullPathName();
    }
    else if (hWin == _subDocTab.getHSelf())
    {
        BufferID idd = _subDocTab.getBufferByIndex(id);
        Buffer * buf = MainFileManager->getBufferByID(idd);
        tip = buf->getFullPathName();
    }
    else
        break;

    lpttt->lpszText = (TCHAR *)tip.c_str();
   } 
   break; 
--- snip ---

Notepad++ uses RealChildWindowFromPoint() to retrieve the window handle/object
to ask for tooltip text.
What basically happens is that the wrong child window is returned from
RealChildWindowFromPoint().

If you hover over first two toolbar buttons, "new file" and "open file", the
scintilla text editor control HWND is returned (empty editor window).
If you hover over third toolbar button "save file" to "formatting" buttons, a
splitter container control is returned.
If you hover further buttons at the end of toolbar strip, a tab control is
returned.

Using the nifty "Winspector" tool (or any other Message Spy tool that can
graphically highlight/inspect selected windows at runtime) one can see the
problem.

WS_VISIBLE set:

Top level main window "Notepad++ ..": (83,212,1038,871)
Rebar/Toolbar strip: (87,254,1034,282)

No WS_VISIBLE set:

Splitter container: (87,254,1034,867)
One of the scintilla editor controls: (87,254,187,354)
Tab control (hidden, not the one showing editor tab): (568,254,1034,867)

Except the top level main window these are all on same window hierarchy level
(child of main) and overlay each other regarding rectangle coordinates.

Code:
http://source.winehq.org/git/wine.git/blob/c764210731d4d4b6fda53bf27e2150b704e09ac8:/dlls/user32/winpos.c#l374

--- snip ---
 374 /*******************************************************************
 375  *         RealChildWindowFromPoint (USER32.@)
 376  */
 377 HWND WINAPI RealChildWindowFromPoint( HWND hwndParent, POINT pt )
 378 {
 379     return ChildWindowFromPointEx( hwndParent, pt, CWP_SKIPTRANSPARENT );
 380 }
--- snip ---

Unfortunately WS_VISIBLE is not evaluated until CWP_SKIPINVISIBLE was passed.

Reading the "community" comments section of RealChildWindowFromPoint():

MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633537.aspx

There is a link to an "The Old New Thing" article: "WindowFromPoint,
ChildWindowFromPoint, RealChildWindowFromPoint, when will it all end?"

http://blogs.msdn.com/b/oldnewthing/archive/2010/12/30/10110077.aspx

The table listing the different API functions and their behaviour gives the
hint:

It seems RealChildWindowFromPoint() skips "hidden" windows.

Adding CWP_SKIPINVISIBLE to list of flags in RealChildWindowFromPoint() helped.
All tooltip texts are now properly shown when hovering mouse over toolbar
buttons.

--- quote ---
It's okay now in 5.6.2 
--- quote ---

DO you really want to know why? Ok, you asked for it ...

They didn't really figure out their problems and used the ultimate hammer:
exception handler.

--- snip ---
    case TTN_GETDISPINFO:
    {
    try {
        LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT)notification; 

        //Joce's fix
        lpttt->hinst = NULL; 
        POINT p;
        ::GetCursorPos(&p);
        ::ScreenToClient(_hSelf, &p);
        HWND hWin = ::RealChildWindowFromPoint(_hSelf, p);
        const int tipMaxLen = 1024;
        static TCHAR docTip[tipMaxLen];
        docTip[0] = '\0';

        generic_string tipTmp(TEXT(""));
        int id = int(lpttt->hdr.idFrom);

        if (hWin == _rebarTop.getHSelf())
        {
            getNameStrFromCmd(id, tipTmp);
            if (tipTmp.length() >= 80)
                return FALSE;

            lstrcpy(lpttt->szText, tipTmp.c_str());
            return TRUE;
        }
        else if (hWin == _mainDocTab.getHSelf())
        {
            BufferID idd = _mainDocTab.getBufferByIndex(id);
            Buffer * buf = MainFileManager->getBufferByID(idd);
            tipTmp = buf->getFullPathName();

            if (tipTmp.length() >= tipMaxLen)
                return FALSE;
            lstrcpy(docTip, tipTmp.c_str());
            lpttt->lpszText = docTip;
            return TRUE;
        }
        else if (hWin == _subDocTab.getHSelf())
        {
            BufferID idd = _subDocTab.getBufferByIndex(id);
            Buffer * buf = MainFileManager->getBufferByID(idd);
            tipTmp = buf->getFullPathName();

            if (tipTmp.length() >= tipMaxLen)
                return FALSE;
            lstrcpy(docTip, tipTmp.c_str());
            lpttt->lpszText = docTip;
            return TRUE;
        }
        else
        {
            return FALSE;
        }
    } catch (...) {
        //printStr(TEXT("ToolTip crash is caught!"));
    }
    }
    break;
--- snip ---

It's so bad that my eyes are bleeding.

$ wine --version
wine-1.3.37

Regards

-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
Do not reply to this email, post in Bugzilla using the
above URL to reply.
------- You are receiving this mail because: -------
You are watching all bug changes.



More information about the wine-bugs mailing list