Store window procedures in a static array instead of creating a heap.
Only allocate the winproc selector when actually needed.

diff --git a/dlls/user/user_main.c b/dlls/user/user_main.c
index b676d50..78dc823 100644
--- a/dlls/user/user_main.c
+++ b/dlls/user/user_main.c
@@ -237,9 +237,6 @@
     /* Setup palette function pointers */
     palette_init();
 
-    /* Initialize window procedures */
-    if (!WINPROC_Init()) return FALSE;
-
     /* Initialize built-in window classes */
     controls_init();
 
diff --git a/dlls/user/winproc.h b/dlls/user/winproc.h
index c5d43f9..18e135c 100644
--- a/dlls/user/winproc.h
+++ b/dlls/user/winproc.h
@@ -56,7 +56,6 @@
 
 struct tagWINDOWPROC;
 
-extern BOOL WINPROC_Init(void);
 extern WNDPROC16 WINPROC_GetProc( WNDPROC proc, WINDOWPROCTYPE type );
 extern BOOL WINPROC_SetProc( WNDPROC *pFirst, WNDPROC func,
                                WINDOWPROCTYPE type, WINDOWPROCUSER user );
diff --git a/windows/winproc.c b/windows/winproc.c
index 1bb9bb9..f7f8567 100644
--- a/windows/winproc.c
+++ b/windows/winproc.c
@@ -31,7 +31,6 @@
 #include "wine/winbase16.h"
 #include "wine/winuser16.h"
 #include "stackframe.h"
-#include "selectors.h"
 #include "controls.h"
 #include "heap.h"
 #include "struct32.h"
@@ -45,7 +44,7 @@
 
 WINE_DECLARE_DEBUG_CHANNEL(msg);
 WINE_DECLARE_DEBUG_CHANNEL(relay);
-WINE_DECLARE_DEBUG_CHANNEL(win);
+WINE_DEFAULT_DEBUG_CHANNEL(win);
 
 #include "pshpack1.h"
 
@@ -110,24 +109,60 @@
                                                UINT msg, WPARAM wParam,
                                                LPARAM lParam );
 
-static HANDLE WinProcHeap;
-static WORD WinProcSel;
+#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 = CRITICAL_SECTION_INIT("winproc_cs");
 
-/**********************************************************************
- *	     WINPROC_Init
- */
-BOOL WINPROC_Init(void)
+/* allocate a window procedure from the global array */
+static WINDOWPROC *alloc_winproc(void)
 {
-    WinProcHeap = HeapCreate( 0, 0x10000, 0x10000 );
-    WinProcSel = SELECTOR_AllocBlock( (void *)WinProcHeap, 0x10000,
-                                      WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT );
-    if (!WinProcHeap || !WinProcSel)
+    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;
+    if (proc != winproc_array + (proc - winproc_array)) return FALSE;
+    return (proc->magic == WINPROC_MAGIC);
+}
+
+static WORD get_winproc_selector(void)
+{
+    static LONG winproc_selector;
+    WORD ret;
+
+    if (!(ret = winproc_selector))
     {
-        WARN_(relay)("Unable to create winproc heap\n" );
-        return FALSE;
+        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 TRUE;
+    return ret;
 }
 
 
@@ -279,12 +314,11 @@
     ptr = (BYTE *)handle;
     /* First check if it is the jmp address */
     proc = (WINDOWPROC *)(ptr - (int)&((WINDOWPROC *)0)->jmp);
-    if (HeapValidate( WinProcHeap, 0, proc ) && (proc->magic == WINPROC_MAGIC))
-        return proc;
+    if (is_valid_winproc(proc)) return proc;
+
     /* Now it must be the thunk address */
     proc = (WINDOWPROC *)(ptr - (int)&((WINDOWPROC *)0)->thunk);
-    if (HeapValidate( WinProcHeap, 0, proc ) && (proc->magic == WINPROC_MAGIC))
-        return proc;
+    if (is_valid_winproc(proc)) return proc;
 
     /* Check for a segmented pointer */
 
@@ -293,8 +327,7 @@
         ptr = MapSL( (SEGPTR)handle );
         /* It must be the thunk address */
         proc = (WINDOWPROC *)(ptr - (int)&((WINDOWPROC *)0)->thunk);
-        if (HeapValidate( WinProcHeap, 0, proc ) && (proc->magic == WINPROC_MAGIC))
-            return proc;
+        if (is_valid_winproc(proc)) return proc;
     }
 
     return NULL;
@@ -315,7 +348,7 @@
 
     /* Allocate a window procedure */
 
-    if (!(proc = HeapAlloc( WinProcHeap, 0, sizeof(WINDOWPROC) ))) return 0;
+    if (!(proc = alloc_winproc())) return 0;
 
     /* Check if the function is already a win proc */
 
@@ -374,7 +407,7 @@
         proc->user  = user;
     }
     proc->next  = NULL;
-    TRACE_(win)("(%p,%d): returning %p\n", func, type, proc );
+    TRACE("(%p,%d): returning %p\n", func, type, proc );
     return proc;
 }
 
@@ -394,7 +427,8 @@
         if (ptr->type == WIN_PROC_16)
             return ptr->thunk.t_from32.proc;
         else
-            return (WNDPROC16)MAKESEGPTR( WinProcSel, (char *)&ptr->thunk - (char *)WinProcHeap );
+            return (WNDPROC16)MAKESEGPTR( get_winproc_selector(),
+                                          (char *)&ptr->thunk - (char *)winproc_array );
     }
     else  /* We want a 32-bit address */
     {
@@ -501,8 +535,7 @@
 
     /* Add the win proc at the head of the list */
 
-    TRACE_(win)("(%08x,%08x,%d): res=%08x\n",
-                 (UINT)*pFirst, (UINT)func, type, (UINT)proc );
+    TRACE("(%p,%p,%d): res=%p\n", *pFirst, func, type, proc );
     proc->next  = *(WINDOWPROC **)pFirst;
     *(WINDOWPROC **)pFirst = proc;
     return TRUE;
@@ -521,8 +554,8 @@
     {
         WINDOWPROC *next = ptr->next;
         if (ptr->user != user) break;
-        TRACE_(win)("freeing %p (%d)\n", ptr, user);
-        HeapFree( WinProcHeap, 0, ptr );
+        TRACE("freeing %p (%d)\n", ptr, user);
+        free_winproc( ptr );
         ptr = next;
     }
 }