You'll need the following Windows functions:

Private Declare Function CreateCaret Lib "User32" (ByVal hWnd As Long, ByVal hBitmap As Long, ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function SetCaretPos Lib "User32" (ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function ShowCaret Lib "User32" (ByVal hWnd As Long) As Long
Private Declare Function DestroyCaret Lib "User32" () As Long

When you receive the focus, call the CreateCaret function.

  • hWnd is the hWnd property of the control.
  • hBitmap is 0 for a black caret, 1 for a grey caret, or a bitmap.
  • X and Y are the width and the height of the caret; for a bitmap caret they're ignored.
Private Sub MyControl_GotFocus()
CreateCaret MyControl.hWnd, SomePicture.Handle, 0, 0
SetCaretPos 8, 8
ShowCaret MyControl.hWnd
End Sub

According to the Windows documentation you should destroy the caret when you lose the focus. But unfortunately VB issues the GotFocus and LostFocus events both from WM_SETFOCUS, after the receiving control has created its caret. So if you would try to destroy your caret in your LostFocus event, you would be destroying that other control's caret! Which would be bad if it were for example a TextBox. The solution either involves a lot of hooking, or the following code for all controls that don't display a caret, like the CommandButton control:

Private Sub MyControl_GotFocus()
End Sub

Which is cumbersome, but works. Some final remarks:

  • You can only have one caret per message queue; every call to CreateCaret contains implicit in it a call to DestroyCaret before the new caret is made. This means you don't have to worry about ‘caret leaks’.
  • Carets will blink automatically when shown, and will automatically pause blinking while they move, so that the user can track the caret while they are entering text.
  • If you do all your painting in Paint events, Windows will automatically hide and redisplay your caret so that you won't paint over the caret.
  • If you want to use a colour bitmap, you may want to xor it against the background colour of whatever control you will be displaying it in before creating the caret.

That's it. As you can see, creating and using carets is easy.