diff --git a/if1632/gdi.spec b/if1632/gdi.spec
index 7c09bea694421a9ebd3881344898fbda5326ad28..9bfee33599d390eaa218220a0a3fd4a3ceaadeef 100644
--- a/if1632/gdi.spec
+++ b/if1632/gdi.spec
@@ -157,8 +157,8 @@ file	gdi.exe
 180 pascal16 SetDCState(word word) SetDCState16
 181 pascal16 RectInRegionOld(word ptr) RectInRegion16
 188 stub GetTextExtentEx
-190 pascal16 SetDCHook(word segptr long) THUNK_SetDCHook
-191 pascal   GetDCHook(word ptr) THUNK_GetDCHook
+190 pascal16 SetDCHook(word segptr long) SetDCHook
+191 pascal   GetDCHook(word ptr) GetDCHook
 192 pascal16 SetHookFlags(word word) SetHookFlags16
 193 pascal16 SetBoundsRect(word ptr word) SetBoundsRect16
 194 pascal16 GetBoundsRect(word ptr word) GetBoundsRect16
diff --git a/include/gdi.h b/include/gdi.h
index 0c9f295ef1efab271a34c73aae7008852cad3680..da3a5781ff4344d0edc7b24b7b3961d9ba5dd037 100644
--- a/include/gdi.h
+++ b/include/gdi.h
@@ -137,15 +137,19 @@ typedef struct
     BOOL          vport2WorldValid;  /* Is xformVport2World valid? */
 } WIN_DC_INFO;
 
