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 7 of 15)
March 2000/User Interface Programming/Listing 4

Listing 4: subtest.c — Test program

#include "internal.h"
#include "resource.h"
#include <stdarg.h>

#ifndef _UNITTEST_
#error subtest.c requires definition of _UNITTEST_
#endif // _UNITTEST_

#define Edit_Append( hwnd, psz ) \
    (Edit_SetSel( hwnd, -1, -1 ), Edit_ReplaceSel( hwnd, psz ))
#define Edit_Clear( hwnd ) \
    (Edit_SetSel( hwnd, 0, -1 ), Edit_ReplaceSel( hwnd, _T( "" ) ))
#define isCareful( hwnd ) \
    ( 0 != Button_GetCheck( GetDlgItem( hwnd, IDC_CAREFUL ) ) )

typedef BOOL (WINAPI *BEEPPROC)( UINT );

static WNDPROC s_tracerOldProc, s_upperOldProc;

void trace( HWND hwnd, LPCTSTR psz ) {
    HWND hwndDiag = GetDlgItem( GetParent(hwnd), IDC_DIAGNOSTICS );
    Edit_Append( hwndDiag, psz );
    OutputDebugString( psz );
}

void __cdecl tracef( HWND hwnd, LPCTSTR pszFmt, ... ) {
    TCHAR sz[ 1000 ];
    va_list vl;
    va_start( vl, pszFmt );
    wvsprintf( sz, pszFmt, vl );
    va_end( vl );
    trace( hwnd, sz );
}

WNDPROC subclass( HWND hwnd, WNDPROC newProc ) {
    assert( getWndProc( hwnd ) != newProc );
    trace2( hwnd, _T( "hooking %s, saving %s\r\n" ),
        getProcName( newProc ), getProcName( getWndProc( hwnd )) );
    return SubclassWindow( hwnd, newProc );
}

BOOL unsubclass( HWND hwnd, WNDPROC saved, WNDPROC expected ) {
    WNDPROC curr = getWndProc( hwnd );

    trace2( hwnd, _T( "unhooking %s, restoring %s\r\n" ),
        getProcName( expected ), getProcName( saved ) );
    if ( curr != expected ) {
        trace2( hwnd, _T( "expected wndproc %s, found %s\r\n" ),
            getProcName( expected ), getProcName( curr ) );
        if ( !isCareful( GetParent( hwnd ) ) ) {
            trace( hwnd, _T( "throwing out old proc!\r\n" ) );
        }
    }
    if ( expected == saved ) {
        trace2( hwnd,
            _T( "expected wndproc %s equals saved wndproc %s\r\n" ),
            getProcName( expected ), getProcName( saved ) );
    }
    if ( curr == expected || !isCareful( GetParent( hwnd ) ) ) {
        SubclassWindow( hwnd, saved );
        return TRUE;
    }
    return FALSE;
}

LRESULT CALLBACK tracer( HWND hwnd, UINT msg, WPARAM w, LPARAM l ) {
    TCHAR szMsg[ 100 ];
    if ( WM_CHAR == msg ) {
        trace1( hwnd, _T( "WM_CHAR trace: '%c'\r\n" ), (TCHAR) w );
        wsprintf( szMsg, _T( "%#x: WM_CHAR = '%c', %#x\r\n" ), 
            hwnd, w, l );
        Edit_Append( GetDlgItem( GetParent( hwnd ), IDC_MESSAGES ),
            szMsg );
    } else if ( WM_DESTROY == msg ) {
        trace( hwnd, _T( "unhooking tracer on WM_DESTROY\r\n" ) );
        unsubclass( hwnd, s_tracerOldProc, tracer );
    }
    return CallWindowProc( s_tracerOldProc, hwnd, msg, w, l );
}

