diff --git a/dlls/user32/caret.c b/dlls/user32/caret.c
index 7b21e03c764..9e0ff5ca48c 100644
--- a/dlls/user32/caret.c
+++ b/dlls/user32/caret.c
@@ -31,222 +31,12 @@
 #include "wine/server.h"
 #include "wine/debug.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(caret);
-
-typedef struct
-{
-    HBITMAP  hBmp;
-    UINT     timeout;
-} CARET;
-
-static CARET Caret = { 0, 500 };
-
-
-/*****************************************************************
- *               CARET_DisplayCaret
- */
-static void CARET_DisplayCaret( HWND hwnd, const RECT *r )
-{
-    HDC hdc;
-    HDC hCompDC;
-
-    /* do not use DCX_CACHE here, for x,y,width,height are in logical units */
-    if (!(hdc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE /*| DCX_CACHE*/ ))) return;
-    hCompDC = CreateCompatibleDC(hdc);
-    if (hCompDC)
-    {
-	HBITMAP	hPrevBmp;
-
-	hPrevBmp = SelectObject(hCompDC, Caret.hBmp);
-	BitBlt(hdc, r->left, r->top, r->right-r->left, r->bottom-r->top, hCompDC, 0, 0, SRCINVERT);
-	SelectObject(hCompDC, hPrevBmp);
-	DeleteDC(hCompDC);
-    }
-    NtUserReleaseDC( hwnd, hdc );
-}
-
-
-void CDECL toggle_caret( HWND hwnd )
-{
-    BOOL ret;
-    RECT r;
-    int hidden = 0;
-
-    SERVER_START_REQ( set_caret_info )
-    {
-        req->flags  = SET_CARET_STATE;
-        req->handle = wine_server_user_handle( hwnd );
-        req->x      = 0;
-        req->y      = 0;
-        req->hide   = 0;
-        req->state  = CARET_STATE_TOGGLE;
-        if ((ret = !wine_server_call( req )))
-        {
-            hwnd      = wine_server_ptr_handle( reply->full_handle );
-            r.left    = reply->old_rect.left;
-            r.top     = reply->old_rect.top;
-            r.right   = reply->old_rect.right;
-            r.bottom  = reply->old_rect.bottom;
-            hidden    = reply->old_hide;
-        }
-    }
-    SERVER_END_REQ;
-
-    if (ret && !hidden) CARET_DisplayCaret( hwnd, &r );
-}
-
-
-static unsigned int get_caret_registry_timeout(void)
-{
-    unsigned int ret = 500;
-    WCHAR value[11];
-    DWORD size;
-    HKEY key;
-
-    if (RegOpenKeyExW( HKEY_CURRENT_USER, L"Control Panel\\Desktop", 0, KEY_READ, &key ))
-        return ret;
-
-    size = sizeof(value);
-    if (!RegQueryValueExW( key, L"CursorBlinkRate", NULL, NULL, (BYTE *)value, &size ))
-        ret = wcstoul( value, NULL, 10 );
-    RegCloseKey( key );
-    return ret;
-}
-
-
-/*****************************************************************
- *		CreateCaret (USER32.@)
- */
-BOOL WINAPI CreateCaret( HWND hwnd, HBITMAP bitmap, INT width, INT height )
-{
-    BOOL ret;
-    RECT r;
-    int old_state = 0;
-    int hidden = 0;
-    HBITMAP hBmp = 0;
-    HWND prev = 0;
-
-    TRACE("hwnd=%p\n", hwnd);
-
-    if (!hwnd) return FALSE;
-
-    if (bitmap && (bitmap != (HBITMAP)1))
-    {
-        BITMAP bmp;
-        if (!GetObjectA( bitmap, sizeof(bmp), &bmp )) return FALSE;
-        width = bmp.bmWidth;
-        height = bmp.bmHeight;
-	bmp.bmBits = NULL;
-	hBmp = CreateBitmapIndirect(&bmp);
-	if (hBmp)
-	{
-	    /* copy the bitmap */
-	    LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, bmp.bmWidthBytes * bmp.bmHeight);
-	    GetBitmapBits(bitmap, bmp.bmWidthBytes * bmp.bmHeight, buf);
-	    SetBitmapBits(hBmp, bmp.bmWidthBytes * bmp.bmHeight, buf);
-	    HeapFree(GetProcessHeap(), 0, buf);
-	}
-    }
-    else
-    {
-	HDC hdc;
-
-        if (!width) width = GetSystemMetrics(SM_CXBORDER);
-        if (!height) height = GetSystemMetrics(SM_CYBORDER);
-
-	/* create the uniform bitmap on the fly */
-	hdc = GetDC(hwnd);
-	if (hdc)
-	{
-	    HDC hMemDC = CreateCompatibleDC(hdc);
-	    if (hMemDC)
-	    {
-		if ((hBmp = CreateCompatibleBitmap(hMemDC, width, height )))
-		{
-		    HBITMAP hPrevBmp = SelectObject(hMemDC, hBmp);
-                    SetRect( &r, 0, 0, width, height );
-		    FillRect(hMemDC, &r, bitmap ? GetStockObject(GRAY_BRUSH) : GetStockObject(WHITE_BRUSH));
-		    SelectObject(hMemDC, hPrevBmp);
-		}
-		DeleteDC(hMemDC);
-	    }
-	    NtUserReleaseDC(hwnd, hdc);
-	}
-    }
-    if (!hBmp) return FALSE;
-
-    SERVER_START_REQ( set_caret_window )
-    {
-        req->handle = wine_server_user_handle( hwnd );
-        req->width  = width;
-        req->height = height;
-        if ((ret = !wine_server_call_err( req )))
-        {
-            prev      = wine_server_ptr_handle( reply->previous );
-            r.left    = reply->old_rect.left;
-            r.top     = reply->old_rect.top;
-            r.right   = reply->old_rect.right;
-            r.bottom  = reply->old_rect.bottom;
-            old_state = reply->old_state;
-            hidden    = reply->old_hide;
-        }
-    }
-    SERVER_END_REQ;
-    if (!ret) return FALSE;
-
-    if (prev && !hidden)  /* hide the previous one */
-    {
-        /* FIXME: won't work if prev belongs to a different process */
-        KillSystemTimer( prev, SYSTEM_TIMER_CARET );
-        if (old_state) CARET_DisplayCaret( prev, &r );
-    }
-
-    if (Caret.hBmp) DeleteObject( Caret.hBmp );
-    Caret.hBmp = hBmp;
-
-    Caret.timeout = get_caret_registry_timeout();
-    return TRUE;
-}
-
-
 /*****************************************************************
  *		DestroyCaret (USER32.@)
  */
 BOOL WINAPI DestroyCaret(void)
 {
-    BOOL ret;
-    HWND prev = 0;
-    RECT r;
-    int old_state = 0;
-    int hidden = 0;
-
-    SERVER_START_REQ( set_caret_window )
-    {
-        req->handle = 0;
-        req->width  = 0;
-        req->height = 0;
-        if ((ret = !wine_server_call_err( req )))
-        {
-            prev      = wine_server_ptr_handle( reply->previous );
-            r.left    = reply->old_rect.left;
-            r.top     = reply->old_rect.top;
-            r.right   = reply->old_rect.right;
-            r.bottom  = reply->old_rect.bottom;
-            old_state = reply->old_state;
-            hidden    = reply->old_hide;
-        }
-    }
-    SERVER_END_REQ;
-
-    if (ret && prev && !hidden)
-    {
-        /* FIXME: won't work if prev belongs to a different process */
-        KillSystemTimer( prev, SYSTEM_TIMER_CARET );
-        if (old_state) CARET_DisplayCaret( prev, &r );
-    }
-    if (Caret.hBmp) DeleteObject( Caret.hBmp );
-    Caret.hBmp = 0;
-    return ret;
+    return NtUserDestroyCaret();
 }
 
 
