Using Cursors


Early versions of Visual Basic lacked any means of assigning a custom mouse pointer, although this is a common technique in Windows-based programs. Many programmers who tried to get around this limitation turned to the Windows API, but even then solutions proved unexpectedly difficult.


Visual Basic now provides a simple and intuitive solution (see the sidebar “Cursors Eat Mouse Icons for Lunch,” page 442). But WinWatch can’t use the Visual Basic Way because it gets cursors from resources. If you check out the Windows API Help, the solution looks simple: just call SetCursor. When you try this, however, the new cursor flickers on and then disappears. Every time you move the cursor, Visual Basic’s original cursor is restored.


Here’s how WinWatch works around this limitation:

Sub ShowCursor(ByVal hMod As Long, sCursor As String)
‘ Get cursor handle
hResourceCur = LoadImage(hMod, sCursor, IMAGE_CURSOR, 0, 0, 0)
If hResourceCur <> hNull Then
ordPointerLast = MousePointer
MousePointer = vbCustom
MouseIcon = CursorToPicture(hResourceCur)
ordResourceLast = RT_CURSOR
Call DrawIconEx(pbResource.hDC, 0, 0, hResourceCur, _
0, 0, 0, hNull, DI_NORMAL)
Else
pbResource.Print “Can’t display cursor: “ & sCrLf & sCrLf & _
WordWrap(ApiError(Err.LastDllError), 25)
End If
End Sub

It simply calls the CursorToPicture function and sets the resulting picture to the form’s MouseIcon property. That’s half the operation. You must also restore the cursor when you change resources. Here’s the part of the Select Case block in ClearResource that restores the previous cursor.

Case RT_GROUP_CURSOR, RT_CURSOR
MousePointer = ordPointerLast

You saw the BitmapToPicture function, and I told you that IconToPicture looked the same. You can probably guess what CursorToPicture looks like. But you guessed wrong:

Function CursorToPicture(ByVal hIcon As Long) As IPicture
‘ It’s just an alias
Set CursorToPicture = IconToPicture(hIcon)
End Function

The StdPicture class is notoriously ignorant about cursors. It accepts them but doesn’t distinguish them from icons. The MouseIcon property, however, knows the difference, and that’s all that matters.


ShowCursor also uses the DrawIconEx function (which also doesn’t distinguish between icons and cursors) to draw a static picture of the cursor. The Draw­Cursors procedure uses code similar to that in ShowIcons to draw each of the cursors in a cursor group. Then it uses the same code as ShowCursor to load the one that best fits the current environment.