Using variable argument types in API calls from Visual Basic


This page shows how to use a variable argument type with API calls from Visual Basic.

Example code

The example below clips and unclips the mouse cursor to a specific screen area.

Using the any type in API calls:
' Declarations

Public Type RECT
  Left As Long
  Top As Long
  Right As Long
  Bottom As Long
End Type

Private Declare Function ClipCursor Lib "user32" (lpRect As Any) As Long

'This is the alternative declaration:
'Private Declare Function MakeTheCursorClip Lib "user32" _
'  Alias "ClipCursor" (lpRect As RECT) As Long
'Private Declare Function UpClipTheCursor Lib "user32" _
'  Alias "ClipCursor" (ByVal ThisShouldBeZero As Long) As Long

Private Declare Function timeGetTime Lib "winmm.dll" () As Long

' Clip the mouse

Public Sub ClipMouse(Left As Long, Top As Long, _
                     Right As Long, Bottom As Long)
  Dim rctClip As RECT

  rctClip.Left = Left
  rctClip.Top = Top
  rctClip.Right = Right
  rctClip.Bottom = Bottom

  If ClipCursor(rctClip) = 0 Then _
    Err.Raise 12345, "MouseIO", "Could not clip cursor!"
End Sub

Public Sub UnClipMouse()
  If ClipCursor(ByVal 0&) = 0 Then _
    Err.Raise 12345, "MouseIO", "Could not un clip cursor!"
End Sub

' Pausing without freezing

Public Sub Wait(TimeOut As Long)
  Dim TimeNow As Long
  TimeNow = timeGetTime()

  Loop While TimeNow + TimeOut > timeGetTime()
End Sub

' Main

Public Sub Main()
  Call ClipMouse(20,20,400,400)

  Debug.Print "The mouse will be clipped for 4 seconds"
  Wait 4000

  Call UnClipMouse
  Debug.Print "Everything is back to normal"
End Sub

The ClipCursor() API accepts one parameter; the location (address) of your RECT buffer in the system memory. This is called "a pointer to a RECT" in C programming.

Supplying a pointer is exactly what Visual Basic does with it's ByRef keyword. The language doesn't allow programmers to supply a "null-location" (also called "null pointer"), as required by the ClipCursor() API. A null pointer indicates there is no reference to a memory location at all. Using the statement ByVal 0&, you can pass a long value of 0 to the function.

The ClipCursor() function expects a "null" location to unset the clipping area. This problem can be solved with the As Any declaration. Using this keyword, Visual Basic no longer performs certain checks on the API function call, and allows you to use free-form values.

There is also an alternative solution to this problem. It's possible to declare two API functions with different names, using the "alias" keyword. Both of names refer to the same API, but have a different argument list. This is shown in the example above.

There is one problem with the As Any declaration, Visual Basic can no longer perform it's magic on the parameters (or at a very late moment).

blog comments powered by Disqus