March 01, 2000
User Interface Programming
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
| |||||||||