Access Cookbook - Ken Getz [230]
Discussion
The ClipCursor API routine (aliased as acb_apiClipCursor in the code) expects as its only parameter a user-defined data type consisting of four long integers representing coordinates of a rectangle. This data type has been declared for you in basClipCursor as acb_tagRect. This is a common data structure, used often with API routines that interact with the screen or printer. It is defined as follows:
Type acb_tagRect
lngLeft As Long
lngTop As Long
lngRight As Long
lngBottom As Long
End Type
When you want to restrict mouse movement, you'll need to retrieve the coordinates of the current form. You can accomplish this by calling the GetWindowRect API function (aliased as acb_apiGetWindowRect in the code), which will fill in an acb_tagRect structure with the left, top, right, and bottom coordinates of the window whose handle you pass it. Therefore, by calling acb_apiGetWindowRect with the handle of the current form, you'll retrieve the coordinates of that form in pixels:
Dim typRect as acb_tagRect
Call acb_apiGetWindowRect (Me.hWnd, typRect)
Once you've got a structure containing the coordinates of the current form, you can call ClipCursor and pass that filled-in structure to it. The sample form combines these API calls, as shown here:
Private Sub cmdClip_Click( )
Dim typRect As acb_tagRect
Static sstrCaption As String
' Static variable to keep track of clipping
Static blnClip As Boolean
If blnClip Then
Me.cmdClip.Caption = sstrCaption
Call acb_apiClipCursor(ByVal vbNullString)
Else
sstrCaption = Me.cmdClip.Caption
Me.cmdClip.Caption = "Free the Mouse!"
Call acb_apiGetWindowRect(Me.hWnd, typRect)
Call acb_apiClipCursor(typRect)
End If
blnClip = Not blnClip
End Sub
In the sample routine, which is executed each time you click the large button on frmClip, blnClip alternates between True and False, keeping track of whether mouse clipping is currently in effect. If it is, the routine calls acb_apiClipCursor to disable clipping and resets the button's caption. If clipping is not in effect, the routine stores away the original caption, sets a new one ("Free the Mouse!"), retrieves the form's coordinates, and finally calls acb_apiClipCursor to restrict the cursor's movement.
To end the mouse-cursor restrictions, send a null value to acb_apiClipCursor. To do that, pass the vbNullString intrinsic constant by value. Because the acb_apiClipCursor procedure has been declared to accept any type of parameter, you can send it a structure in one call and a null value in another.
The method presented in this solution is not foolproof in Access. You're taking control of a feature that Access normally controls itself, and sometimes the interaction may be unpredictable. In this case, if you restrict the mouse movement to a single form, but then use the mouse to move or resize the form, Access will free the mouse for you. Therefore, if you want to force users to stay on a single form, you're better off using a modal form instead. If, on the other hand, you're just trying to ensure that the mouse remains in the area of the form where the users need it to be, the method described here is appropriate. Restricting the mouse movement is not meant for every application, but if you want to help your users out a little, try it.
11.5. Run Another Program and Pause Until It's Done
Problem
From within your application, you sometimes need to run another Windows application, or a DOS batch file or utility program that requires some time to do its job. You'd like your Access application to pause until this other program has finished its work. Every time you try it, though, the code starts up the other application but then keeps on going. Is there a way to make Access wait until the other application has completed before moving on?
Solution
The Shell function in VBA (and the ShellExecute function we will mention in the Solution in Recipe 11.7) returns a unique long integer value representing the running task. You can use this value—the instance handle for the running application