Changed winproc allocation to be based only on the procedure address,
authorAlexandre Julliard <julliard@winehq.org>
Wed, 24 Nov 2004 18:43:18 +0000 (18:43 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Wed, 24 Nov 2004 18:43:18 +0000 (18:43 +0000)
to avoid the need to keep track of winprocs for each window and class.

dlls/user/winproc.h
windows/class.c
windows/defdlg.c
windows/timer.c
windows/win.c
windows/winproc.c

index dd5ea18c80879387d1493271f7618dcbaa7e58f9..6cfc515d9df588509173de11577767ced69a66e7 100644 (file)
@@ -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,
index 0c7cdc953b8b30fcb6409910305ed2c7263f426e..f8a0538e7048b7921d7caf0a437c2c6c78cd96c6 100644 (file)
@@ -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;
index 4f81462103fb24da0e34649385c02ffa3b1389c1..5ed5b9e75efa6ab82e561f9ad73d043503dafc62 100644 (file)
@@ -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 */
index 30d4677a8bac38da96c79775ab8e7fd2a6939090..c3d2870417171679aeb3e38fe333f5a3a51955fa 100644 (file)
@@ -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 )
     {
index bad768562aeafbabb5b3d99660ba464a3029e5dc..f6387f9f413305f5028482837e7c0895cc4b4eb8 100644 (file)
@@ -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;
         }
index c6fcc472fd35abfac663da31f830a27ff5e649e6..ca145253c1f19f9fee7d347d76b6aa564b140e8d 100644 (file)
@@ -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)
+static BOOL is_valid_winproc( WINDOWPROC *proc )
 {
-    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;
+    /* 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->type != WIN_PROC_INVALID);
 }
 
-static void free_winproc( WINDOWPROC *proc )
+/* 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 )
 {
-    EnterCriticalSection( &winproc_cs );
-    proc->magic = 0;
-    proc->next  = winproc_first_free;
-    winproc_first_free = proc;
-    LeaveCriticalSection( &winproc_cs );
+    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;
 }
 
-static BOOL is_valid_winproc( WINDOWPROC *proc )
+/* initialize a new winproc */
+static inline void set_winproc( WINDOWPROC *proc, WNDPROC func, WINDOWPROCTYPE type )
 {
-    if (proc < winproc_array || proc >= winproc_array + MAX_WINPROCS) return FALSE;
-    if (proc != winproc_array + (proc - winproc_array)) return FALSE;
-    return (proc->magic == WINPROC_MAGIC);
+#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
- *
- * Set the window procedure for a window or class. There are
- * three tree classes of winproc callbacks:
+ *          WINPROC_AllocProc
  *
- * 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)
-    {
-        if (proc)
-        {
-            if (*ppPrev == proc)
-            {
-                if ((*ppPrev)->user != user)
-               {
-                   /* terminal thunk is being restored */
+    EnterCriticalSection( &winproc_cs );
 
-                   WINPROC_FreeProc( *pFirst, (*ppPrev)->user );
-                   *(WINDOWPROC **)pFirst = *ppPrev;
-                   return TRUE;
-               }
-               bRecycle = TRUE;
-               break;
-           }
-        }
-        else
+    /* check if the function is already a win proc */
+    if (!(proc = WINPROC_GetPtr( func )))
+    {
+        /* then check if we already have a winproc for that function */
+        if (!(proc = find_winproc( func, type )))
         {
-            if (((*ppPrev)->type == type) &&
-                (func == (WNDPROC)WINPROC_THUNKPROC(*ppPrev)))
+            if (winproc_used >= MAX_WINPROCS)
+                FIXME( "too many winprocs, cannot allocate one for %p/%d\n", func, type );
+            else
             {
-                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;
-    }
-
-    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;
+        else TRACE( "reusing %p for %p/%d\n", proc, func, type );
     }
 
-    /* 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;
 }
 /**********************************************************************