It's time now for some real examples. The rest of this chapter will look at some actual examples of API calls being used. Before jumping into the individual examples, however, look again at the API declarations used for all of them, merely for your convenience and to refresh them in your mind (see Listing 15.2). These can be found in the module modWindowsAPIRoutines, in Chap15.mdb.
The first example will use the FindExecutable() API routine. This function is useful when you want to let users choose between different file types to open. Rather than hard-code which application to use, you can check to make sure that it's associated with an application.
The form used for this example, FindExecutableExample, is located in Chap15.mdb in the ExamplesChap15 folder on the CD-ROM. The form consists of a combo box named cboFileToFindExe, a text box named txtExecutablePath, and a command button named cmdOpenApplication.
cboFileToFileExe is interesting in itself because it uses a function to populate itself. This function, ListFiles(), is placed in the combo box's Row Source Type property (see Figure 15.5). Listing 15.3 shows the code used in the ListFiles() function.
The ListFiles() function is standard for populating a combo box programmatically. The combo box is used to place all the filenames in the current folder in the astrFiles array.
When the combo box is populated, users can choose a file to examine from the list. When they do, the AfterUpdate event of the combo box has an event attached to it that uses the FindExecutable() API function to locate the executable application for the file, if one exists. Listing 15.4 shows the code for the cboFileToFindExe_AfterUpdate sub.
Private Sub cboFileToFindExe_AfterUpdate() Dim strFileName As String Dim lngReturnVal '-- Set up the string buffer used for the actual return value. Dim EXEPath As String EXEPath = String$(255, 0) '-- Actual API Call lngReturnVal = wu_FindExecutable(Me!cboFileToFindExe, _ strAppPath, EXEPath) If lngReturnVal > 32 Then Me!txtExecutablePath = Left(EXEPath, InStr(1, EXEPath, Chr(0)) - 1) '-- Greater then 32 means an exe has been found. Else Me!txtExecutablePath = "Not Associated with an Application" End If End Sub |
Here are a couple of main points about the cboFileToFindExe_AfterUpdate routine:
The following lines are quite common for setting up strings used to return a string value from an API call:
'-- Set up the string buffer used for the actual return value. Dim EXEPath As String EXEPath = String$(255, 0)
Note
You have to pad out a string to a maximum fixed length because API calls can't deal with Access variable-length strings. The API call can't expand a string, so you need to make it the maximum size possible.
In the following code lines, Me!cboFileToFindExe is the combo box value that's a filename, strAppPath is the path of the application that was retrieved in the ListFiles() function, and EXEPath is the return buffer set up earlier in the function:
'-- Actual API Call lngReturnVal = wu_FindExecutable(Me!cboFileToFindExe, _ strAppPath, EXEPath)
The last line trims off the Null value that's placed the end of a string retrieved from the API call:
Me!txtExecutablePath = Left(EXEPath, InStr(1, _ EXEPath, Chr(0)) - 1)
Figure 15.6 shows the form just after it looks up the executable for Win32api.txt.
The other interesting code takes the executable path that was stored in txtExecutablePath and uses Shell() to start the application, opening the file chosen in the cboFileToFindExe combo box. The code, shown in Listing 15.5, is attached to the cmdOpenApplication command button on the OnClick event.
Private Sub cmdOpenApplication_Click() Dim lngReturnVal As Long '-- Test to make sure a file has been chosen If IsNull(Me!cboFileToFindExe) Then MsgBox "No File Chosen!" Exit Sub End If '-- Make sure an application is associated If Me!txtExecutablePath = "Not Associated with an Application" Then MsgBox "This file has no application associated with it!" Exit Sub End If '-- Call the shell command lngReturnVal = Shell(Me!txtExecutablePath & " " & strAppPath & _ Me!cboFileToFindExe, 3) End Sub |
This code can be useful when used in an environment that you don't know which applications will be needed. Other useful routines are those that can help with handling the network from within Access.
Being able to manipulate the network from within your application gives you just that much more power, so you won't have to rely on outside applications to help control the environment.Two ways to do that are demonstrated in the following sections for both connecting and disconnecting network drives:
Programmatically connecting and disconnecting network drives directly
By calling the standard dialogs to connect and disconnect the network drives
The following API declarations—WNetAddConnectionA and WNetCancelConnectionA—are dealt with in this section:
Declare Function wu_NetAddConnection Lib "mpr" Alias _ "WNetAddConnectionA" (ByVal NetPath$, ByVal Password$, _ ByVal LocalDrive$) As Integer Declare Function wu_NetCancelConnection Lib "mpr" Alias _ "WNetCancelConnectionA" (ByVal NetPath$, ByVal FileForce%) _ As Integer
The form used for this example is named—aptly enough—ConnectAndDisconnectDriveExample. In Figure 15.7, see what Explorer shows for existing drive connections.
Open the ConnectAndDisconnectDriveExample form. Next, fill in the Server Path to Connect text box, which is also called txtPathToConnect. Also fill in the Drive to Connect text box, which is also called txtDriveToConnect. You can see the resulting text in the form in Figure 15.8.
Click the command button labeled Connect New Drive, otherwise known as cmdConnectNewDrive. If the connection is successful, you'll see a message saying so; if not, you'll see an error message. After the connection, Explorer should look like Figure 15.9.
The actual code to perform this magic is a little more than a dozen lines (see Listing 15.6). The tough one is performed with one API call. The routine, cmdConnectNewDrive_Click, is attached to the command button cmdConnectNewDrive.
Private Sub cmdConnectNewDrive_Click() Dim lngResult As Long '-- Make sure both fields are there. If IsNull(Me!txtPathToConnect) Or IsNull(Me!txtDriveToConnect) Then MsgBox "Please supply both a path and a drive!" Exit Sub End If '-- Attempt the connection lngResult = wu_NetAddConnection(Me!txtPathToConnect, "", _ Me!txtDriveToConnect) If lngResult = 0 Then MsgBox "Drive connected successfully!" Else MsgBox "Error occurred!" End If End Sub |
As you can see, the workhorse is the line that reads
lngResult = wu_NetAddConnection(Me!txtPathToConnect, "", _ Me!txtDriveToConnect)
This routine takes the path and the drive to connect. (The empty quotation marks in the middle are for a password, if required.)
The last part of this example disconnects the drive specified in txtDriveToConnect. The interesting part of this code is it tries to disconnect gently first. This means that if any files are still open, the disconnection will fail.
The routine then brings back a message box, asking whether the user wants to strong-arm the file(s) and force the closing. The code is attached to the OnClick event of the cmdDisconnect command button and is shown in Listing 15.7.
Private Sub cmdDisconnect_Click() Dim lngResult As Long '-- Try a gentle disconnect first If wu_NetCancelConnection(Me!txtDriveToConnect, 0) <> 0 Then Beep If MsgBox("The Connection could not be disconnected, " & _ "this is probably because you have files open on this drive." _ & vbCrLf & vbCrLf & "Do you want to force the disconnection" _ & " with a possible loss of data?", 20, "Disconnect Error") = 6 Then '-- If permission was granted, then force the disconnect lngResult = wu_NetCancelConnection(Me!txtDriveToConnect, 1) Else '-- If no, then leave Exit Sub End If End If MsgBox "Drive disconnected successfully!" End Sub |
The idea behind these routines is to use them when you don't want to have user intervention. They're used on a form here, but can be called without users even knowing about them. Generally, if you want users to supply the paths, you can just call the standard dialogs.
By calling the standard network dialogs, users have a familiar way to choose network drives and paths in which to create connections. The routines to call the functions WNetConnectionDialog and WNetDisconnectDialog are very straightforward to call, but require some arguments to be passed. You might not want to have to deal with these arguments each time you call because they have no real effect and don't change when you call them. When this is the case, you can call them from other routines.
Note
Routines such as these are sometimes called wrappers, because they're wrapped around the function and set up variables within them. You can then call them fairly easily from anywhere in the application.
To simplify things even further, however, I've created some wrappers for the API calls. The declarations for the two routines are as follows:
Declare Function wu_WNetConnectionDialog Lib "mpr" Alias _ "WNetConnectionDialog" (ByVal hwnd As Long, ByVal dwType As Long) _ As Long Declare Function wu_WNetDisconnectDialog Lib "mpr" Alias _ "WNetDisconnectDialog" (ByVal hwnd As Long, _ ByVal dwType As Long) As Long
The form used for these examples is ConnectAndDisconnectDialogsExample. Figure 15.10 shows this form with the connect dialog (Map Network Drive) displayed by clicking the command button labeled Call Network Connect Dialog.
The wrapper functions used—ap_CallNetworkConnectDialog() and ap_CallNetworkDisconnectDialog()—are placed in the OnClick event of each of the command buttons. Listing 15.8 shows the code for p_CallNetworkConnectDialog().
Public Function ap_CallNetworkConnectDialog() Dim lngDummy As Long Dim lngHWind As Long lngDummy = wu_WNetConnectionDialog(lngHWind, 1) End Function |
Pretty extensive, isn't it? As mentioned before, this call doesn't even necessarily require a wrapper function. The function ap_CallNetworkDisconnectDialog() isn't really any more difficult, as you can see in Listing 15.9.
Function ap_CallNetworkDisconnectDialog() Dim lngDummy As Long Dim lngHWind As Long lngDummy = wu_WNetDisconnectDialog(lngHWind, 1) End Function |
Note
The return value of both API calls isn't used for these examples. If successful in their tasks, the routines return a 0; anything else means that a problem occurred or Cancel was chosen. Different values are returned for various situations, and you'll need to play with them to determine which to trap.
Figure 15.11 shows the dialog that's brought up by clicking the Call Network Disconnect Dialog button.
There are additional networking API calls as well. The examples shown here have proven to be the most valuable to me. Another set of valuable routines is discussed in the next section.
The next two API routines, GetUserNameA and GetComputerNameA, return the current user and computer name. Here are the declarations for these routines:
Declare Function wu_GetUserName Lib "advapi32.dll" Alias "GetUserNameA" _ (ByVal lpBuffer As String, nSize As Long) As Long Declare Function wu_GetComputerName Lib "kernel32" Alias _ "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long
These routines come in handy for creating a logon screen for your application that automatically polls who the user is from the system. You can then pass the information on when dealing with ODBC queries, as well as when dealing with Access's own security.
The form, GetUserAndComputerNameExample, is located in the Chap15.mdb database. It has two text boxes, txtUserName and txtComputerName. As you can see in Figure 15.12, the actual API calls are called from within other wrapper functions.
Listing 15.10 shows the code for ap_GetUserName().
Function ap_GetUserName() As Variant Dim strUserName As String Dim lngLength As Long Dim lngResult As Long '-- Set up the buffer strUserName = String$(255, 0) lngLength = 255 '-- Make the call lngResult = wu_GetUserName(strUserName, lngLength) '-- Assign the value ap_GetUserName = strUserName End Function |
Pretty tough, huh? The code for ap_GetComputerName() is about as “hard,” as Listing 15.11 shows.
Function ap_GetComputerName() As Variant Dim strComputerName As String Dim lngLength As Long Dim lngResult As Long '-- Set up buffer. strComputerName = String$(255, 0) lngLength = 255 '-- Make the call. lngResult = wu_GetComputerName(strComputerName, lngLength) '-- Clean up and assign the value. ap_GetComputerName = Left(strComputerName, InStr(1, strComputerName, _ Chr(0)) - 1) End Function |
That's all there is to it. Figure 15.13 shows the form in Run mode, with the user and computer name showing.
The next set of API calls displays additional information about the computer you're using. These calls display various paths of the three most important folders used by most Windows setups:
Windows folder
Windows System folder
Temp folder
18.220.126.5