@@ -255,167 +45,14 @@ BOOL WINAPI DestroyCaret(void)
  */
 BOOL WINAPI SetCaretPos( INT x, INT y )
 {
-    BOOL ret;
-    HWND hwnd = 0;
-    RECT r;
-    int old_state = 0;
-    int hidden = 0;
-
-    SERVER_START_REQ( set_caret_info )
-    {
-        req->flags  = SET_CARET_POS|SET_CARET_STATE;
-        req->handle = 0;
-        req->x      = x;
-        req->y      = y;
-        req->hide   = 0;
-        req->state  = CARET_STATE_ON_IF_MOVED;
-        if ((ret = !wine_server_call_err( req )))
-        {
-            hwnd      = wine_server_ptr_handle( reply->full_handle );
-            r.left    = reply->old_rect.left;
-            r.top     = reply->old_rect.top;
-            r.right   = reply->old_rect.right;
-            r.bottom  = reply->old_rect.bottom;
-            old_state = reply->old_state;
-            hidden    = reply->old_hide;
-        }
-    }
-    SERVER_END_REQ;
-    if (ret && !hidden && (x != r.left || y != r.top))
-    {
-        if (old_state) CARET_DisplayCaret( hwnd, &r );
-        r.right += x - r.left;
-        r.bottom += y - r.top;
-        r.left = x;
-        r.top = y;
-        CARET_DisplayCaret( hwnd, &r );
-        NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, Caret.timeout );
-    }
-    return ret;
-}
-
-
-/*****************************************************************
- *		HideCaret (USER32.@)
- */
-BOOL WINAPI HideCaret( HWND hwnd )
-{
-    BOOL ret;
-    RECT r;
-    int old_state = 0;
-    int hidden = 0;
-
-    SERVER_START_REQ( set_caret_info )
-    {
-        req->flags  = SET_CARET_HIDE|SET_CARET_STATE;
-        req->handle = wine_server_user_handle( hwnd );
-        req->x      = 0;
-        req->y      = 0;
-        req->hide   = 1;
-        req->state  = CARET_STATE_OFF;
-        if ((ret = !wine_server_call_err( req )))
-        {
-            hwnd      = wine_server_ptr_handle( reply->full_handle );
-            r.left    = reply->old_rect.left;
-            r.top     = reply->old_rect.top;
-            r.right   = reply->old_rect.right;
-            r.bottom  = reply->old_rect.bottom;
-            old_state = reply->old_state;
-            hidden    = reply->old_hide;
-        }
-    }
-    SERVER_END_REQ;
-
-    if (ret && !hidden)
-    {
-        if (old_state) CARET_DisplayCaret( hwnd, &r );
-        KillSystemTimer( hwnd, SYSTEM_TIMER_CARET );
-    }
-    return ret;
-}
-
-
-/*****************************************************************
- *		ShowCaret (USER32.@)
- */
-BOOL WINAPI ShowCaret( HWND hwnd )
-{
-    BOOL ret;
-    RECT r;
-    int hidden = 0;
-
-    SERVER_START_REQ( set_caret_info )
-    {
-        req->flags  = SET_CARET_HIDE|SET_CARET_STATE;
-        req->handle = wine_server_user_handle( hwnd );
-        req->x      = 0;
-        req->y      = 0;
-        req->hide   = -1;
-        req->state  = CARET_STATE_ON;
-        if ((ret = !wine_server_call_err( req )))
-        {
-            hwnd      = wine_server_ptr_handle( reply->full_handle );
-            r.left    = reply->old_rect.left;
-            r.top     = reply->old_rect.top;
-            r.right   = reply->old_rect.right;
-            r.bottom  = reply->old_rect.bottom;
-            hidden    = reply->old_hide;
-        }
-    }
-    SERVER_END_REQ;
-
-    if (ret && (hidden == 1))  /* hidden was 1 so it's now 0 */
-    {
-        CARET_DisplayCaret( hwnd, &r );
-        NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, Caret.timeout );
-    }
-    return ret;
-}
-
-
-/*****************************************************************
- *		GetCaretPos (USER32.@)
- */
-BOOL WINAPI GetCaretPos( LPPOINT pt )
-{
-    BOOL ret;
-
-    SERVER_START_REQ( set_caret_info )
-    {
-        req->flags  = 0;  /* don't set anything */
-        req->handle = 0;
-        req->x      = 0;
-        req->y      = 0;
-        req->hide   = 0;
-        req->state  = 0;
-        if ((ret = !wine_server_call_err( req )))
-        {
-            pt->x = reply->old_rect.left;
-            pt->y = reply->old_rect.top;
-        }
-    }
-    SERVER_END_REQ;
-    return ret;
+    return NtUserSetCaretPos( x, y );
 }
 
 
 /*****************************************************************
  *		SetCaretBlinkTime (USER32.@)
  */
-BOOL WINAPI SetCaretBlinkTime( UINT msecs )
-{
-    TRACE("msecs=%d\n", msecs);
-
-    Caret.timeout = msecs;
-/*    if (Caret.hwnd) CARET_SetTimer(); FIXME */
-    return TRUE;
-}
-
-
-/*****************************************************************
- *		GetCaretBlinkTime (USER32.@)
- */
-UINT WINAPI GetCaretBlinkTime(void)
+BOOL WINAPI SetCaretBlinkTime( unsigned int time )
 {
-    return Caret.timeout;
+    return NtUserSetCaretBlinkTime( time );
 }
diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c
index f15c4c8e550..4e32a59df48 100644
--- a/dlls/user32/edit.c
+++ b/dlls/user32/edit.c
@@ -3807,10 +3807,10 @@ static void EDIT_WM_SetFocus(EDITSTATE *es)
             NtUserReleaseDC( es->hwndSelf, hdc );
         }
 
-	CreateCaret(es->hwndSelf, 0, 1, es->line_height);
+        NtUserCreateCaret( es->hwndSelf, 0, 1, es->line_height );
 	EDIT_SetCaretPos(es, es->selection_end,
 			 es->flags & EF_AFTER_WRAP);
-	ShowCaret(es->hwndSelf);
+        NtUserShowCaret( es->hwndSelf );
 	EDIT_NOTIFY_PARENT(es, EN_SETFOCUS);
 }
 
@@ -3890,10 +3890,10 @@ static void EDIT_WM_SetFont(EDITSTATE *es, HFONT font, BOOL redraw)
 		EDIT_UpdateText(es, NULL, TRUE);
 	if (es->flags & EF_FOCUSED) {
 		DestroyCaret();
-		CreateCaret(es->hwndSelf, 0, 1, es->line_height);
+		NtUserCreateCaret( es->hwndSelf, 0, 1, es->line_height );
 		EDIT_SetCaretPos(es, es->selection_end,
 				 es->flags & EF_AFTER_WRAP);
-		ShowCaret(es->hwndSelf);
+		NtUserShowCaret( es->hwndSelf );
 	}
 }
 
diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c
index 6fb9422cf9d..cc6c5c953e9 100644
--- a/dlls/user32/menu.c
+++ b/dlls/user32/menu.c
@@ -3300,7 +3300,7 @@ static BOOL MENU_InitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
     
     TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
 
