How to Create and Use a Custom Cursor in Visual Basic; Win SDK

Last reviewed: June 21, 1995
Article ID: Q76666
The information in this article applies to:

- Standard and Professional Editions of Microsoft Visual Basic for

  Windows, versions 2.0 and 3.0
- Microsoft Visual Basic programming system for Windows, version 1.0

SUMMARY

Using a graphics editor, the Microsoft Windows Software Development Kit (SDK), and the Microsoft C compiler, you can create a dynamic-link library (DLL) containing mouse cursors that can be used in a Microsoft Visual Basic application. By making calls to the Windows API functions LoadLibrary, LoadCursor, SetClassWord, and GetFocus, you can display a custom cursor from within a Visual Basic application. Below are the steps necessary to a create a custom cursor and a Visual Basic application to use this custom cursor.

MORE INFORMATION

Setting a custom cursor in a Visual Basic application requires a call to the Windows API function LoadLibrary to load the custom DLL containing the cursor resource(s). A call to LoadCursor is then required to load a single cursor contained in the DLL. The return value of the LoadCursor function is a handle to the custom cursor. This handle can be passed as an argument to the API function SetClassWord with the constant GCW_HCURSOR. SetClassWord also requires a window handle (hWnd) to the object (form or control) for which the cursor is to be set. The hWnd of a form is available via the hWnd run-time method. For example, the statement FWnd = Form1.hWnd will return the hWnd of Form1 to the variable FWnd. The hWnd of a control can be obtained by first using the SetFocus method on the control to give it the input focus and then calling the API function GetFocus. GetFocus returns the hWnd of the object with the current input focus.

A custom cursor always takes the place of the system cursor. The MousePointer property of a form or control to receive the custom cursor must be set to zero (system). Any other value for this property will result in the selected cursor being displayed, not the custom cursor.

Because the cursor is defined as part of a window class, any change to the window class will be reflected across any control or form that uses that class. For example, if the MousePointer property for two command buttons is zero (system) and a custom cursor is set for one of the command buttons, both of the command buttons will receive the custom cursor. To guarantee a custom cursor for each control requires that the cursor be set by calling SetClassWord in the MouseMove event procedure of the control.

Some controls, such as command buttons, do not contain a MouseMove event procedure. A custom mouse pointer for these types of controls can be set by initiating a timer event. Within the timer event, calls to the API functions GetCursorPos and WindowFromPoint can be made to determine if the mouse is over the control or not. If the WindowFromPoint API call returns the hWnd of the control, then the mouse is over the control. A call to SetClassWord can then be made to set the custom cursor for the control.

Below is an example of using the Windows SDK and C Compiler to create a DLL containing cursor resources. Further below are the steps necessary to create a Visual Basic for Windows program to use the cursor resources.

If you do not have the Windows SDK but have a pre-compiled DLL containing cursor resources, skip to the steps below outlining how to create a Visual Basic application to use the custom cursor resources.

  1. Using a graphics editor such as Microsoft Windows SDK Paint program, create two cursor images. Save the images separately as CURS1.CUR and CURS2.CUR, respectively.

  2. Using any text editor, create a C source file containing the minimum amount of code for a Windows DLL. The source code must contain the functions LibEntry and WEP (Windows exit procedure). Below is an example of the C source file:

       #include <windows.h>
       int _far _pascal LibMain (HANDLE hInstance,
                                 WORD wDataSeg,
                                 WORD cbHeapSize,
                                 LPSTR lpszCmdLine)
       {
          return(1);
       }
    
       int _far _pascal WEP (int nParameter)
       {
          return(1);
       }
    
    

  3. Save the file created in step 2 above as CURSORS.C.

  4. Using any text editor, create a definition file (.DEF) for the DLL. Enter the following as the body of the .DEF file:

    LIBRARY CURSORS

    DESCRIPTION 'DLL containing cursor resources'

    EXETYPE WINDOWS

    STUB 'WINSTUB.EXE'

    CODE MOVEABLE DISCARDABLE

    DATA MOVEABLE SINGLE

    HEAPSIZE 0

    EXPORTS

          WEP   @1 RESIDENTNAME
    
    

  5. Save the file created in step 4 above as CURSORS.DEF.

  6. Using a text editor, create a resource file for the cursors created in step 1 above. Enter the following as the body of the .RC file:

    Cursor1 CURSOR CURS1.CUR Cursor2 CURSOR CURS2.CUR

  7. Save the file created in step 6 above as CURSORS.RC.

  8. Compile CURSORS.C from the MS-DOS command line as follows:

           CL /W2 /ALw /c /Od /GD /W2 CURSORS.C
    

  9. Link the program from the MS-DOS command line as follows (enter the following two lines on a single line):

    LINK /NOE /NOD cursors.obj +

                LIBENTRY.OBJ,,,MDLLCEW.LIB+LIBW.LIB,CURSORS.DEF;
    
       This will create the file CURSORS.EXE.
    
    

  10. Add the cursor resources created in step 1 above to the .EXE file

        created in step 9 above by invoking the Microsoft Resource
        Compiler (RC.EXE) from the MS-DOS command line as follows:
    

        RC CURSORS.RC
    

  11. Rename CURSORS.EXE to CURSORS.DLL from the MS-DOS command line as

        follows:
    

        REN CURSORS.EXE CURSORS.DLL
    

