FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
Dobbs M-Dev
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
March 01, 2000

User Interface Programming

(Page 13 of 15)
March 2000/User Interface Programming/Listing 3

Listing 3: wdjsub.c — Source for subclassing library

#include "internal.h"

static ATOM s_prop = 0;
#define PROP_NAME MAKEINTRESOURCE( s_prop )

LPCTSTR getPropertyName( void ) { return PROP_NAME; }

static BOOL allocPropertyName( void ) {
    s_prop = GlobalAddAtom( _T( "wdj_sub_root" ) );
    assert( 0 != s_prop );
    return 0 != s_prop;
}

static void releasePropertyName( void ) {
    assert( 0 != s_prop );
    verify( 0 == GlobalDeleteAtom( s_prop ) );
}

static SUBCLASSING *find( WNDPROC wndProc, HWND hwnd ) {
    SUBCLASSING *p = getHead( hwnd );
    assert( IsWindow( hwnd ) );
    while ( 0 != p && wndProc != p->wndProc ) {
        p = p->pNext;
    }
    return p;
}

static BOOL setHead( HWND hwnd, const SUBCLASSING *pHead ) {
    if( 0 != GetProp( hwnd, getPropertyName() ) ) {
        verify( RemoveProp( hwnd, getPropertyName() ) );
    }
    if ( 0 != pHead ) {
        verify( SetProp( hwnd, getPropertyName(), (HANDLE)pHead ) );
    }
    return (HANDLE) pHead == GetProp( hwnd, getPropertyName() );
}

static BOOL initNode( HWND hwnd, SUBCLASSING *p, 
    WNDPROC wndProc, void *pData, SUBCLASSING *pNext ) 
{
    p->wndProc      = wndProc;
    p->pData        = pData;
    p->pNext        = pNext;
    p->wndProcSaved = SubclassWindow( hwnd, wndProc );
    assert( 0 != p->wndProcSaved );
    return  0 != p->wndProcSaved;
}

BOOL wdjSubclass( WNDPROC wndProc, HWND hwnd, void *pData ) {
    SUBCLASSING *pHead = getHead( hwnd );
    SUBCLASSING *pThis = find( wndProc, hwnd );
    WNDPROC curr = getWndProc( hwnd );

    assert( IsWindow( hwnd ) );
    assert( GetCurrentThreadId() == 
       GetWindowThreadProcessId( hwnd, 0 ) );
    trace2( hwnd, _T( "wdjSubclass %s (saving %s)\r\n" ),
        getProcName( wndProc ), getProcName( curr ) ); 
    if ( 0 != pThis || curr == wndProc ) {
        trace1( hwnd, _T( "wdjSubclass: %s already exists\r\n" ),
            getProcName( wndProc ) );
        return FALSE; //*** FUNCTION EXIT POINT
    }
#ifdef _DEBUG
    if ( 0 != pHead && pHead->wndProc != curr ) {
        trace2( hwnd, _T( "warning: %s blocks %s\r\n" ),
            getProcName( curr ), getProcName( pHead->wndProc ) );
    }
#endif // _DEBUG
    if ( allocPropertyName() ) {
        if ( 0 != (pThis = malloc( sizeof( *pThis ) ) ) ) {
            if ( initNode( hwnd, pThis, wndProc, pData, pHead ) ) {
                if ( setHead( hwnd, pThis ) ) {
                    return TRUE; //*** FUNCTION EXIT POINT
                }
                SubclassWindow( hwnd, pThis->wndProcSaved );
                trace1( hwnd, _T( "wdjSubclass: Can't set %s\r\n" ),
                    getProcName( wndProc ) );
            } else {
                trace1( hwnd, _T( "wdjSubclass: %s failed\r\n" ),
                    getProcName( wndProc ) );
            }
            free( pThis );
        } else {
            trace( hwnd, _T( "wdjSubclass: Out of memory\r\n" ) );
        }
        releasePropertyName();
    }
    return FALSE;
}

BOOL wdjUnhook( WNDPROC id, HWND hwnd ) {
    SUBCLASSING *pHead = getHead( hwnd );
    SUBCLASSING *pThis = find( id, hwnd );
    const WNDPROC curr = getWndProc( hwnd );

    assert( IsWindow( hwnd ) );
    assert( GetCurrentThreadId() == 
       GetWindowThreadProcessId( hwnd, 0 ) );
    trace1( hwnd, _T( "wdjUnhook %s\r\n" ), getProcName( id ) );
    if ( 0 == pThis ) {
        trace1( hwnd,  _T( "wdjUnhook: %s does not exist\r\n" ),
            getProcName( id ) );
        return FALSE; //*** FUNCTION EXIT POINT
    }
    if ( pHead == pThis ) {
        if ( curr != id ) {
            trace2( hwnd, _T( "wdjUnhook found %s instead " )
                _T( "of %s at top of stack; NOT unhooking\r\n" ),
               getProcName( curr ), getProcName( id ) );
            return FALSE; //*** FUNCTION EXIT POINT
        }
        SubclassWindow( hwnd, pThis->wndProcSaved );
        verify( setHead( hwnd, pThis->pNext ) );
    } else {
        SUBCLASSING *pPrev = pHead;
        while ( pPrev->pNext != pThis ) {
            pPrev = pPrev->pNext;
        }
        assert( pPrev->pNext == pThis );
        if ( pPrev->wndProcSaved != id ) {
            trace3( hwnd, _T( "wdjUnhook: %s has come " )
                _T( "between %s and %s\r\nNOT unhooking\r\n" ),
                getProcName( pPrev->wndProcSaved ),
                getProcName( pPrev->wndProc ), getProcName( id ) );
            return FALSE; //*** FUNCTION EXIT POINT
        }
        pPrev->pNext        = pThis->pNext;
        pPrev->wndProcSaved = pThis->wndProcSaved;
    }
    free( pThis );
    releasePropertyName();
    return TRUE;
}

LRESULT wdjCallOldProc( 
    WNDPROC id, HWND hwnd, UINT msg, WPARAM w, LPARAM l )
{
    LRESULT lResult = 0;
    const SUBCLASSING *pThis = find( id, hwnd );
    if ( 0 != pThis ) {
        const WNDPROC oldProc = pThis->wndProcSaved;
        assert( 0 != oldProc );
        if ( WM_DESTROY == msg || WM_NCDESTROY == msg ) {
            if ( wdjUnhook( id, hwnd ) ) {
                trace1( hwnd,
                    _T( "wdjCallOldProc: OK %s auto unhook\r\n" ),
                    getProcName( id ) );
            } else {
                trace1( hwnd,
                    _T( "wdjCallOldProc: no %s auto unhook\r\n" ),
                    getProcName( id ) );
            }
        }
        if ( 0 != oldProc ) {
            lResult = CallWindowProc( oldProc, hwnd, msg, w, l );
        } else { // TODO: Discuss DefWindowProc
            trace1( hwnd,
                _T( "wdjCallOldProc: didn't get %s old proc\r\n" ),
                getProcName( id ) );
        }
    } else {
        trace1( hwnd, _T( "wdjCallOldProc: %s not found\r\n" ),
            getProcName( id ) );
    }

    return lResult;
}

void *wdjGetData( WNDPROC id, HWND hwnd ) {
    const SUBCLASSING *pThis = find( id, hwnd );
    return 0 != pThis ? pThis->pData : 0;
}
// End of File
Previous Page | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 Next Page
TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK