2

My dll uses SetWindowsHookEx to get into the main window's thread ( 3rd party application ) to subclass it with SetWindowSubclass. Subclassed window procedure is used just to control additional child window added to the main window. RemoveWindowSubclass is called inside window procedure on WM_DESTROY. When the hooked window is closed by user, application unloads dll. After DLL_PROCESS_DETACH is processed, sometimes ( on some pc's ) application is crashed. All threads which dll created are finished before DLL_PROCESS_DETACH, so it does not look like some not finished cleanup. After many experiments i've found out that commenting all this subclassing stuff solves the crash. So what am i doing wrong?

Here are code snippets to verify

Here is subclasser methods

    BOOL CSubclasser2::subclass( HWND hwnd, SUBCLASSPROC proc, DWORD_PTR data )
    {
        BOOL res;
    if( GetCurrentThreadId() == GetWindowThreadProcessId( hwnd, 0 ) )
        {
            res = SetWindowSubclass( hwnd, proc, 0, data );
        }
        else
        {
            m_hwnd = hwnd;
            m_wndProc = proc;
            m_pData = data;
            m_bSubclass = TRUE;

            setHook();

            SendMessage( hwnd, WM_NULL, 0, 0 ); //waiting for hook proc called

            unsetHook();    

            res = m_subclassed;
        }

void CSubclasser2::setHook()
{
    if( !m_hook )
    {
        m_hook = SetWindowsHookEx( WH_CALLWNDPROC, m_hookCallWndProc, 0, GetWindowThreadProcessId( m_hwnd, 0 ) );
    }
}

LRESULT CALLBACK CSubclasser2::m_hookCallWndProc( int nCode, WPARAM wParam, LPARAM lParam )
{
    if( nCode == HC_ACTION && m_hwnd && ( ( CWPSTRUCT* )lParam )->hwnd == m_hwnd )
    {
        if( m_bSubclass )
        {
            m_subclassed = SetWindowSubclass( m_hwnd, m_wndProc, 0, m_pData );
        }
        else
        {
            m_subclassed = RemoveWindowSubclass( m_hwnd, m_wndProc, 0 );
        }
        m_hwnd = 0;
    }
    return( CallNextHookEx( 0, nCode, wParam, lParam ) );
}

Here is WM_DESTROY handler

...
        case WM_DESTROY:
            g_sc->unsubclass( hWnd, ( SUBCLASSPROC )wndProc );
            break;
    }
    return( DefSubclassProc( hwnd, msg, wp, lp ) );

unsubclass() method works similar to subclass(). Of course, in case of calling unsubclass() on WM_DESTROY, direct RemoveWindowSubclass is called instead of SetWindowsHookEx.

psu
  • 111
  • 1
  • 10
  • The usual problem with subclassing a window you don't own is what happens when somebody else does this as well. You're liable to restore a window procedure that's no longer valid if un-subclassing doesn't happen in the correct order. Use WM_NCDESTROY for better odds. – Hans Passant Apr 22 '14 at 19:20
  • Is your comment about SetWindowLong + GWL_WNDPROC? Have you read the question actually? – psu Apr 22 '14 at 19:23
  • @HansPassant: the nice thing about using [`SetWindowSubClass()`](http://msdn.microsoft.com/en-us/library/windows/desktop/bb762102.aspx) is that it allows multiple subclasses at a time, without having to worry about other people's subclassing. That is primarily why it is preferred over `SetWindowsLong/Ptr()` subclassing, which is subject to the pitfall you mention. – Remy Lebeau Apr 23 '14 at 18:41
  • @Remy - as long as that other guy uses it as well. I also consider it unlikely that the OP logs a FALSE return value. But I didn't read the question well enough to see it. – Hans Passant Apr 23 '14 at 18:45
  • Looks like changing WM_DESTROY to WM_NCDESTROY fixes the problem. Any logical explanations? – psu Apr 24 '14 at 05:25
  • Does your code do anything else with g_sc (pointer to the window)? Since WM_DESTROY is called before the window is destroyed, maybe you still have some messages delivered to your class that cause your code to try and perform some actions on the window through g_sc which is no longer really connected to the actual window causing the crash? – o_weisman Apr 24 '14 at 07:29
  • g_sc is CSubclasser2 instance, which does only actions described above - set/remove window subclass. In subclassed window procedure it is used only on window destruction. But even if it did some more events handling, they should not occur after successful RemoveWindowSubclass call, right? – psu Apr 24 '14 at 07:52
  • just found out, that WM_NCDESTROY DOES NOT FIXES the problem :( – psu Apr 25 '14 at 07:08
  • Any suggestion how else to get into window's thread to call SetWindowSubclass? Tried QueueUserAPC(), but apc callback is not called. Trying switch thread's context, but no luck: – psu Apr 28 '14 at 19:26

0 Answers0