Changed winproc allocation to be based only on the procedure address,
to avoid the need to keep track of winprocs for each window and class.
This commit is contained in:
parent
958f4c643e
commit
648994c3ef
|
@ -36,13 +36,6 @@ typedef enum
|
|||
WIN_PROC_32W
|
||||
} WINDOWPROCTYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
WIN_PROC_CLASS,
|
||||
WIN_PROC_WINDOW,
|
||||
WIN_PROC_TIMER
|
||||
} WINDOWPROCUSER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WPARAM16 wParam;
|
||||
|
@ -60,9 +53,7 @@ typedef struct
|
|||
struct tagWINDOWPROC;
|
||||
|
||||
extern WNDPROC16 WINPROC_GetProc( WNDPROC proc, WINDOWPROCTYPE type );
|
||||
extern BOOL WINPROC_SetProc( WNDPROC *pFirst, WNDPROC func,
|
||||
WINDOWPROCTYPE type, WINDOWPROCUSER user );
|
||||
extern void WINPROC_FreeProc( WNDPROC proc, WINDOWPROCUSER user );
|
||||
extern WNDPROC WINPROC_AllocProc( WNDPROC func, WINDOWPROCTYPE type );
|
||||
extern WINDOWPROCTYPE WINPROC_GetProcType( WNDPROC proc );
|
||||
|
||||
extern INT WINPROC_MapMsg32ATo32W( HWND hwnd, UINT msg, WPARAM *pwparam,
|
||||
|
|
|
@ -187,20 +187,14 @@ static WNDPROC16 CLASS_SetProc( CLASS *classPtr, WNDPROC newproc, WINDOWPROCTYPE
|
|||
if (!*proc || type == WIN_PROC_32W) proc = &classPtr->winprocW;
|
||||
}
|
||||
ret = WINPROC_GetProc( *proc, type );
|
||||
WINPROC_SetProc( proc, newproc, type, WIN_PROC_CLASS );
|
||||
/* now free the one that we didn't set */
|
||||
*proc = WINPROC_AllocProc( newproc, type );
|
||||
/* now clear the one that we didn't set */
|
||||
if (classPtr->winprocA && classPtr->winprocW)
|
||||
{
|
||||
if (proc == &classPtr->winprocA)
|
||||
{
|
||||
WINPROC_FreeProc( classPtr->winprocW, WIN_PROC_CLASS );
|
||||
classPtr->winprocW = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
WINPROC_FreeProc( classPtr->winprocA, WIN_PROC_CLASS );
|
||||
classPtr->winprocA = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -303,8 +297,6 @@ static void CLASS_FreeClass( CLASS *classPtr )
|
|||
if (classPtr->dce) DCE_FreeDCE( classPtr->dce );
|
||||
if (classPtr->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
|
||||
DeleteObject( classPtr->hbrBackground );
|
||||
WINPROC_FreeProc( classPtr->winprocA, WIN_PROC_CLASS );
|
||||
WINPROC_FreeProc( classPtr->winprocW, WIN_PROC_CLASS );
|
||||
UnMapLS( classPtr->segMenuName );
|
||||
HeapFree( GetProcessHeap(), 0, classPtr->menuName );
|
||||
HeapFree( GetProcessHeap(), 0, classPtr );
|
||||
|
@ -458,10 +450,8 @@ static CLASS *register_builtin( const struct builtin_class_descr *descr )
|
|||
classPtr->hCursor = LoadCursorA( 0, (LPSTR)descr->cursor );
|
||||
classPtr->hbrBackground = descr->brush;
|
||||
|
||||
if (descr->procA) WINPROC_SetProc( &classPtr->winprocA, descr->procA,
|
||||
WIN_PROC_32A, WIN_PROC_CLASS );
|
||||
if (descr->procW) WINPROC_SetProc( &classPtr->winprocW, descr->procW,
|
||||
WIN_PROC_32W, WIN_PROC_CLASS );
|
||||
if (descr->procA) classPtr->winprocA = WINPROC_AllocProc( descr->procA, WIN_PROC_32A );
|
||||
if (descr->procW) classPtr->winprocW = WINPROC_AllocProc( descr->procW, WIN_PROC_32W );
|
||||
release_class_ptr( classPtr );
|
||||
return classPtr;
|
||||
}
|
||||
|
@ -623,8 +613,7 @@ ATOM WINAPI RegisterClassEx16( const WNDCLASSEX16 *wc )
|
|||
classPtr->hCursor = HCURSOR_32(wc->hCursor);
|
||||
classPtr->hbrBackground = HBRUSH_32(wc->hbrBackground);
|
||||
|
||||
WINPROC_SetProc( &classPtr->winprocA, (WNDPROC)wc->lpfnWndProc,
|
||||
WIN_PROC_16, WIN_PROC_CLASS );
|
||||
classPtr->winprocA = WINPROC_AllocProc( (WNDPROC)wc->lpfnWndProc, WIN_PROC_16 );
|
||||
CLASS_SetMenuNameA( classPtr, MapSL(wc->lpszMenuName) );
|
||||
release_class_ptr( classPtr );
|
||||
return atom;
|
||||
|
@ -662,7 +651,7 @@ ATOM WINAPI RegisterClassExA( const WNDCLASSEXA* wc )
|
|||
classPtr->hIconSm = wc->hIconSm;
|
||||
classPtr->hCursor = wc->hCursor;
|
||||
classPtr->hbrBackground = wc->hbrBackground;
|
||||
WINPROC_SetProc( &classPtr->winprocA, wc->lpfnWndProc, WIN_PROC_32A, WIN_PROC_CLASS );
|
||||
classPtr->winprocA = WINPROC_AllocProc( wc->lpfnWndProc, WIN_PROC_32A );
|
||||
CLASS_SetMenuNameA( classPtr, wc->lpszMenuName );
|
||||
release_class_ptr( classPtr );
|
||||
return atom;
|
||||
|
@ -700,7 +689,7 @@ ATOM WINAPI RegisterClassExW( const WNDCLASSEXW* wc )
|
|||
classPtr->hIconSm = wc->hIconSm;
|
||||
classPtr->hCursor = wc->hCursor;
|
||||
classPtr->hbrBackground = wc->hbrBackground;
|
||||
WINPROC_SetProc( &classPtr->winprocW, wc->lpfnWndProc, WIN_PROC_32W, WIN_PROC_CLASS );
|
||||
classPtr->winprocW = WINPROC_AllocProc( wc->lpfnWndProc, WIN_PROC_32W );
|
||||
CLASS_SetMenuNameW( classPtr, wc->lpszMenuName );
|
||||
release_class_ptr( classPtr );
|
||||
return atom;
|
||||
|
|
|
@ -247,7 +247,6 @@ static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
|
|||
}
|
||||
if (dlgInfo->hUserFont) DeleteObject( dlgInfo->hUserFont );
|
||||
if (dlgInfo->hMenu) DestroyMenu( dlgInfo->hMenu );
|
||||
WINPROC_FreeProc( DEFDLG_GetDlgProc( hwnd ), WIN_PROC_WINDOW );
|
||||
HeapFree( GetProcessHeap(), 0, dlgInfo );
|
||||
}
|
||||
/* Window clean-up */
|
||||
|
|
|
@ -77,7 +77,6 @@ static void TIMER_ClearTimer( TIMER * pTimer )
|
|||
pTimer->msg = 0;
|
||||
pTimer->id = 0;
|
||||
pTimer->timeout = 0;
|
||||
WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
|
||||
}
|
||||
|
||||
|
||||
|
@ -172,7 +171,7 @@ static UINT_PTR TIMER_SetTimer( HWND hwnd, UINT_PTR id, UINT timeout,
|
|||
|
||||
if (!hwnd) id = i + 1;
|
||||
|
||||
if (proc) WINPROC_SetProc( &winproc, proc, type, WIN_PROC_TIMER );
|
||||
if (proc) winproc = WINPROC_AllocProc( proc, type );
|
||||
|
||||
SERVER_START_REQ( set_win_timer )
|
||||
{
|
||||
|
|
|
@ -650,7 +650,6 @@ LRESULT WIN_DestroyWindow( HWND hwnd )
|
|||
}
|
||||
DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
|
||||
if (USER_Driver.pDestroyWindow) USER_Driver.pDestroyWindow( hwnd );
|
||||
WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
|
||||
wndPtr->class = NULL;
|
||||
wndPtr->dwMagic = 0; /* Mark it as invalid */
|
||||
WIN_ReleaseWndPtr( wndPtr );
|
||||
|
@ -2058,7 +2057,7 @@ static LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, LONG_PTR newval,
|
|||
}
|
||||
case GWLP_WNDPROC:
|
||||
retval = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, type );
|
||||
WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
|
||||
wndPtr->winproc = WINPROC_AllocProc( (WNDPROC)newval, type );
|
||||
WIN_ReleasePtr( wndPtr );
|
||||
return retval;
|
||||
case GWLP_ID:
|
||||
|
@ -2070,7 +2069,7 @@ static LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, LONG_PTR newval,
|
|||
{
|
||||
WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
|
||||
retval = (ULONG_PTR)WINPROC_GetProc( *ptr, type );
|
||||
WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
|
||||
*ptr = WINPROC_AllocProc( (WNDPROC)newval, type );
|
||||
WIN_ReleasePtr( wndPtr );
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@ WINE_DECLARE_DEBUG_CHANNEL(msg);
|
|||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(win);
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#include "pshpack1.h"
|
||||
|
||||
/* Window procedure 16-to-32-bit thunk */
|
||||
|
@ -78,8 +80,28 @@ typedef struct
|
|||
BYTE jmp; /* jmp proc (relative jump) */
|
||||
WNDPROC proc;
|
||||
} WINPROC_JUMP;
|
||||
|
||||
#include "poppack.h"
|
||||
|
||||
#else /* __i386__ */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WNDPROC proc;
|
||||
} WINPROC_THUNK_FROM16;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WNDPROC16 proc;
|
||||
} WINPROC_THUNK_FROM32;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WNDPROC proc;
|
||||
} WINPROC_JUMP;
|
||||
|
||||
#endif /* __i386__ */
|
||||
|
||||
typedef union
|
||||
{
|
||||
WINPROC_THUNK_FROM16 t_from16;
|
||||
|
@ -88,21 +110,11 @@ typedef union
|
|||
|
||||
typedef struct tagWINDOWPROC
|
||||
{
|
||||
WINPROC_THUNK thunk; /* Thunk */
|
||||
WINPROC_JUMP jmp; /* Jump */
|
||||
struct tagWINDOWPROC *next; /* Next window proc */
|
||||
UINT magic; /* Magic number */
|
||||
WINDOWPROCTYPE type; /* Function type */
|
||||
WINDOWPROCUSER user; /* Function user */
|
||||
WINPROC_THUNK thunk; /* Thunk */
|
||||
WINPROC_JUMP jmp; /* Jump */
|
||||
BYTE type; /* Function type */
|
||||
} WINDOWPROC;
|
||||
|
||||
#define WINPROC_MAGIC ('W' | ('P' << 8) | ('R' << 16) | ('C' << 24))
|
||||
|
||||
#define WINPROC_THUNKPROC(pproc) \
|
||||
(((pproc)->type == WIN_PROC_16) ? \
|
||||
(WNDPROC16)((pproc)->thunk.t_from32.proc) : \
|
||||
(WNDPROC16)((pproc)->thunk.t_from16.proc))
|
||||
|
||||
static LRESULT WINAPI WINPROC_CallProc32ATo16( WNDPROC16 func, HWND hwnd,
|
||||
UINT msg, WPARAM wParam,
|
||||
LPARAM lParam );
|
||||
|
@ -113,7 +125,6 @@ static LRESULT WINAPI WINPROC_CallProc32WTo16( WNDPROC16 func, HWND hwnd,
|
|||
#define MAX_WINPROCS (0x10000 / sizeof(WINDOWPROC))
|
||||
|
||||
static WINDOWPROC winproc_array[MAX_WINPROCS];
|
||||
static WINDOWPROC *winproc_first_free;
|
||||
static UINT winproc_used;
|
||||
|
||||
static CRITICAL_SECTION winproc_cs;
|
||||
|
@ -125,34 +136,109 @@ static CRITICAL_SECTION_DEBUG critsect_debug =
|
|||
};
|
||||
static CRITICAL_SECTION winproc_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
/* allocate a window procedure from the global array */
|
||||
static WINDOWPROC *alloc_winproc(void)
|
||||
{
|
||||
WINDOWPROC *ret = NULL;
|
||||
|
||||
EnterCriticalSection( &winproc_cs );
|
||||
if ((ret = winproc_first_free))
|
||||
winproc_first_free = ret->next;
|
||||
else if (winproc_used < MAX_WINPROCS)
|
||||
ret = &winproc_array[winproc_used++];
|
||||
LeaveCriticalSection( &winproc_cs );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void free_winproc( WINDOWPROC *proc )
|
||||
{
|
||||
EnterCriticalSection( &winproc_cs );
|
||||
proc->magic = 0;
|
||||
proc->next = winproc_first_free;
|
||||
winproc_first_free = proc;
|
||||
LeaveCriticalSection( &winproc_cs );
|
||||
}
|
||||
|
||||
static BOOL is_valid_winproc( WINDOWPROC *proc )
|
||||
{
|
||||
if (proc < winproc_array || proc >= winproc_array + MAX_WINPROCS) return FALSE;
|
||||
/* check array limits */
|
||||
if (proc < winproc_array || proc >= winproc_array + winproc_used) return FALSE;
|
||||
/* check alignment */
|
||||
if (proc != winproc_array + (proc - winproc_array)) return FALSE;
|
||||
return (proc->magic == WINPROC_MAGIC);
|
||||
return (proc->type != WIN_PROC_INVALID);
|
||||
}
|
||||
|
||||
/* find an existing winproc for a given function and type */
|
||||
/* FIXME: probably should do something more clever than a linear search */
|
||||
static inline WINDOWPROC *find_winproc( WNDPROC func, WINDOWPROCTYPE type )
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (type == WIN_PROC_16)
|
||||
{
|
||||
for (i = 0; i < winproc_used; i++)
|
||||
{
|
||||
if (winproc_array[i].type == type &&
|
||||
winproc_array[i].thunk.t_from32.proc == (WNDPROC16)func)
|
||||
return &winproc_array[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < winproc_used; i++)
|
||||
{
|
||||
if (winproc_array[i].type == type &&
|
||||
winproc_array[i].thunk.t_from16.proc == func)
|
||||
return &winproc_array[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* initialize a new winproc */
|
||||
static inline void set_winproc( WINDOWPROC *proc, WNDPROC func, WINDOWPROCTYPE type )
|
||||
{
|
||||
#ifdef __i386__
|
||||
static FARPROC16 relay_32A, relay_32W;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case WIN_PROC_16:
|
||||
proc->thunk.t_from32.popl_eax = 0x58; /* popl %eax */
|
||||
proc->thunk.t_from32.pushl_func = 0x68; /* pushl $proc */
|
||||
proc->thunk.t_from32.proc = (WNDPROC16)func;
|
||||
proc->thunk.t_from32.pushl_eax = 0x50; /* pushl %eax */
|
||||
proc->thunk.t_from32.jmp = 0xe9; /* jmp relay*/
|
||||
proc->thunk.t_from32.relay = /* relative jump */
|
||||
(void(*)())((DWORD)WINPROC_CallProc32ATo16 -
|
||||
(DWORD)(&proc->thunk.t_from32.relay + 1));
|
||||
break;
|
||||
case WIN_PROC_32A:
|
||||
if (!relay_32A) relay_32A = GetProcAddress16( GetModuleHandle16("user"),
|
||||
"__wine_call_wndproc_32A" );
|
||||
proc->thunk.t_from16.popl_eax = 0x58; /* popl %eax */
|
||||
proc->thunk.t_from16.pushl_func = 0x68; /* pushl $proc */
|
||||
proc->thunk.t_from16.proc = func;
|
||||
proc->thunk.t_from16.pushl_eax = 0x50; /* pushl %eax */
|
||||
proc->thunk.t_from16.ljmp = 0xea; /* ljmp relay*/
|
||||
proc->thunk.t_from16.relay_offset = OFFSETOF(relay_32A);
|
||||
proc->thunk.t_from16.relay_sel = SELECTOROF(relay_32A);
|
||||
proc->jmp.jmp = 0xe9;
|
||||
/* Fixup relative jump */
|
||||
proc->jmp.proc = (WNDPROC)((DWORD)func - (DWORD)(&proc->jmp.proc + 1));
|
||||
break;
|
||||
case WIN_PROC_32W:
|
||||
if (!relay_32W) relay_32W = GetProcAddress16( GetModuleHandle16("user"),
|
||||
"__wine_call_wndproc_32W" );
|
||||
proc->thunk.t_from16.popl_eax = 0x58; /* popl %eax */
|
||||
proc->thunk.t_from16.pushl_func = 0x68; /* pushl $proc */
|
||||
proc->thunk.t_from16.proc = func;
|
||||
proc->thunk.t_from16.pushl_eax = 0x50; /* pushl %eax */
|
||||
proc->thunk.t_from16.ljmp = 0xea; /* ljmp relay*/
|
||||
proc->thunk.t_from16.relay_offset = OFFSETOF(relay_32W);
|
||||
proc->thunk.t_from16.relay_sel = SELECTOROF(relay_32W);
|
||||
proc->jmp.jmp = 0xe9;
|
||||
/* Fixup relative jump */
|
||||
proc->jmp.proc = (WNDPROC)((char *)func - (char *)(&proc->jmp.proc + 1));
|
||||
break;
|
||||
default:
|
||||
/* Should not happen */
|
||||
break;
|
||||
}
|
||||
#else /* __i386__ */
|
||||
switch(type)
|
||||
{
|
||||
case WIN_PROC_16:
|
||||
proc->thunk.t_from32.proc = (WNDPROC16)func;
|
||||
break;
|
||||
case WIN_PROC_32A:
|
||||
case WIN_PROC_32W:
|
||||
proc->thunk.t_from16.proc = func;
|
||||
break;
|
||||
default:
|
||||
/* Should not happen */
|
||||
break;
|
||||
}
|
||||
#endif /* __i386__ */
|
||||
|
||||
proc->type = type;
|
||||
}
|
||||
|
||||
static WORD get_winproc_selector(void)
|
||||
|
@ -437,96 +523,15 @@ static WINDOWPROC *WINPROC_GetPtr( WNDPROC handle )
|
|||
|
||||
/* Check for a segmented pointer */
|
||||
|
||||
if (!IsBadReadPtr16( (SEGPTR)handle, sizeof(proc->thunk) ))
|
||||
{
|
||||
ptr = MapSL( (SEGPTR)handle );
|
||||
/* It must be the thunk address */
|
||||
proc = (WINDOWPROC *)(ptr - (int)&((WINDOWPROC *)0)->thunk);
|
||||
if (is_valid_winproc(proc)) return proc;
|
||||
}
|
||||
ptr = MapSL( (SEGPTR)handle );
|
||||
/* It must be the thunk address */
|
||||
proc = (WINDOWPROC *)(ptr - (int)&((WINDOWPROC *)0)->thunk);
|
||||
if (is_valid_winproc(proc)) return proc;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* WINPROC_AllocWinProc
|
||||
*
|
||||
* Allocate a new window procedure.
|
||||
*/
|
||||
static WINDOWPROC *WINPROC_AllocWinProc( WNDPROC func, WINDOWPROCTYPE type,
|
||||
WINDOWPROCUSER user )
|
||||
{
|
||||
static FARPROC16 relay_32A, relay_32W;
|
||||
|
||||
WINDOWPROC *proc, *oldproc;
|
||||
|
||||
/* Allocate a window procedure */
|
||||
|
||||
if (!(proc = alloc_winproc())) return 0;
|
||||
|
||||
/* Check if the function is already a win proc */
|
||||
|
||||
if ((oldproc = WINPROC_GetPtr( func )))
|
||||
{
|
||||
*proc = *oldproc;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case WIN_PROC_16:
|
||||
proc->thunk.t_from32.popl_eax = 0x58; /* popl %eax */
|
||||
proc->thunk.t_from32.pushl_func = 0x68; /* pushl $proc */
|
||||
proc->thunk.t_from32.proc = (WNDPROC16)func;
|
||||
proc->thunk.t_from32.pushl_eax = 0x50; /* pushl %eax */
|
||||
proc->thunk.t_from32.jmp = 0xe9; /* jmp relay*/
|
||||
proc->thunk.t_from32.relay = /* relative jump */
|
||||
(void(*)())((DWORD)WINPROC_CallProc32ATo16 -
|
||||
(DWORD)(&proc->thunk.t_from32.relay + 1));
|
||||
break;
|
||||
case WIN_PROC_32A:
|
||||
if (!relay_32A) relay_32A = GetProcAddress16( GetModuleHandle16("user"),
|
||||
"__wine_call_wndproc_32A" );
|
||||
proc->thunk.t_from16.popl_eax = 0x58; /* popl %eax */
|
||||
proc->thunk.t_from16.pushl_func = 0x68; /* pushl $proc */
|
||||
proc->thunk.t_from16.proc = func;
|
||||
proc->thunk.t_from16.pushl_eax = 0x50; /* pushl %eax */
|
||||
proc->thunk.t_from16.ljmp = 0xea; /* ljmp relay*/
|
||||
proc->thunk.t_from16.relay_offset = OFFSETOF(relay_32A);
|
||||
proc->thunk.t_from16.relay_sel = SELECTOROF(relay_32A);
|
||||
proc->jmp.jmp = 0xe9;
|
||||
/* Fixup relative jump */
|
||||
proc->jmp.proc = (WNDPROC)((DWORD)func - (DWORD)(&proc->jmp.proc + 1));
|
||||
break;
|
||||
case WIN_PROC_32W:
|
||||
if (!relay_32W) relay_32W = GetProcAddress16( GetModuleHandle16("user"),
|
||||
"__wine_call_wndproc_32W" );
|
||||
proc->thunk.t_from16.popl_eax = 0x58; /* popl %eax */
|
||||
proc->thunk.t_from16.pushl_func = 0x68; /* pushl $proc */
|
||||
proc->thunk.t_from16.proc = func;
|
||||
proc->thunk.t_from16.pushl_eax = 0x50; /* pushl %eax */
|
||||
proc->thunk.t_from16.ljmp = 0xea; /* ljmp relay*/
|
||||
proc->thunk.t_from16.relay_offset = OFFSETOF(relay_32W);
|
||||
proc->thunk.t_from16.relay_sel = SELECTOROF(relay_32W);
|
||||
proc->jmp.jmp = 0xe9;
|
||||
/* Fixup relative jump */
|
||||
proc->jmp.proc = (WNDPROC)((char *)func - (char *)(&proc->jmp.proc + 1));
|
||||
break;
|
||||
default:
|
||||
/* Should not happen */
|
||||
break;
|
||||
}
|
||||
proc->magic = WINPROC_MAGIC;
|
||||
proc->type = type;
|
||||
proc->user = user;
|
||||
}
|
||||
proc->next = NULL;
|
||||
TRACE("(%p,%d): returning %p\n", func, type, proc );
|
||||
return proc;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* WINPROC_GetProc
|
||||
*
|
||||
|
@ -560,119 +565,43 @@ WNDPROC16 WINPROC_GetProc( WNDPROC proc, WINDOWPROCTYPE type )
|
|||
|
||||
|
||||
/**********************************************************************
|
||||
* WINPROC_SetProc
|
||||
* WINPROC_AllocProc
|
||||
*
|
||||
* Set the window procedure for a window or class. There are
|
||||
* three tree classes of winproc callbacks:
|
||||
*
|
||||
* 1) class -> wp - not subclassed
|
||||
* class -> wp -> wp -> wp -> wp - SetClassLong()
|
||||
* / /
|
||||
* 2) window -' / - not subclassed
|
||||
* window -> wp -> wp ' - SetWindowLong()
|
||||
*
|
||||
* 3) timer -> wp - SetTimer()
|
||||
*
|
||||
* Initially, winproc of the window points to the current winproc
|
||||
* thunk of its class. Subclassing prepends a new thunk to the
|
||||
* window winproc chain at the head of the list. Thus, window thunk
|
||||
* list includes class thunks and the latter are preserved when the
|
||||
* window is destroyed.
|
||||
* Allocate a window procedure for a window or class.
|
||||
*
|
||||
* Note that allocated winprocs are never freed; the idea is that even if an app creates a
|
||||
* lot of windows, it will usually only have a limited number of window procedures, so the
|
||||
* array won't grow too large, and this way we avoid the need to track allocations per window.
|
||||
*/
|
||||
BOOL WINPROC_SetProc( WNDPROC *pFirst, WNDPROC func,
|
||||
WINDOWPROCTYPE type, WINDOWPROCUSER user )
|
||||
WNDPROC WINPROC_AllocProc( WNDPROC func, WINDOWPROCTYPE type )
|
||||
{
|
||||
BOOL bRecycle = FALSE;
|
||||
WINDOWPROC *proc, **ppPrev;
|
||||
WINDOWPROC *proc;
|
||||
|
||||
/* Check if function is already in the list */
|
||||
if (!func) return NULL;
|
||||
|
||||
ppPrev = (WINDOWPROC **)pFirst;
|
||||
proc = WINPROC_GetPtr( func );
|
||||
while (*ppPrev)
|
||||
EnterCriticalSection( &winproc_cs );
|
||||
|
||||
/* check if the function is already a win proc */
|
||||
if (!(proc = WINPROC_GetPtr( func )))
|
||||
{
|
||||
if (proc)
|
||||
/* then check if we already have a winproc for that function */
|
||||
if (!(proc = find_winproc( func, type )))
|
||||
{
|
||||
if (*ppPrev == proc)
|
||||
if (winproc_used >= MAX_WINPROCS)
|
||||
FIXME( "too many winprocs, cannot allocate one for %p/%d\n", func, type );
|
||||
else
|
||||
{
|
||||
if ((*ppPrev)->user != user)
|
||||
{
|
||||
/* terminal thunk is being restored */
|
||||
|
||||
WINPROC_FreeProc( *pFirst, (*ppPrev)->user );
|
||||
*(WINDOWPROC **)pFirst = *ppPrev;
|
||||
return TRUE;
|
||||
}
|
||||
bRecycle = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((*ppPrev)->type == type) &&
|
||||
(func == (WNDPROC)WINPROC_THUNKPROC(*ppPrev)))
|
||||
{
|
||||
if((*ppPrev)->user == user)
|
||||
{
|
||||
bRecycle = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
WINPROC_FreeProc( (WNDPROC)*ppPrev, user );
|
||||
*ppPrev = NULL;
|
||||
}
|
||||
break;
|
||||
proc = &winproc_array[winproc_used++];
|
||||
set_winproc( proc, func, type );
|
||||
TRACE( "allocated %p for %p/%d (%d/%d used)\n",
|
||||
proc, func, type, winproc_used, MAX_WINPROCS );
|
||||
}
|
||||
}
|
||||
|
||||
/* WPF_CLASS thunk terminates window thunk list */
|
||||
if ((*ppPrev)->user != user) break;
|
||||
ppPrev = &(*ppPrev)->next;
|
||||
else TRACE( "reusing %p for %p/%d\n", proc, func, type );
|
||||
}
|
||||
|
||||
if (bRecycle)
|
||||
{
|
||||
/* Extract this thunk from the list */
|
||||
proc = *ppPrev;
|
||||
*ppPrev = proc->next;
|
||||
}
|
||||
else /* Allocate a new one */
|
||||
{
|
||||
if (proc) /* Was already a win proc */
|
||||
{
|
||||
type = proc->type;
|
||||
func = (WNDPROC)WINPROC_THUNKPROC(proc);
|
||||
}
|
||||
proc = WINPROC_AllocWinProc( func, type, user );
|
||||
if (!proc) return FALSE;
|
||||
}
|
||||
|
||||
/* Add the win proc at the head of the list */
|
||||
|
||||
TRACE("(%p,%p,%d): res=%p\n", *pFirst, func, type, proc );
|
||||
proc->next = *(WINDOWPROC **)pFirst;
|
||||
*(WINDOWPROC **)pFirst = proc;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* WINPROC_FreeProc
|
||||
*
|
||||
* Free a list of win procs.
|
||||
*/
|
||||
void WINPROC_FreeProc( WNDPROC proc, WINDOWPROCUSER user )
|
||||
{
|
||||
WINDOWPROC *ptr = (WINDOWPROC *)proc;
|
||||
while (ptr)
|
||||
{
|
||||
WINDOWPROC *next = ptr->next;
|
||||
if (ptr->user != user) break;
|
||||
TRACE("freeing %p (%d)\n", ptr, user);
|
||||
free_winproc( ptr );
|
||||
ptr = next;
|
||||
}
|
||||
LeaveCriticalSection( &winproc_cs );
|
||||
return (WNDPROC)proc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -683,9 +612,7 @@ void WINPROC_FreeProc( WNDPROC proc, WINDOWPROCUSER user )
|
|||
*/
|
||||
WINDOWPROCTYPE WINPROC_GetProcType( WNDPROC proc )
|
||||
{
|
||||
if (!proc ||
|
||||
(((WINDOWPROC *)proc)->magic != WINPROC_MAGIC))
|
||||
return WIN_PROC_INVALID;
|
||||
if (!proc) return WIN_PROC_INVALID;
|
||||
return ((WINDOWPROC *)proc)->type;
|
||||
}
|
||||
/**********************************************************************
|
||||
|
|
Loading…
Reference in New Issue