+
+typedef BOOL16 (CALLBACK *DCHOOKPROC)(HDC16,WORD,DWORD,LPARAM);
+
 typedef struct tagDC
 {
-    GDIOBJHDR      header;
+    GDIOBJHDR    header;
     HDC          hSelf;            /* Handle to this DC */
     const struct tagDC_FUNCS *funcs; /* DC function table */
-    void          *physDev;          /* Physical device (driver-specific) */
+    void         *physDev;         /* Physical device (driver-specific) */
     INT          saveLevel;
-    DWORD          dwHookData;
-    FARPROC16      hookProc;
+    DWORD        dwHookData;
+    FARPROC16    hookProc;         /* the original SEGPTR ... */
+    DCHOOKPROC   hookThunk;        /* ... and the thunk to call it */
 
     INT          wndOrgX;          /* Window origin */
     INT          wndOrgY;
diff --git a/objects/.cvsignore b/objects/.cvsignore
index f3c7a7c5da68804a1bdf391127ba34aed33c3cca..6c4db5dab95390d2ab7afb7568f7e605aeb0d681 100644
--- a/objects/.cvsignore
+++ b/objects/.cvsignore
@@ -1 +1,2 @@
 Makefile
+dc.glue.c
diff --git a/objects/Makefile.in b/objects/Makefile.in
index 02a4311dfe9625217e9bd7da483e698ee5e34220..1a9202b804da458d716253f32a8ea0c8217719db 100644
--- a/objects/Makefile.in
+++ b/objects/Makefile.in
@@ -24,6 +24,8 @@ C_SRCS = \
 	region.c \
 	text.c
 
+GLUE = dc.c
+
 all: $(MODULE).o
 
 @MAKE_RULES@
diff --git a/objects/clipping.c b/objects/clipping.c
index 841ad8a36cd6c80936f028f2432f469b22fda00f..0484e3ebaad1635c9e8d510ad19abe6e25cc6243 100644
--- a/objects/clipping.c
+++ b/objects/clipping.c
@@ -15,8 +15,8 @@ DECLARE_DEBUG_CHANNEL(region)
 
 #define UPDATE_DIRTY_DC(dc) \
  do { \
-   if ((dc)->hookProc && !((dc)->w.flags & (DC_SAVED | DC_MEMORY))) \
-     (dc)->hookProc( (dc)->hSelf, DCHC_INVALIDVISRGN, (dc)->dwHookData, 0 ); \
+   if ((dc)->hookThunk && !((dc)->w.flags & (DC_SAVED | DC_MEMORY))) \
+     (dc)->hookThunk( (dc)->hSelf, DCHC_INVALIDVISRGN, (dc)->dwHookData, 0 ); \
  } while(0)
 
 
diff --git a/objects/dc.c b/objects/dc.c
index 7d074bc6afde4aaa92bcab5bf19d7d9f6abf3a3d..1dfb530aab13ac334c2533e5f9dbdfc8715ef605 100644
--- a/objects/dc.c
+++ b/objects/dc.c
@@ -99,6 +99,7 @@ DC *DC_AllocDC( const DC_FUNCTIONS *funcs )
     dc->saveLevel  = 0;
     dc->dwHookData = 0L;
     dc->hookProc   = NULL;
+    dc->hookThunk  = NULL;
     dc->wndOrgX    = 0;
     dc->wndOrgY    = 0;
     dc->wndExtX    = 1;
@@ -680,8 +681,8 @@ BOOL WINAPI DeleteDC( HDC hdc )
     TRACE("%04x\n", hdc );
 
     /* Call hook procedure to check whether is it OK to delete this DC */
-    if (    dc->hookProc && !(dc->w.flags & (DC_SAVED | DC_MEMORY))
-         && dc->hookProc( hdc, DCHC_DELETEDC, dc->dwHookData, 0 ) == FALSE )
+    if (    dc->hookThunk && !(dc->w.flags & (DC_SAVED | DC_MEMORY))
+         && dc->hookThunk( hdc, DCHC_DELETEDC, dc->dwHookData, 0 ) == FALSE )
     {
         GDI_HEAP_UNLOCK( hdc );
         return FALSE;
@@ -710,6 +711,7 @@ BOOL WINAPI DeleteDC( HDC hdc )
     if (dc->w.hVisRgn) DeleteObject( dc->w.hVisRgn );
     if (dc->w.hGCClipRgn) DeleteObject( dc->w.hGCClipRgn );
     if (dc->w.pAbortProc) THUNK_Free( (FARPROC)dc->w.pAbortProc );
+    if (dc->hookThunk) THUNK_Free( (FARPROC)dc->hookThunk );
     PATH_DestroyGdiPath(&dc->w.path);
     
     return GDI_FreeObject( hdc );
@@ -1201,16 +1203,35 @@ BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
 /***********************************************************************
  *           SetDCHook   (GDI.190)
  */
+/* ### start build ### */
+extern WORD CALLBACK GDI_CallTo16_word_wwll(FARPROC16,WORD,WORD,LONG,LONG);
+/* ### stop build ### */
 BOOL16 WINAPI SetDCHook( HDC16 hdc, FARPROC16 hookProc, DWORD dwHookData )
 {
     DC *dc = (DC *)GDI_GetObjPtr( hdc, DC_MAGIC );
+    if (!dc) return FALSE;
 
-    TRACE("hookProc %08x, default is %08x\n",
-                (UINT)hookProc, (UINT)DCHook16 );
+    /*
+     * Note: We store the original SEGPTR 'hookProc' as we need to be
+     *       able to return it verbatim in GetDCHook,
+     *
+     *       On the other hand, we still call THUNK_Alloc and store the
+     *       32-bit thunk into another DC member, because THUNK_Alloc
+     *       recognizes the (typical) case that the 'hookProc' is indeed
+     *       the 16-bit API entry point of a built-in routine (e.g. DCHook16)
+     *
+     *       We could perform that test every time the hook is about to
+     *       be called (or else we could live with the 32->16->32 detour),
+     *       but this way is the most efficient ...
+     */
 
-    if (!dc) return FALSE;
     dc->hookProc = hookProc;
     dc->dwHookData = dwHookData;
+
+    THUNK_Free( (FARPROC)dc->hookThunk );
+    dc->hookThunk = (DCHOOKPROC)
+                    THUNK_Alloc( hookProc, (RELAY)GDI_CallTo16_word_wwll );
+
     GDI_HEAP_UNLOCK( hdc );
     return TRUE;
 }
diff --git a/windows/dce.c b/windows/dce.c
index e825596db433d5566314d408ed42fc12974b119a..2e24db52a68be35b1f7e7d880503038232a89061 100644
--- a/windows/dce.c
+++ b/windows/dce.c
@@ -27,7 +27,9 @@
 #include "region.h"
 #include "heap.h"
 #include "local.h"
+#include "module.h"
 #include "debugtools.h"
+#include "wine/winbase16.h"
 #include "wine/winuser16.h"
 
 DEFAULT_DEBUG_CHANNEL(dc)
@@ -71,6 +73,7 @@ static void DCE_DumpCache(void)
  */
 DCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type )
 {
+    FARPROC16 hookProc;
     DCE * dce;
     WND* wnd;
     
@@ -85,7 +88,8 @@ DCE *DCE_AllocDCE( HWND hWnd, DCE_TYPE type )
     
     /* store DCE handle in DC hook data field */
 
-    SetDCHook( dce->hDC, (FARPROC16)DCHook16, (DWORD)dce );
+    hookProc = (FARPROC16)NE_GetEntryPoint( GetModuleHandle16("USER"), 362 );
+    SetDCHook( dce->hDC, hookProc, (DWORD)dce );
 
     dce->hwndCurrent = hWnd;
     dce->hClipRgn    = 0;