-    HideCaret(0);
+    NtUserHideCaret( 0 );
 
     if (!(menu = MENU_GetMenu( hMenu ))) return FALSE;
 
@@ -3342,7 +3342,7 @@ static BOOL MENU_ExitTracking(HWND hWnd, BOOL bPopup)
     TRACE("hwnd=%p\n", hWnd);
 
     SendMessageW( hWnd, WM_EXITMENULOOP, bPopup, 0 );
-    ShowCaret(0);
+    NtUserShowCaret( 0 );
     top_popup = 0;
     top_popup_hmenu = NULL;
     return TRUE;
diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c
index 94e462605dd..29450e6e984 100644
--- a/dlls/user32/painting.c
+++ b/dlls/user32/painting.c
@@ -285,7 +285,7 @@ static INT scroll_window( HWND hwnd, INT dx, INT dy, const RECT *rect, const REC
 
         hwndCaret = fix_caret(hwnd, &rc, dx, dy, flags, &moveCaret, &newCaretPos);
         if (hwndCaret)
-            HideCaret(hwndCaret);
+            NtUserHideCaret( hwndCaret );
 
         if (is_ex) dcxflags |= DCX_CACHE;
         if( style & WS_CLIPSIBLINGS) dcxflags |= DCX_CLIPSIBLINGS;
@@ -388,7 +388,7 @@ static INT scroll_window( HWND hwnd, INT dx, INT dy, const RECT *rect, const REC
     if( moveCaret )
         SetCaretPos( newCaretPos.x, newCaretPos.y );
     if( hwndCaret )
-        ShowCaret( hwndCaret );
+        NtUserShowCaret( hwndCaret );
 
     if( bOwnRgn && hrgnUpdate ) DeleteObject( hrgnUpdate );
 
diff --git a/dlls/user32/scroll.c b/dlls/user32/scroll.c
index 8f085364dab..efe115246f2 100644
--- a/dlls/user32/scroll.c
+++ b/dlls/user32/scroll.c
@@ -756,7 +756,7 @@ static void SCROLL_HandleKbdEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
 
     /* hide caret on first KEYDOWN to prevent flicker */
     if ((lParam & PFD_DOUBLEBUFFER_DONTCARE) == 0)
-        HideCaret(hwnd);
+        NtUserHideCaret( hwnd );
 
     switch(wParam)
     {
@@ -814,7 +814,7 @@ void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt )
         switch(msg)
         {
             case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
-                HideCaret(hwnd);  /* hide caret while holding down LBUTTON */
+                NtUserHideCaret( hwnd ); /* hide caret while holding down LBUTTON */
                 NtUserSetCapture( hwnd );
                 prevPt = pt;
                 g_tracking_info.hit_test = hittest = SCROLL_THUMB;
@@ -826,7 +826,7 @@ void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt )
             case WM_LBUTTONUP:
                 ReleaseCapture();
                 g_tracking_info.hit_test = hittest = SCROLL_NOWHERE;
-                if (hwnd==GetFocus()) ShowCaret(hwnd);
+                if (hwnd == GetFocus()) NtUserShowCaret( hwnd );
                 break;
             case WM_SYSTIMER:
                 pt = prevPt;
@@ -844,7 +844,7 @@ void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt )
     switch(msg)
     {
       case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
-          HideCaret(hwnd);  /* hide caret while holding down LBUTTON */
+          NtUserHideCaret( hwnd ); /* hide caret while holding down LBUTTON */
           g_tracking_info.vertical = vertical;
           g_tracking_info.hit_test = hittest = SCROLL_HitTest( hwnd, nBar, pt, FALSE );
           lastClickPos  = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
@@ -911,7 +911,7 @@ void SCROLL_HandleScrollEvent( HWND hwnd, INT nBar, UINT msg, POINT pt )
           hittest = SCROLL_NOWHERE;
           ReleaseCapture();
           /* if scrollbar has focus, show back caret */
-          if (hwnd==GetFocus()) ShowCaret(hwnd);
+          if (hwnd == GetFocus()) NtUserShowCaret( hwnd );
           break;
 
       case WM_SYSTIMER:
@@ -1468,7 +1468,7 @@ LRESULT WINAPI USER_ScrollBarProc( HWND hwnd, UINT message, WPARAM wParam, LPARA
         break;
 
     case WM_KEYUP:
-        ShowCaret(hwnd);
+        NtUserShowCaret( hwnd );
         break;
 
     case WM_SETFOCUS:
@@ -1480,15 +1480,15 @@ LRESULT WINAPI USER_ScrollBarProc( HWND hwnd, UINT message, WPARAM wParam, LPARA
                                                 &arrowSize, &thumbSize, &thumbPos );
             if (!vertical)
             {
-                CreateCaret(hwnd, (HBITMAP)1, thumbSize-2, rect.bottom-rect.top-2);
+                NtUserCreateCaret( hwnd, (HBITMAP)1, thumbSize - 2, rect.bottom - rect.top - 2 );
                 SetCaretPos(thumbPos+1, rect.top+1);
             }
             else
             {
-                CreateCaret(hwnd, (HBITMAP)1, rect.right-rect.left-2,thumbSize-2);
+                NtUserCreateCaret( hwnd, (HBITMAP)1, rect.right - rect.left - 2, thumbSize - 2);
                 SetCaretPos(rect.top+1, thumbPos+1);
             }
-            ShowCaret(hwnd);
+            NtUserShowCaret( hwnd );
         }
         break;
 
@@ -1506,7 +1506,7 @@ LRESULT WINAPI USER_ScrollBarProc( HWND hwnd, UINT message, WPARAM wParam, LPARA
                 rect.top=thumbPos+1;
                 rect.bottom=rect.top+thumbSize;
             }
-            HideCaret(hwnd);
+            NtUserHideCaret( hwnd );
             InvalidateRect(hwnd,&rect,0);
             DestroyCaret();
         }
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec
index 6f86fccdfbd..da0b7c5a1ab 100644
--- a/dlls/user32/user32.spec
+++ b/dlls/user32/user32.spec
@@ -86,7 +86,7 @@
 @ stdcall CountClipboardFormats() NtUserCountClipboardFormats
 @ stdcall CreateAcceleratorTableA(ptr long)
 @ stdcall CreateAcceleratorTableW(ptr long) NtUserCreateAcceleratorTable
-@ stdcall CreateCaret(long long long long)
+@ stdcall CreateCaret(long long long long) NtUserCreateCaret
 @ stdcall CreateCursor(long long long long long ptr ptr)
 @ stdcall CreateDesktopA(str str ptr long long ptr)
 @ stdcall CreateDesktopW(wstr wstr ptr long long ptr)
@@ -259,8 +259,8 @@
 @ stdcall GetAutoRotationState(ptr)
 @ stdcall GetAwarenessFromDpiAwarenessContext(long)
 @ stdcall GetCapture()
-@ stdcall GetCaretBlinkTime()
-@ stdcall GetCaretPos(ptr)
+@ stdcall GetCaretBlinkTime() NtUserGetCaretBlinkTime
+@ stdcall GetCaretPos(ptr) NtUserGetCaretPos
 @ stdcall GetClassInfoA(long str ptr)
 @ stdcall GetClassInfoExA(long str ptr)
 @ stdcall GetClassInfoExW(long wstr ptr)
@@ -425,7 +425,7 @@
 @ stdcall GrayStringA(long long ptr long long long long long long)
 @ stdcall GrayStringW(long long ptr long long long long long long)
 # @ stub HasSystemSleepStarted
-@ stdcall HideCaret(long)
+@ stdcall HideCaret(long) NtUserHideCaret
 @ stdcall HiliteMenuItem(long long long long)
 # @ stub IMPGetIMEA
 # @ stub IMPGetIMEW
@@ -736,7 +736,7 @@
 @ stdcall SetWindowsHookExA(long long long long)
 @ stdcall SetWindowsHookExW(long long long long)
 @ stdcall SetWindowsHookW(long ptr)
-@ stdcall ShowCaret(long)
+@ stdcall ShowCaret(long) NtUserShowCaret
 @ stdcall -import ShowCursor(long) NtUserShowCursor
 @ stdcall ShowOwnedPopups(long long)
 @ stdcall ShowScrollBar(long long long)
diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c
index d529e49ba3a..1258181c88a 100644
--- a/dlls/user32/user_main.c
+++ b/dlls/user32/user_main.c
@@ -161,13 +161,10 @@ static const struct user_callbacks user_funcs =
 {
     AdjustWindowRectEx,
     CopyImage,
-    DestroyCaret,
     EndMenu,
-    HideCaret,
     ImmProcessKey,
     ImmTranslateMessage,
     SetSystemMenu,
-    ShowCaret,
     free_menu_items,
     free_win_ptr,
     MENU_IsMenuActive,
@@ -177,7 +174,6 @@ static const struct user_callbacks user_funcs =
     rawinput_device_get_usages,
     register_builtin_classes,
     SCROLL_SetStandardScrollPainted,
-    toggle_caret,
     unpack_dde_message,
     register_imm,
     unregister_imm,
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index 8fa8af00326..f28fc66bbf2 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -101,7 +101,6 @@ extern HBRUSH SYSCOLOR_Get55AABrush(void) DECLSPEC_HIDDEN;
 extern void SYSPARAMS_Init(void) DECLSPEC_HIDDEN;
 extern void USER_CheckNotLock(void) DECLSPEC_HIDDEN;
 extern BOOL USER_IsExitingThread( DWORD tid ) DECLSPEC_HIDDEN;
-extern void CDECL toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN;
 
 typedef LRESULT (*winproc_callback_t)( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
                                        LRESULT *result, void *arg );
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c
index aa16c099d97..80f630b5614 100644
--- a/dlls/win32u/dce.c
+++ b/dlls/win32u/dce.c
@@ -1340,7 +1340,7 @@ HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps )
     RECT rect;
     UINT flags = UPDATE_NONCLIENT | UPDATE_ERASE | UPDATE_PAINT | UPDATE_INTERNALPAINT | UPDATE_NOCHILDREN;
 
-    if (user_callbacks) user_callbacks->pHideCaret( hwnd );
+    NtUserHideCaret( hwnd );
 
     if (!(hrgn = send_ncpaint( hwnd, NULL, &flags ))) return 0;
 
@@ -1364,7 +1364,7 @@ HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps )
  */
 BOOL WINAPI NtUserEndPaint( HWND hwnd, const PAINTSTRUCT *ps )
 {
-    if (user_callbacks) user_callbacks->pShowCaret( hwnd );
+    NtUserShowCaret( hwnd );
     flush_window_surfaces( FALSE );
     if (!ps) return FALSE;
     release_dc( hwnd, ps->hdc, TRUE );
diff --git a/dlls/win32u/gdiobj.c b/dlls/win32u/gdiobj.c
index 0f82d446269..c5db1bfcc30 100644
--- a/dlls/win32u/gdiobj.c
+++ b/dlls/win32u/gdiobj.c
@@ -1147,6 +1147,7 @@ static struct unix_funcs unix_funcs =
     NtUserClipCursor,
     NtUserCloseClipboard,
     NtUserCountClipboardFormats,
+    NtUserCreateCaret,
     NtUserCreateWindowEx,
     NtUserDeferWindowPosAndBand,
     NtUserDestroyCursor,
@@ -1178,6 +1179,7 @@ static struct unix_funcs unix_funcs =
     NtUserGetUpdateRect,
     NtUserGetUpdateRgn,
     NtUserGetUpdatedClipboardFormats,
+    NtUserHideCaret,
     NtUserIsClipboardFormatAvailable,
     NtUserMapVirtualKeyEx,
     NtUserMessageCall,
@@ -1214,6 +1216,7 @@ static struct unix_funcs unix_funcs =
     NtUserSetWindowPos,
     NtUserSetWindowRgn,
     NtUserSetWindowWord,
+    NtUserShowCaret,
     NtUserShowCursor,
     NtUserShowWindow,
     NtUserShowWindowAsync,
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c
index c9d14ed746f..28fc5a918c8 100644
--- a/dlls/win32u/input.c
+++ b/dlls/win32u/input.c
@@ -2,10 +2,14 @@
  * USER Input processing
  *
  * Copyright 1993 Bob Amstadt
+ * Copyright 1993 David Metcalfe
  * Copyright 1996 Albrecht Kleine
+ * Copyright 1996 Frans van Dorsselaer
  * Copyright 1997 David Faure
  * Copyright 1998 Morten Welinder
  * Copyright 1998 Ulrich Weigand
+ * Copyright 2001 Eric Pouech
+ * Copyright 2002 Alexandre Julliard
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -1767,3 +1771,383 @@ BOOL set_foreground_window( HWND hwnd, BOOL mouse )
     }
     return ret;
 }
