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