LRESULT CALLBACK upper( HWND hwnd, UINT msg, WPARAM w, LPARAM l ) {
    if ( WM_CHAR == msg ) {
        trace1( hwnd, _T( "WM_CHAR upper: '%c'\r\n" ), (TCHAR) w );
        w = _totupper( (TCHAR) w );
    } else if ( WM_NCDESTROY == msg ) {
        trace( hwnd, _T( "unhooking upper on WM_NCDESTROY\r\n" ) );
        unsubclass( hwnd, s_upperOldProc, upper );
    }
    return CallWindowProc( s_upperOldProc, hwnd, msg, w, l );
}

LRESULT CALLBACK digits( HWND hwnd, UINT msg, WPARAM w, LPARAM l ) {
    if ( WM_CHAR == msg ) {
        trace1( hwnd, _T( "WM_CHAR digits: '%c'\r\n" ), (TCHAR) w );
        if ( 0 == _tcschr( wdjGetData(digits, hwnd), (TCHAR) w ) ) {
            return 0; //*** EAT THE KEYSTROKE!
        }
    }
    return wdjCallOldProc( digits, hwnd, msg, w, l );
}

LRESULT CALLBACK hex( HWND hwnd, UINT msg, WPARAM w, LPARAM l ) {
    if ( WM_CHAR == msg ) {
        trace1( hwnd, _T( "WM_CHAR hex: '%c'\r\n" ), (TCHAR) w );
        if ( 0 == _tcschr( wdjGetData( hex, hwnd ), (TCHAR) w ) ) {
            return 0; //*** EAT THE KEYSTROKE!
        }
    }
    return wdjCallOldProc( hex, hwnd, msg, w, l );
}

LRESULT CALLBACK beep( HWND hwnd, UINT msg, WPARAM w, LPARAM l ) {
    if ( WM_CHAR == msg ) {
        trace1( hwnd, _T( "WM_CHAR beep: '%c'\r\n" ), (TCHAR) w );
        ((BEEPPROC) wdjGetData( beep, hwnd ))( MB_ICONWARNING );
    }
    return wdjCallOldProc( beep, hwnd, msg, w, l );
}


//   assert( GetCurrentThreadId() == GetWindowThreadProcessId( hwnd, 0 ) );

LPCTSTR getProcName( WNDPROC wndProc ) {
    #define NUMBUFS 4
    #define BUFLEN 20
    static int nBuf = 0;
    static TCHAR aszBufs[ NUMBUFS ][ BUFLEN ];

    LPCTSTR pszName = 0;
    if ( beep   == wndProc ) { pszName = _T( "beep"   ); }
    if ( hex    == wndProc ) { pszName = _T( "hex"    ); }
    if ( digits == wndProc ) { pszName = _T( "digits" ); }
    if ( upper  == wndProc ) { pszName = _T( "upper"  ); }
    if ( tracer == wndProc ) { pszName = _T( "tracer" ); }
    if ( 0      == wndProc ) { pszName = _T( "null"   ); }

    nBuf = (nBuf + 1) % NUMBUFS;
    if ( 0 != pszName ) {
        wsprintf( aszBufs[ nBuf ], _T( "%s" ), pszName );
    } else {
        wsprintf( aszBufs[ nBuf ], _T( "%#x" ), wndProc );
    }
    return aszBufs[ nBuf ];
}

static void updateStack( HWND hwnd ) {
    #define SET_NEXT( saved )                        \
        if ( curr == saved ) { ListBox_InsertString( \
            hwndStack, i++, _T( "infinite loop" ) ); \
            return; } curr = saved

    HWND hwndEdit  = GetDlgItem( hwnd, IDC_TESTEDIT );
    HWND hwndStack = GetDlgItem( hwnd, IDC_STACK    );
    WNDPROC curr = getWndProc( hwndEdit );
    int i = 0;
    ListBox_ResetContent( hwndStack );
    for ( ;; ) {
        ListBox_InsertString( hwndStack, i++, getProcName( curr ) );
        if ( curr == tracer ) {
            SET_NEXT( s_tracerOldProc );
        } else if ( curr == upper ) {
            SET_NEXT( s_upperOldProc );
        } else {
            SUBCLASSING *p = getHead( hwndEdit );
            while ( 0 != p && p->wndProc != curr ) {
                p = p->pNext;
            }
            if ( 0 != p ) {
                SET_NEXT( p->wndProcSaved );
            } else {         // Presumably original edit proc
                return;      //*** FUNCTION EXIT POINT
            }
        }
    }
}

