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