Below are the steps necessary to create a Visual Basic for Windows application that uses the cursor resources created in the steps above.

Important

When running the Visual Basic for Windows program created by following the steps below, it is important to terminate the application from the system menu, NOT the Run End option from the file menu. When Run End is chosen from the file menu, the unload event procedure is not executed. Therefore, the system cursor is not restored and the custom cursor will remain present at design time. Using Visual Basic version 1.0 for Windows, avoid terminating the program from the Program Manager (PROGMAN.EXE) task list. The unload event procedure is also not called when a program is terminated from the task list in Visual Basic version 1.0 for Windows.

  1. Start Visual Basic for Windows, or from the File menu, choose New Project (press ALT, F, N) if Visual Basic for Windows is already running. Form1 will be created by default.

  2. Place a picture control (Picture1), command button (Command1), and timer control (Timer1) on Form1.

  3. Enter the following code in the Global Module:

    Type PointType

          x As Integer
          y As Integer
    
    End Type

  4. Enter the following code in the General Declaration section of Form1:

    DefInt A-Z

       ' Enter each of the following Declare statements as one, single line:
       Declare Function LoadLibrary Lib "kernel" (ByVal LibName$)
       Declare Function LoadCursor Lib "user"
          (ByVal hInstance, ByVal CursorName$)
       Declare Function SetClassWord Lib "user"
          (ByVal hWnd, ByVal nIndex, ByVal NewVal)
       Declare Function GetFocus Lib "user" ()
       Declare Function PutFocus Lib "user" Alias "SetFocus" (ByVal hWnd)
       Declare Sub GetCursorPos Lib "user" (p As PointType)
       Declare Function WindowFromPoint Lib "user" (ByVal y, ByVal x)
       Declare Sub FreeLibrary LIB "Kernel" (ByVal hLIbMod as Integer)
       Const GCW_HCURSOR = (-12)
       Dim DLLInstance as Long
       Dim SysCursHandle
       Dim Curs1Handle
       Dim Curs2Handle
       Dim Pic1hWnd
       Dim Command1hWnd
       Dim p As PointType
    
    

  5. Enter the following code in the Form_Load event procedure of Form1:

       Sub Form_Load ()
          Form1.Show
          DLLInstance = LoadLibrary("CURSORS.DLL")
          Curs1Handle = LoadCursor(DLLInstance, "Cursor1")
          Curs2Handle = LoadCursor(DLLInstance, "Cursor2")
          SysCursHandle=SetClassWord(Form1.hWnd,GCW_HCURSOR,Curs2Handle)
    
          ' Get the current control with the input focus.
          CurrHwnd = GetFocus()
    
          ' Get the Window handle of Picture1.
          Picture1.SetFocus
          Pic1hWnd = GetFocus()
    
          ' Get the Window handle of Command1.
          Command1.SetFocus
          Command1hWnd = GetFocus()
    
          ' Restore the focus to the control with the input focus.
          r = PutFocus(CurrHwnd)
          timer1.interval = 1   ' One millisecond.
          timer1.enabled = -1
       End Sub
    
    

  6. Enter the following code in the Form_Unload event procedure of Form1:

       Sub Form_Unload (Cancel As Integer)
          ' Restore the custom cursors to the system cursor:
          LastCursor =SetClassWord(Form1.hWnd, GCW_HCURSOR, SysCursHandle)
          LastCursor = SetClassWord(Pic1hWnd, GCW_HCURSOR, SysCursHandle)
          LastCursor=SetClassWord(Command1hWnd, GCW_HCURSOR,SysCursHandle)
          FreeLibrary(DLLInstance)
       End Sub
    
    

  7. Enter the following code in the Timer1_Timer event procedure of Timer1:

       Sub Timer1_Timer ()
    
          ' Get the current (absolute) cursor position.
          Call GetCursorPos(p)
    
          ' Find out which control the midpoint of the cursor is over.
          ' The cursor is 32 x 32 pixels square. Change the class word
          ' of the control to the appropriate cursor.
          Select Case WindowFromPoint(p.y + 16, p.x + 16)
    
             Case Form1.hWnd
                LastCursor=SetClassWord(Form1.hWnd, GCW_HCURSOR, Curs2Handle)
                LastCursor=SetClassWord(Command1hWnd, GCW_HCURSOR, Curs2Handle)
                LastCursor=SetClassWord(Pic1hWnd, GCW_HCURSOR, Curs2Handle)
    
             Case Command1hWnd
                LastCursor=SetClassWord(Form1.hWnd, GCW_HCURSOR, Curs1Handle)
                LastCursor=SetClassWord(Command1hWnd, GCW_HCURSOR, Curs1Handle)
    
             Case Pic1hWnd
                LastCursor = SetClassWord(Form1.hWnd, GCW_HCURSOR, Curs1Handle)
                LastCursor = SetClassWord(Pic1hWnd%, GCW_HCURSOR, Curs1Handle)
          End Select
       End Sub
    
    

  8. Run the program. The form should receive the "Cursor2" cursor and the controls Command1 and Picture1 should receive the "Cursor1" cursor as the mouse cursor is moved about the form.


Additional reference words: 1.00 2.00 3.00
KBCategory: kbgraphic kbprg kbcode
KBSubcategory: APrgGrap APrgOther


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: June 21, 1995
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.