Alexandre Julliard : user:
Allocate 16-bit thunks separately from the window proc structure.
Alexandre Julliard
julliard at wine.codeweavers.com
Wed May 17 14:48:25 CDT 2006
Module: wine
Branch: refs/heads/master
Commit: 2a809c195dc118f839a43b4e6fcf09d1d3ae31d1
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=2a809c195dc118f839a43b4e6fcf09d1d3ae31d1
Author: Alexandre Julliard <julliard at winehq.org>
Date: Wed May 17 13:51:37 2006 +0200
user: Allocate 16-bit thunks separately from the window proc structure.
Also make sure the thunk memory block has execute permissions.
---
dlls/user/winproc.c | 188 +++++++++++++++++++++++++++------------------------
1 files changed, 101 insertions(+), 87 deletions(-)
diff --git a/dlls/user/winproc.c b/dlls/user/winproc.c
index d01f137..5a40111 100644
--- a/dlls/user/winproc.c
+++ b/dlls/user/winproc.c
@@ -45,36 +45,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 */
-typedef struct
-{
- BYTE popl_eax; /* popl %eax (return address) */
- BYTE pushl_func; /* pushl $proc */
- struct tagWINDOWPROC *proc;
- BYTE pushl_eax; /* pushl %eax */
- BYTE ljmp; /* ljmp relay*/
- DWORD relay_offset; /* __wine_call_wndproc */
- WORD relay_sel;
-} WINPROC_THUNK;
-
-#include "poppack.h"
-
-#else /* __i386__ */
-
-typedef struct
-{
- WNDPROC proc;
-} WINPROC_THUNK;
-
-#endif /* __i386__ */
-
typedef struct tagWINDOWPROC
{
- WINPROC_THUNK thunk; /* Thunk */
BYTE type; /* Function type */
union
{
@@ -106,15 +78,6 @@ static CRITICAL_SECTION_DEBUG critsect_d
};
static CRITICAL_SECTION winproc_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
-static BOOL is_valid_winproc( WINDOWPROC *proc )
-{
- /* check alignment */
- if (((BYTE *)proc - (BYTE *)winproc_array) % sizeof(*proc)) return FALSE;
- /* check array limits */
- if (proc < winproc_array || proc >= winproc_array + winproc_used) return FALSE;
- return (proc->type != WIN_PROC_INVALID);
-}
-
/* find an existing winproc for a given 16-bit function and type */
/* FIXME: probably should do something more clever than a linear search */
static inline WINDOWPROC *find_winproc16( WNDPROC16 func )
@@ -151,43 +114,9 @@ static inline WINDOWPROC *init_winproc(v
if (winproc_used >= MAX_WINPROCS) return NULL;
proc = &winproc_array[winproc_used++];
-#ifdef __i386__
- {
- static FARPROC16 relay;
-
- if (!relay) relay = GetProcAddress16( GetModuleHandle16("user"), "__wine_call_wndproc" );
-
- proc->thunk.popl_eax = 0x58; /* popl %eax */
- proc->thunk.pushl_func = 0x68; /* pushl $proc */
- proc->thunk.proc = proc;
- proc->thunk.pushl_eax = 0x50; /* pushl %eax */
- proc->thunk.ljmp = 0xea; /* ljmp relay*/
- proc->thunk.relay_offset = OFFSETOF(relay);
- proc->thunk.relay_sel = SELECTOROF(relay);
- }
-#endif /* __i386__ */
return proc;
}
-static WORD get_winproc_selector(void)
-{
- static LONG winproc_selector;
- WORD ret;
-
- if (!(ret = winproc_selector))
- {
- LDT_ENTRY entry;
- WORD sel = wine_ldt_alloc_entries(1);
- wine_ldt_set_base( &entry, winproc_array );
- wine_ldt_set_limit( &entry, sizeof(winproc_array) - 1 );
- wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
- wine_ldt_set_entry( sel, &entry );
- if (!(ret = InterlockedCompareExchange( &winproc_selector, sel, 0 ))) ret = sel;
- else wine_ldt_free_entries( sel, 1 ); /* somebody beat us to it */
- }
- return ret;
-}
-
/* return the window proc for a given handle, or NULL for an invalid handle */
static inline WINDOWPROC *handle_to_proc( WNDPROC handle )
{
@@ -197,20 +126,6 @@ static inline WINDOWPROC *handle_to_proc
return &winproc_array[index];
}
-/* return the window proc for a given handle, or NULL for an invalid handle */
-static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
-{
- if (HIWORD(handle) == get_winproc_selector())
- {
- BYTE *ptr = (BYTE *)winproc_array + LOWORD(handle);
- /* It must be the thunk address */
- WINDOWPROC *proc = (WINDOWPROC *)(ptr - FIELD_OFFSET(WINDOWPROC,thunk));
- if (is_valid_winproc(proc)) return proc;
- return NULL;
- }
- return handle_to_proc( (WNDPROC)handle );
-}
-
/* create a handle for a given window proc */
static inline WNDPROC proc_to_handle( WINDOWPROC *proc )
{
@@ -249,6 +164,106 @@ static inline WINDOWPROC *alloc_winproc(
#ifdef __i386__
+
+#include "pshpack1.h"
+
+/* Window procedure 16-to-32-bit thunk */
+typedef struct
+{
+ BYTE popl_eax; /* popl %eax (return address) */
+ BYTE pushl_func; /* pushl $proc */
+ WINDOWPROC *proc;
+ BYTE pushl_eax; /* pushl %eax */
+ BYTE ljmp; /* ljmp relay*/
+ DWORD relay_offset; /* __wine_call_wndproc */
+ WORD relay_sel;
+} WINPROC_THUNK;
+
+#include "poppack.h"
+
+#define MAX_THUNKS (0x10000 / sizeof(WINPROC_THUNK))
+
+static WINPROC_THUNK *thunk_array;
+static UINT thunk_selector;
+static UINT thunk_used;
+
+/* return the window proc for a given handle, or NULL for an invalid handle */
+static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
+{
+ if (HIWORD(handle) == thunk_selector)
+ {
+ UINT index = LOWORD(handle) / sizeof(WINPROC_THUNK);
+ /* check alignment */
+ if (index * sizeof(WINPROC_THUNK) != LOWORD(handle)) return NULL;
+ /* check array limits */
+ if (index >= thunk_used) return NULL;
+ return thunk_array[index].proc;
+ }
+ return handle_to_proc( (WNDPROC)handle );
+}
+
+/* allocate a 16-bit thunk for an existing window proc */
+static WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc )
+{
+ static FARPROC16 relay;
+ WNDPROC16 ret = 0;
+ UINT i;
+
+ EnterCriticalSection( &winproc_cs );
+
+ if (!thunk_array) /* allocate the array and its selector */
+ {
+ LDT_ENTRY entry;
+
+ if (!(thunk_selector = wine_ldt_alloc_entries(1))) goto done;
+ if (!(thunk_array = VirtualAlloc( NULL, MAX_THUNKS * sizeof(WINPROC_THUNK), MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE ))) goto done;
+ wine_ldt_set_base( &entry, thunk_array );
+ wine_ldt_set_limit( &entry, MAX_THUNKS * sizeof(WINPROC_THUNK) - 1 );
+ wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
+ wine_ldt_set_entry( thunk_selector, &entry );
+ relay = GetProcAddress16( GetModuleHandle16("user"), "__wine_call_wndproc" );
+ }
+
+ /* check if it already exists */
+ for (i = 0; i < thunk_used; i++) if (thunk_array[i].proc == proc) break;
+
+ if (i == thunk_used) /* create a new one */
+ {
+ WINPROC_THUNK *thunk;
+
+ if (thunk_used >= MAX_THUNKS) goto done;
+ thunk = &thunk_array[thunk_used++];
+ thunk->popl_eax = 0x58; /* popl %eax */
+ thunk->pushl_func = 0x68; /* pushl $proc */
+ thunk->proc = proc;
+ thunk->pushl_eax = 0x50; /* pushl %eax */
+ thunk->ljmp = 0xea; /* ljmp relay*/
+ thunk->relay_offset = OFFSETOF(relay);
+ thunk->relay_sel = SELECTOROF(relay);
+ }
+ ret = (WNDPROC16)MAKESEGPTR( thunk_selector, i * sizeof(WINPROC_THUNK) );
+done:
+ LeaveCriticalSection( &winproc_cs );
+ return ret;
+}
+
+#else /* __i386__ */
+
+static inline WINDOWPROC *handle16_to_proc( WNDPROC16 handle )
+{
+ return handle_to_proc( (WNDPROC)handle );
+}
+
+static inline WNDPROC16 alloc_win16_thunk( WINDOWPROC *proc )
+{
+ return 0;
+}
+
+#endif /* __i386__ */
+
+
+#ifdef __i386__
/* Some window procedures modify register they shouldn't, or are not
* properly declared stdcall; so we need a small assembly wrapper to
* call them. */
@@ -495,8 +510,7 @@ WNDPROC16 WINPROC_GetProc16( WNDPROC pro
if (ptr->type == WIN_PROC_16)
return ptr->u.proc16;
else
- return (WNDPROC16)MAKESEGPTR( get_winproc_selector(),
- (char *)&ptr->thunk - (char *)winproc_array );
+ return alloc_win16_thunk( ptr );
}
More information about the wine-cvs
mailing list