+
+struct
+{
+    HBITMAP bitmap;
+    unsigned int timeout;
+} caret = {0, 500};
+
+static void display_caret( HWND hwnd, const RECT *r )
+{
+    HDC dc, mem_dc;
+
+    /* do not use DCX_CACHE here, since coördinates are in logical units */
+    if (!(dc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE )))
+        return;
+    mem_dc = NtGdiCreateCompatibleDC(dc);
+    if (mem_dc)
+    {
+        HBITMAP prev_bitmap;
+
+        prev_bitmap = NtGdiSelectBitmap( mem_dc, caret.bitmap );
+        NtGdiBitBlt( dc, r->left, r->top, r->right-r->left, r->bottom-r->top, mem_dc, 0, 0, SRCINVERT, 0, 0 );
+        NtGdiSelectBitmap( mem_dc, prev_bitmap );
+        NtGdiDeleteObjectApp( mem_dc );
+    }
+    NtUserReleaseDC( hwnd, dc );
+}
+
+static void fill_rect( HDC dc, const RECT *rect, HBRUSH hbrush )
+{
+    HBRUSH prev_brush;
+
+    prev_brush = NtGdiSelectBrush( dc, hbrush );
+    NtGdiPatBlt( dc, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
+    if (prev_brush) NtGdiSelectBrush( dc, prev_brush );
+}
+
+static unsigned int get_caret_registry_timeout(void)
+{
+    char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[11 * sizeof(WCHAR)])];
+    KEY_VALUE_PARTIAL_INFORMATION *value = (void *)value_buffer;
+    unsigned int ret = 500;
+    HKEY key;
+
+    if (!(key = reg_open_hkcu_key( "Control Panel\\Desktop" )))
+        return ret;
+
+    if (query_reg_ascii_value( key, "CursorBlinkRate", value, sizeof(value_buffer) ))
+        ret = wcstoul( (WCHAR *)value->Data, NULL, 10 );
+    NtClose( key );
+    return ret;
+}
+
+/*****************************************************************
+ *           NtUserCreateCaret  (win32u.@)
+ */
+BOOL WINAPI NtUserCreateCaret( HWND hwnd, HBITMAP bitmap, int width, int height )
+{
+    HBITMAP caret_bitmap = 0;
+    int old_state = 0;
+    int hidden = 0;
+    HWND prev = 0;
+    BOOL ret;
+    RECT r;
+
+    TRACE( "hwnd %p, bitmap %p, width %d, height %d\n", hwnd, bitmap, width, height );
+
+    if (!hwnd) return FALSE;
+
+    if (bitmap && bitmap != (HBITMAP)1)
+    {
+        BITMAP bitmap_data;
+
+        if (!NtGdiExtGetObjectW( bitmap, sizeof(bitmap_data), &bitmap_data )) return FALSE;
+        caret_bitmap = NtGdiCreateBitmap( bitmap_data.bmWidth, bitmap_data.bmHeight,
+                                          bitmap_data.bmPlanes, bitmap_data.bmBitsPixel, NULL );
+        if (caret_bitmap)
+        {
+            size_t size = bitmap_data.bmWidthBytes * bitmap_data.bmHeight;
+            BYTE *bits = malloc( size );
+
+            NtGdiGetBitmapBits( bitmap, size, bits );
+            NtGdiSetBitmapBits( caret_bitmap, size, bits );
+            free( bits );
+        }
+    }
+    else
+    {
+        HDC dc;
+
+        if (!width) width = get_system_metrics( SM_CXBORDER );
+        if (!height) height = get_system_metrics( SM_CYBORDER );
+
+        /* create the uniform bitmap on the fly */
+        dc = NtUserGetDCEx( hwnd, 0, DCX_USESTYLE );
+        if (dc)
+        {
+            HDC mem_dc = NtGdiCreateCompatibleDC( dc );
+            if (mem_dc)
+            {
+                if ((caret_bitmap = NtGdiCreateCompatibleBitmap( mem_dc, width, height )))
+                {
+                    HBITMAP prev_bitmap = NtGdiSelectBitmap( mem_dc, caret_bitmap );
+                    SetRect( &r, 0, 0, width, height );
+                    fill_rect( mem_dc, &r, GetStockObject( bitmap ? GRAY_BRUSH : WHITE_BRUSH ));
+                    NtGdiSelectBitmap( mem_dc, prev_bitmap );
+                }
+                NtGdiDeleteObjectApp( mem_dc );
+            }
+            NtUserReleaseDC( hwnd, dc );
+        }
+    }
+    if (!caret_bitmap) return FALSE;
+
+    SERVER_START_REQ( set_caret_window )
+    {
+        req->handle = wine_server_user_handle( hwnd );
+        req->width  = width;
+        req->height = height;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            prev      = wine_server_ptr_handle( reply->previous );
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+    if (!ret) return FALSE;
+
+    if (prev && !hidden)  /* hide the previous one */
+    {
+        /* FIXME: won't work if prev belongs to a different process */
+        kill_system_timer( prev, SYSTEM_TIMER_CARET );
+        if (old_state) display_caret( prev, &r );
+    }
+
+    if (caret.bitmap) NtGdiDeleteObjectApp( caret.bitmap );
+    caret.bitmap = caret_bitmap;
+    caret.timeout = get_caret_registry_timeout();
+    return TRUE;
+}
+
+/*******************************************************************
+ *              destroy_caret
+ */
+BOOL destroy_caret(void)
+{
+    int old_state = 0;
+    int hidden = 0;
+    HWND prev = 0;
+    BOOL ret;
+    RECT r;
+
+    SERVER_START_REQ( set_caret_window )
+    {
+        req->handle = 0;
+        req->width  = 0;
+        req->height = 0;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            prev      = wine_server_ptr_handle( reply->previous );
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (ret && prev && !hidden)
+    {
+        /* FIXME: won't work if prev belongs to a different process */
+        kill_system_timer( prev, SYSTEM_TIMER_CARET );
+        if (old_state) display_caret( prev, &r );
+    }
+    if (caret.bitmap) NtGdiDeleteObjectApp( caret.bitmap );
+    caret.bitmap = 0;
+    return ret;
+}
+
+/*****************************************************************
+ *           NtUserGetCaretBlinkTime  (win32u.@)
+ */
+UINT WINAPI NtUserGetCaretBlinkTime(void)
+{
+    return caret.timeout;
+}
+
+/*******************************************************************
+ *              set_caret_blink_time
+ */
+BOOL set_caret_blink_time( unsigned int time )
+{
+    TRACE( "time %u\n", time );
+
+    caret.timeout = time;
+    /* FIXME: update the timer */
+    return TRUE;
+}
+
+/*****************************************************************
+ *           NtUserGetCaretPos  (win32u.@)
+ */
+BOOL WINAPI NtUserGetCaretPos( POINT *pt )
+{
+    BOOL ret;
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = 0;  /* don't set anything */
+        req->handle = 0;
+        req->x      = 0;
+        req->y      = 0;
+        req->hide   = 0;
+        req->state  = 0;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            pt->x = reply->old_rect.left;
+            pt->y = reply->old_rect.top;
+        }
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+/*******************************************************************
+ *              set_caret_pos
+ */
+BOOL set_caret_pos( int x, int y )
+{
+    int old_state = 0;
+    int hidden = 0;
+    HWND hwnd = 0;
+    BOOL ret;
+    RECT r;
+
+    TRACE( "(%d, %d)\n", x, y );
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = SET_CARET_POS|SET_CARET_STATE;
+        req->handle = 0;
+        req->x      = x;
+        req->y      = y;
+        req->hide   = 0;
+        req->state  = CARET_STATE_ON_IF_MOVED;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            hwnd      = wine_server_ptr_handle( reply->full_handle );
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+    if (ret && !hidden && (x != r.left || y != r.top))
+    {
+        if (old_state) display_caret( hwnd, &r );
+        r.right += x - r.left;
+        r.bottom += y - r.top;
+        r.left = x;
+        r.top = y;
+        display_caret( hwnd, &r );
+        NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout );
+    }
+    return ret;
+}
+
+/*****************************************************************
+ *           NtUserShowCaret  (win32u.@)
+ */
+BOOL WINAPI NtUserShowCaret( HWND hwnd )
+{
+    int hidden = 0;
+    BOOL ret;
+    RECT r;
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = SET_CARET_HIDE | SET_CARET_STATE;
+        req->handle = wine_server_user_handle( hwnd );
+        req->x      = 0;
+        req->y      = 0;
+        req->hide   = -1;
+        req->state  = CARET_STATE_ON;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            hwnd      = wine_server_ptr_handle( reply->full_handle );
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (ret && hidden == 1)  /* hidden was 1 so it's now 0 */
+    {
+        display_caret( hwnd, &r );
+        NtUserSetSystemTimer( hwnd, SYSTEM_TIMER_CARET, caret.timeout );
+    }
+    return ret;
+}
+
+/*****************************************************************
+ *           NtUserHideCaret  (win32u.@)
+ */
+BOOL WINAPI NtUserHideCaret( HWND hwnd )
+{
+    int old_state = 0;
+    int hidden = 0;
+    BOOL ret;
+    RECT r;
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = SET_CARET_HIDE | SET_CARET_STATE;
+        req->handle = wine_server_user_handle( hwnd );
+        req->x      = 0;
+        req->y      = 0;
+        req->hide   = 1;
+        req->state  = CARET_STATE_OFF;
+        if ((ret = !wine_server_call_err( req )))
+        {
+            hwnd      = wine_server_ptr_handle( reply->full_handle );
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            old_state = reply->old_state;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (ret && !hidden)
+    {
+        if (old_state) display_caret( hwnd, &r );
+        kill_system_timer( hwnd, SYSTEM_TIMER_CARET );
+    }
+    return ret;
+}
+
+void toggle_caret( HWND hwnd )
+{
+    BOOL ret;
+    RECT r;
+    int hidden = 0;
+
+    SERVER_START_REQ( set_caret_info )
+    {
+        req->flags  = SET_CARET_STATE;
+        req->handle = wine_server_user_handle( hwnd );
+        req->x      = 0;
+        req->y      = 0;
+        req->hide   = 0;
+        req->state  = CARET_STATE_TOGGLE;
+        if ((ret = !wine_server_call( req )))
+        {
+            hwnd      = wine_server_ptr_handle( reply->full_handle );
+            r.left    = reply->old_rect.left;
+            r.top     = reply->old_rect.top;
+            r.right   = reply->old_rect.right;
+            r.bottom  = reply->old_rect.bottom;
+            hidden    = reply->old_hide;
+        }
+    }
+    SERVER_END_REQ;
+
+    if (ret && !hidden) display_caret( hwnd, &r );
+}
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c
index 8ad4a0271b3..d43dca723d2 100644
--- a/dlls/win32u/message.c
+++ b/dlls/win32u/message.c
@@ -2474,8 +2474,7 @@ LRESULT dispatch_message( const MSG *msg, BOOL ansi )
         switch (msg->wParam)
         {
             case SYSTEM_TIMER_CARET:
-                if (!user_callbacks) break;
-                user_callbacks->toggle_caret( msg->hwnd );
+                toggle_caret( msg->hwnd );
                 return 0;
 
             case SYSTEM_TIMER_TRACK_MOUSE:
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h
index cad038dbff6..632cb16d23a 100644
--- a/dlls/win32u/ntuser_private.h
+++ b/dlls/win32u/ntuser_private.h
@@ -34,13 +34,10 @@ struct user_callbacks
 {
     BOOL (WINAPI *pAdjustWindowRectEx)( RECT *, DWORD, BOOL, DWORD );
     HANDLE (WINAPI *pCopyImage)( HANDLE, UINT, INT, INT, UINT );
-    BOOL (WINAPI *pDestroyCaret)(void);
     BOOL (WINAPI *pEndMenu)(void);
-    BOOL (WINAPI *pHideCaret)( HWND hwnd );
     BOOL (WINAPI *pImmProcessKey)(HWND, HKL, UINT, LPARAM, DWORD);
     BOOL (WINAPI *pImmTranslateMessage)(HWND, UINT, WPARAM, LPARAM);
     BOOL (WINAPI *pSetSystemMenu)( HWND hwnd, HMENU menu );
-    BOOL (WINAPI *pShowCaret)( HWND hwnd );
     void (CDECL *free_menu_items)( void *ptr );
     void (CDECL *free_win_ptr)( struct tagWND *win );
     HWND (CDECL *is_menu_active)(void);
@@ -51,7 +48,6 @@ struct user_callbacks
     BOOL (CDECL *rawinput_device_get_usages)(HANDLE handle, USHORT *usage_page, USHORT *usage);
     void (CDECL *register_builtin_classes)(void);
     void (WINAPI *set_standard_scroll_painted)( HWND hwnd, INT bar, BOOL visible );
-    void (CDECL *toggle_caret)( HWND hwnd );
     BOOL (CDECL *unpack_dde_message)( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam,
                                       void **buffer, size_t size );
     BOOL (WINAPI *register_imm)( HWND hwnd );
diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c
index 0be0863b992..dc58cbe1944 100644
--- a/dlls/win32u/syscall.c
+++ b/dlls/win32u/syscall.c
@@ -119,6 +119,8 @@ static void * const syscalls[] =
     NtUserFindWindowEx,
     NtUserGetAncestor,
     NtUserGetAtomName,
+    NtUserGetCaretBlinkTime,
+    NtUserGetCaretPos,
     NtUserGetClassName,
     NtUserGetClipboardFormatName,
     NtUserGetClipboardOwner,
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c
index 696fc9d922d..3cf03d68399 100644
--- a/dlls/win32u/sysparams.c
+++ b/dlls/win32u/sysparams.c
@@ -4653,6 +4653,9 @@ ULONG_PTR WINAPI NtUserCallNoParam( ULONG code )
 {
     switch(code)
     {
+    case NtUserCallNoParam_DestroyCaret:
+        return destroy_caret();
+
     case NtUserCallNoParam_GetDesktopWindow:
         return HandleToUlong( get_desktop_window() );
 
@@ -4744,6 +4747,9 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code )
     case NtUserCallOneParam_MessageBeep:
         return message_beep( arg );
 
+    case NtUserCallOneParam_SetCaretBlinkTime:
+        return set_caret_blink_time( arg );
+
     /* temporary exports */
     case NtUserCallHooks:
         {
@@ -4800,6 +4806,9 @@ ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code
     case NtUserCallTwoParam_ReplyMessage:
         return reply_message_result( arg1, (MSG *)arg2 );
 
+    case NtUserCallTwoParam_SetCaretPos:
+        return set_caret_pos( arg1, arg2 );
+
     case NtUserCallTwoParam_SetIconParam:
         return set_icon_param( UlongToHandle(arg1), arg2 );
 
diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec
index e94ec7f4a39..208b167229e 100644
--- a/dlls/win32u/win32u.spec
+++ b/dlls/win32u/win32u.spec
@@ -807,7 +807,7 @@
 @ stdcall -syscall NtUserCreateAcceleratorTable(ptr long)
 @ stub NtUserCreateActivationGroup
 @ stub NtUserCreateActivationObject
-@ stub NtUserCreateCaret
+@ stdcall NtUserCreateCaret(long long long long)
 @ stub NtUserCreateDCompositionHwndTarget
 @ stdcall -syscall NtUserCreateDesktopEx(ptr ptr ptr long long long)
 @ stub NtUserCreateEmptyCursorObject
@@ -896,8 +896,8 @@
 @ stub NtUserGetAutoRotationState
 @ stub NtUserGetCIMSSM
 @ stub NtUserGetCPD
-@ stub NtUserGetCaretBlinkTime
-@ stub NtUserGetCaretPos
+@ stdcall -syscall NtUserGetCaretBlinkTime()
+@ stdcall -syscall NtUserGetCaretPos(ptr)
 @ stdcall NtUserGetClassInfoEx(ptr ptr ptr ptr long)
 @ stdcall -syscall NtUserGetClassName(long long ptr)
 @ stub NtUserGetClipCursor
@@ -1020,7 +1020,7 @@
 @ stub NtUserGhostWindowFromHungWindow
 @ stub NtUserHandleDelegatedInput
 @ stub NtUserHardErrorControl
-@ stub NtUserHideCaret
+@ stdcall NtUserHideCaret(long)
 @ stub NtUserHidePointerContactVisualization
 @ stub NtUserHiliteMenuItem
 @ stub NtUserHungWindowFromGhostWindow
@@ -1257,7 +1257,7 @@
 @ stdcall NtUserSetWindowWord(long long long)
 @ stub NtUserSetWindowsHookAW
 @ stdcall -syscall NtUserSetWindowsHookEx(ptr ptr long long ptr long)
-@ stub NtUserShowCaret
+@ stdcall NtUserShowCaret(long)
 @ stdcall NtUserShowCursor(long)
 @ stub NtUserShowScrollBar
 @ stub NtUserShowSystemCursor
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h
index 122921431fc..caf77590559 100644
--- a/dlls/win32u/win32u_private.h
+++ b/dlls/win32u/win32u_private.h
@@ -197,6 +197,7 @@ struct unix_funcs
     BOOL     (WINAPI *pNtUserClipCursor)( const RECT *rect );
     BOOL     (WINAPI *pNtUserCloseClipboard)(void);
     INT      (WINAPI *pNtUserCountClipboardFormats)(void);
+    BOOL     (WINAPI *pNtUserCreateCaret)( HWND hwnd, HBITMAP bitmap, int width, int height );
     HWND     (WINAPI *pNtUserCreateWindowEx)( DWORD ex_style, UNICODE_STRING *class_name,
                                               UNICODE_STRING *version, UNICODE_STRING *window_name,
                                               DWORD style, INT x, INT y, INT width, INT height,
@@ -240,6 +241,7 @@ struct unix_funcs
     BOOL     (WINAPI *pNtUserGetUpdateRect)( HWND hwnd, RECT *rect, BOOL erase );
     INT      (WINAPI *pNtUserGetUpdateRgn)( HWND hwnd, HRGN hrgn, BOOL erase );
     BOOL     (WINAPI *pNtUserGetUpdatedClipboardFormats)( UINT *formats, UINT size, UINT *out_size );
+    BOOL     (WINAPI *pNtUserHideCaret)( HWND hwnd );
     BOOL     (WINAPI *pNtUserIsClipboardFormatAvailable)( UINT format );
     UINT     (WINAPI *pNtUserMapVirtualKeyEx)( UINT code, UINT type, HKL layout );
     LRESULT  (WINAPI *pNtUserMessageCall)( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam,
@@ -284,6 +286,7 @@ struct unix_funcs
     BOOL     (WINAPI *pNtUserSetWindowPos)( HWND hwnd, HWND after, INT x, INT y, INT cx, INT cy, UINT flags );
     int      (WINAPI *pNtUserSetWindowRgn)( HWND hwnd, HRGN hrgn, BOOL redraw );
     WORD     (WINAPI *pNtUserSetWindowWord)( HWND hwnd, INT offset, WORD newval );
+    BOOL     (WINAPI *pNtUserShowCaret)( HWND hwnd );
     INT      (WINAPI *pNtUserShowCursor)( BOOL show );
     BOOL     (WINAPI *pNtUserShowWindow)( HWND hwnd, INT cmd );
     BOOL     (WINAPI *pNtUserShowWindowAsync)( HWND hwnd, INT cmd );
@@ -354,6 +357,7 @@ extern LRESULT call_hooks( INT id, INT code, WPARAM wparam, LPARAM lparam, BOOL
 extern BOOL unhook_windows_hook( INT id, HOOKPROC proc ) DECLSPEC_HIDDEN;
 
 /* input.c */
+extern BOOL destroy_caret(void) DECLSPEC_HIDDEN;
 extern LONG global_key_state_counter DECLSPEC_HIDDEN;
 extern HWND get_active_window(void) DECLSPEC_HIDDEN;
 extern HWND get_capture(void) DECLSPEC_HIDDEN;
@@ -362,7 +366,10 @@ extern HWND get_focus(void) DECLSPEC_HIDDEN;
 extern DWORD get_input_state(void) DECLSPEC_HIDDEN;
 extern BOOL WINAPI release_capture(void) DECLSPEC_HIDDEN;
 extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ) DECLSPEC_HIDDEN;
+extern BOOL set_caret_blink_time( unsigned int time ) DECLSPEC_HIDDEN;
+extern BOOL set_caret_pos( int x, int y ) DECLSPEC_HIDDEN;
 extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN;
+extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN;
 extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN;
 
 /* menu.c */
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c
index a20c2886bc1..e206881e596 100644
--- a/dlls/win32u/window.c
+++ b/dlls/win32u/window.c
@@ -3307,13 +3307,10 @@ BOOL set_window_pos( WINDOWPOS *winpos, int parent_x, int parent_y )
                            &new_window_rect, &new_client_rect, valid_rects ))
         goto done;
 
-    if (user_callbacks)
-    {
-        if (winpos->flags & SWP_HIDEWINDOW)
-            user_callbacks->pHideCaret( winpos->hwnd );
-        else if (winpos->flags & SWP_SHOWWINDOW)
-            user_callbacks->pShowCaret( winpos->hwnd );
-    }
+    if (winpos->flags & SWP_HIDEWINDOW)
+        NtUserHideCaret( winpos->hwnd );
+    else if (winpos->flags & SWP_SHOWWINDOW)
+        NtUserShowCaret( winpos->hwnd );
 
     if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
     {
@@ -4407,7 +4404,7 @@ static void send_destroy_message( HWND hwnd )
     info.cbSize = sizeof(info);
     if (NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ))
     {
-        if (hwnd == info.hwndCaret && user_callbacks) user_callbacks->pDestroyCaret();
+        if (hwnd == info.hwndCaret) destroy_caret();
         if (hwnd == info.hwndActive) activate_other_window( hwnd );
     }
 
diff --git a/dlls/win32u/wrappers.c b/dlls/win32u/wrappers.c
index d38501f5c4c..05107352dfa 100644
--- a/dlls/win32u/wrappers.c
+++ b/dlls/win32u/wrappers.c
@@ -780,6 +780,12 @@ INT WINAPI NtUserCountClipboardFormats(void)
     return unix_funcs->pNtUserCountClipboardFormats();
 }
 
+BOOL WINAPI NtUserCreateCaret( HWND hwnd, HBITMAP bitmap, int width, int height )
+{
+    if (!unix_funcs) return 0;
+    return unix_funcs->pNtUserCreateCaret( hwnd, bitmap, width, height );
+}
+
 HWND WINAPI NtUserCreateWindowEx( DWORD ex_style, UNICODE_STRING *class_name,
                                   UNICODE_STRING *version, UNICODE_STRING *window_name,
                                   DWORD style, INT x, INT y, INT width, INT height,
@@ -957,6 +963,12 @@ INT WINAPI NtUserGetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase )
     return unix_funcs->pNtUserGetUpdateRgn( hwnd, hrgn, erase );
 }
 
+BOOL WINAPI NtUserHideCaret( HWND hwnd )
+{
+    if (!unix_funcs) return FALSE;
+    return unix_funcs->pNtUserHideCaret( hwnd );
+}
+
 BOOL WINAPI NtUserMoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy, BOOL repaint )
 {
     if (!unix_funcs) return 0;
@@ -1197,6 +1209,12 @@ WORD WINAPI NtUserSetWindowWord( HWND hwnd, INT offset, WORD newval )
     return unix_funcs->pNtUserSetWindowWord( hwnd, offset, newval );
 }
 
+BOOL WINAPI NtUserShowCaret( HWND hwnd )
+{
+    if (!unix_funcs) return FALSE;
+    return unix_funcs->pNtUserShowCaret( hwnd );
+}
+
 INT WINAPI NtUserShowCursor( BOOL show )
 {
     if (!unix_funcs) return 0;
diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h
index 124506bdb05..1bfc210eab0 100644
--- a/dlls/wow64win/syscall.h
+++ b/dlls/wow64win/syscall.h
@@ -106,6 +106,8 @@
     SYSCALL_ENTRY( NtUserFindWindowEx ) \
     SYSCALL_ENTRY( NtUserGetAncestor ) \
     SYSCALL_ENTRY( NtUserGetAtomName ) \
+    SYSCALL_ENTRY( NtUserGetCaretBlinkTime ) \
+    SYSCALL_ENTRY( NtUserGetCaretPos ) \
     SYSCALL_ENTRY( NtUserGetClassName ) \
     SYSCALL_ENTRY( NtUserGetClipboardFormatName ) \
     SYSCALL_ENTRY( NtUserGetClipboardOwner ) \
diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c
index 3e8004b005c..554a6634f0e 100644
--- a/dlls/wow64win/user.c
+++ b/dlls/wow64win/user.c
@@ -608,6 +608,18 @@ NTSTATUS WINAPI wow64_NtUserKillTimer( UINT *args )
     return NtUserKillTimer( hwnd, id );
 }
 
+NTSTATUS WINAPI wow64_NtUserGetCaretBlinkTime( UINT *args )
+{
+    return NtUserGetCaretBlinkTime();
+}
+
+NTSTATUS WINAPI wow64_NtUserGetCaretPos( UINT *args )
+{
+    POINT *pt = get_ptr( &args );
+
+    return NtUserGetCaretPos( pt );
+}
+
 NTSTATUS WINAPI wow64_NtUserCopyAcceleratorTable( UINT *args )
 {
     HACCEL src = get_handle( &args );
diff --git a/include/ntuser.h b/include/ntuser.h
index 47bc7cbeb41..f49c9bc7723 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -463,6 +463,7 @@ BOOL    WINAPI NtUserCloseWindowStation( HWINSTA handle );
 INT     WINAPI NtUserCopyAcceleratorTable( HACCEL src, ACCEL *dst, INT count );
 INT     WINAPI NtUserCountClipboardFormats(void);
 HACCEL  WINAPI NtUserCreateAcceleratorTable( ACCEL *table, INT count );
+BOOL    WINAPI NtUserCreateCaret( HWND hwnd, HBITMAP bitmap, int width, int height );
 HDESK   WINAPI NtUserCreateDesktopEx( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *device,
                                       DEVMODEW *devmode, DWORD flags, ACCESS_MASK access,
                                       ULONG heap_size );
@@ -500,6 +501,8 @@ BOOL    WINAPI NtUserFlashWindowEx( FLASHWINFO *info );
 HWND    WINAPI NtUserGetAncestor( HWND hwnd, UINT type );
 SHORT   WINAPI NtUserGetAsyncKeyState( INT key );
 ULONG   WINAPI NtUserGetAtomName( ATOM atom, UNICODE_STRING *name );
+UINT    WINAPI NtUserGetCaretBlinkTime(void);
+BOOL    WINAPI NtUserGetCaretPos( POINT *point );
 ATOM    WINAPI NtUserGetClassInfoEx( HINSTANCE instance, UNICODE_STRING *name, WNDCLASSEXW *wc,
                                      struct client_menu_name *menu_name, BOOL ansi );
 INT     WINAPI NtUserGetClassName( HWND hwnd, BOOL real, UNICODE_STRING *name );
@@ -547,6 +550,7 @@ INT     WINAPI NtUserGetUpdateRgn( HWND hwnd, HRGN hrgn, BOOL erase );
 BOOL    WINAPI NtUserGetUpdatedClipboardFormats( UINT *formats, UINT size, UINT *out_size );
 BOOL    WINAPI NtUserGetUpdateRect( HWND hwnd, RECT *rect, BOOL erase );
 int     WINAPI NtUserGetWindowRgnEx( HWND hwnd, HRGN hrgn, UINT unk );
+BOOL    WINAPI NtUserHideCaret( HWND hwnd );
 NTSTATUS WINAPI NtUserInitializeClientPfnArrays( const struct user_client_procs *client_procsA,
                                                  const struct user_client_procs *client_procsW,
                                                  const void *client_workers, HINSTANCE user_module );
@@ -616,6 +620,7 @@ HHOOK   WINAPI NtUserSetWindowsHookEx( HINSTANCE inst, UNICODE_STRING *module, D
 HWINEVENTHOOK WINAPI NtUserSetWinEventHook( DWORD event_min, DWORD event_max, HMODULE inst,
                                             UNICODE_STRING *module, WINEVENTPROC proc,
                                             DWORD pid, DWORD tid, DWORD flags );
+BOOL    WINAPI NtUserShowCaret( HWND hwnd );
 INT     WINAPI NtUserShowCursor( BOOL show );
 BOOL    WINAPI NtUserShowWindow( HWND hwnd, INT cmd );
 BOOL    WINAPI NtUserShowWindowAsync( HWND hwnd, INT cmd );
@@ -643,6 +648,7 @@ HWND    WINAPI NtUserWindowFromPoint( LONG x, LONG y );
 /* NtUserCallNoParam codes, not compatible with Windows */
 enum
 {
+    NtUserCallNoParam_DestroyCaret,
     NtUserCallNoParam_GetDesktopWindow,
     NtUserCallNoParam_GetInputState,
     NtUserCallNoParam_ReleaseCapture,
@@ -651,6 +657,11 @@ enum
     NtUserThreadDetach,
 };
 
+static inline BOOL NtUserDestroyCaret(void)
+{
+    return NtUserCallNoParam( NtUserCallNoParam_DestroyCaret );
+}
+
 static inline HWND NtUserGetDesktopWindow(void)
 {
     return UlongToHandle( NtUserCallNoParam( NtUserCallNoParam_GetDesktopWindow ));
@@ -688,6 +699,7 @@ enum
     NtUserCallOneParam_IsWindowRectFullScreen,
     NtUserCallOneParam_MessageBeep,
     NtUserCallOneParam_RealizePalette,
+    NtUserCallOneParam_SetCaretBlinkTime,
     /* temporary exports */
     NtUserCallHooks,
     NtUserGetDeskPattern,
@@ -754,6 +766,11 @@ static inline RECT NtUserGetPrimaryMonitorRect(void)
     return primary;
 }
 
+static inline BOOL NtUserSetCaretBlinkTime( unsigned int time )
+{
+    return NtUserCallOneParam( time, NtUserCallOneParam_SetCaretBlinkTime );
+}
+
 static inline COLORREF NtUserGetSysColor( INT index )
 {
     return NtUserCallOneParam( index, NtUserCallOneParam_GetSysColor );
@@ -804,6 +821,7 @@ enum
     NtUserCallTwoParam_GetSystemMetricsForDpi,
     NtUserCallTwoParam_MonitorFromRect,
     NtUserCallTwoParam_ReplyMessage,
+    NtUserCallTwoParam_SetCaretPos,
     NtUserCallTwoParam_SetIconParam,
     NtUserCallTwoParam_UnhookWindowsHook,
     /* temporary exports */
@@ -839,6 +857,11 @@ static inline BOOL NtUserReplyMessage( LRESULT result, MSG *msg )
     return NtUserCallTwoParam( result, (UINT_PTR)msg, NtUserCallTwoParam_ReplyMessage );
 }
 
+static inline BOOL NtUserSetCaretPos( int x, int y )
+{
+    return NtUserCallTwoParam( x, y, NtUserCallTwoParam_SetCaretPos );
+}
+
 static inline UINT_PTR NtUserSetIconParam( HICON icon, ULONG_PTR param )
 {
     return NtUserCallTwoParam( HandleToUlong(icon), param, NtUserCallTwoParam_SetIconParam );