BOOL onInitDialog( HWND hwnd ) {
    updateStack( hwnd );
    Button_SetCheck( GetDlgItem( hwnd, IDC_CAREFUL ), 1 );
    SetFocus( GetDlgItem( hwnd, IDC_TESTEDIT ) );
    return FALSE;            // ...since we set the focus.
}

BOOL onClicked( HWND hwnd, int id, HWND hwndCtl ) {
    HWND hwndEdit = GetDlgItem( hwnd, IDC_TESTEDIT );

    #define HANDLE_WDJ( proc, data )                   \
        if ( Button_GetCheck( hwndCtl ) )              \
            wdjSubclass( proc, hwndEdit, data );       \
        else if ( !wdjUnhook( proc, hwndEdit) )        \
            Button_SetCheck( hwndCtl, 1 );
    #define HANDLE_FOREIGN( proc, old )                \
        if ( Button_GetCheck( hwndCtl ) )              \
            old = subclass( hwndEdit, proc );          \
        else if ( !unsubclass( hwndEdit, old, proc ) ) \
            Button_SetCheck( hwndCtl, 1 );

    switch ( id ) {
    case IDOK:
    case IDCANCEL:
        EndDialog( hwnd, id );                              break;
    case IDC_DIGITS:
        HANDLE_WDJ( digits, _T( "0123456789" ) );           break;
    case IDC_HEX:
        HANDLE_WDJ( hex, _T( "0123456789abcdefgABCDEF" ) ); break;
    case IDC_BEEP:
        HANDLE_WDJ( beep, MessageBeep );                    break;
    case IDC_TRACING:
        HANDLE_FOREIGN( tracer, s_tracerOldProc );          break;
    case IDC_UPPER_CASE:
        HANDLE_FOREIGN( upper, s_upperOldProc );            break;
    case IDC_CLEAR:
        Edit_Clear( GetDlgItem( hwnd, IDC_DIAGNOSTICS ) );
        Edit_Clear( GetDlgItem( hwnd, IDC_MESSAGES    ) );  break;
    case IDC_DESTROY:
        FORWARD_WM_NEXTDLGCTL( hwnd, GetDlgItem( hwnd, 
            IDC_DIAGNOSTICS ), TRUE, SNDMSG );
        EnableWindow( GetDlgItem( hwnd, IDC_DIGITS     ), FALSE );
        EnableWindow( GetDlgItem( hwnd, IDC_HEX        ), FALSE );
        EnableWindow( GetDlgItem( hwnd, IDC_BEEP       ), FALSE );
        EnableWindow( GetDlgItem( hwnd, IDC_TRACING    ), FALSE );
        EnableWindow( GetDlgItem( hwnd, IDC_UPPER_CASE ), FALSE );
        EnableWindow( GetDlgItem( hwnd, IDC_DESTROY    ), FALSE );
        EnableWindow( GetDlgItem( hwnd, IDC_CAREFUL    ), FALSE );
        DestroyWindow( hwndEdit ); //*** Goodbye!
        break;
    }
    updateStack( hwnd );
    return TRUE;
}

BOOL CALLBACK dlgFunc( HWND hwnd, UINT msg, WPARAM w, LPARAM l ) {
    if ( WM_INITDIALOG == msg ) {
        return onInitDialog( hwnd );
    } else if ( WM_COMMAND == msg ) {
        return BN_CLICKED == GET_WM_COMMAND_CMD ( w, l ) &&
            onClicked( hwnd, GET_WM_COMMAND_ID  ( w, l ) ,
                             GET_WM_COMMAND_HWND( w, l ) );
    }
    return FALSE;
}

int APIENTRY WinMain( HINSTANCE h, HINSTANCE h2, LPSTR p, int n ) {
    return DialogBox( h, _T( "TestDlg" ), HWND_DESKTOP, dlgFunc );
}
// 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