Visual Basic

Removing Declare Statements

We generally prefix Windows API calls with Win to show that the routine being called is in Windows, that it's an API call. You've also seen how to make these calls using Alias within the declaration of the routine. (Alias allows you to rename routines.) Here BringWindowToTop is being renamed WinBringWindowToTop:

Declare Function WinBringWindowToTop Lib "user32" _
     Alias "BringWindowToTop" (ByVal hwnd As Long) As Long

However, we could use a type library to do the same thing. Here's an entire type library used to do just that:


' The machine name for a type library is a GUID.
 library APILibrary
     module APILibrary
         [entry("BringWindowToTop")] long stdcall
             WinBringWindowToTop([in] long hWnd);


apilib.tlb : apilib.odl makefile
     mktyplib /win32 apilib.odl

The MAKEFILE is used to create the TLB file given the ODL file source code. To run MAKEFILE, invoke NMAKE.EXE. If you don't have NMAKE.EXE, simply run MKTYPLIB.EXE from a command prompt like this:

mktyplib /win32 apilib.odl

The type library contains a description of an interface in APILibrary named WinBringWindowToTop. Once you have compiled the library, run Visual Basic and select References from the Project menu. Click the Browse button in the References dialog box to find the APILIB.TLB file, and then select it, as shown in Figure 7-3.

Figure 7-3 Selecting APILibrary (APILIB.TLB) in the References dialog box

Click OK and press F2 to bring up Visual Basic's Object Browser, which is shown in Figure 7-4:

Figure 7-4 APILibrary displayed in the Object Browser

In Figure 7-4, notice that the method WinBringWindowToTop seems to be defined in a module and a server, both named APILibrary. Notice also that we have access to the syntax of the method. (The Quick Info help in Visual Basic will also display correctly for this method.) To use the method (which is really a function in USER32.DLL), all we have to do is enter code. No DLL declaration is now required (and so none can be entered incorrectly).

Call WinBringWindowToTop(frmMainForm.hWnd)

Another useful addition to a type library is named constants. Here's a modified APILIB.ODL:

 library APILibrary
     module WindowsFunctions
         [entry("BringWindowToTop")] long stdcall
             WinBringWindowToTop([in] long hWnd);
         [entry("ShowWindow")] long stdcall
             WinShowWindow([in] long hwnd, [in] long nCmdShow);
         ("WinShowWindow Constants - See SDK ShowWindow for more.")
         [helpstring("Hides the window, activates another")]
             SW_HIDE = 0,
         [helpstring("Maximizes the window")]
             SW_MAXIMIZE = 3,
         [helpstring("Minimizes the window activates next window")]
             SW_MINIMIZE = 6,
         [helpstring("Activates the window")]
             SW_RESTORE = 9,
         [helpstring("Activates/displays (current size and pos)" )]
             SW_SHOW = 5,
         [helpstring("Sets window state based on the SW_ flag")]
             SW_SHOWDEFAULT = 10,
         [helpstring("Activates window - displays maximized")]
             SW_SHOWMAXIMIZED = 3,
         [helpstring("Activates window - displays minimized")]
             SW_SHOWMINIMIZED = 2,
         [helpstring("Displays  window minimized")]
             SW_SHOWMINNOACTIVE = 7,
         [helpstring("Displays  window to current state.")]
             SW_SHOWNA = 8,
         [helpstring("Displays  window (current size and pos)")]
             SW_SHOWNOACTIVATE = 4,
         [helpstring("Activates and displays window")]
             SW_SHOWNORMAL = 1,
     } WinShowWindowConstants;

The library (APILibrary) now contains two sections, WindowsFunctions and WinShowWindowConstants, as shown in Figure 7-5.

Figure 7-5 APILibrary with named constants displayed in the Object Browser

The long numbers [uuid(9ca45f20-6710-11d0-9d65-00a024154cf1)] used in the ODL file are Globally Unique IDs (GUIDs). (See Chapter 1, for more detailed information on GUIDs.) Just for your interest, here's a small Visual Basic program that'll generate GUIDs for you. No matter how many times you run this program (which outputs a GUID for each button click), it will never produce the same GUID twice!

Declaration Section

 Option Explicit
 Private Type GUID
     D1       As Long
     D2       As Integer
     D3       As Integer
     D4(8)    As Byte
 End Type
 Private Declare Function WinCoCreateGuid Lib "OLE32.DLL" _
     Alias "CoCreateGuid" (g As GUID) As Long


Public Function CreateGUID() As String
     Dim g          As GUID
     Dim sBuffer    As String
     Dim nLoop As Integer
     Call WinCoCreateGuid(g)
     sBuffer = PadRight0(sBuffer, Hex$(g.D1), 8, True)
     sBuffer = PadRight0(sBuffer, Hex$(g.D2), 4, True)
     sBuffer = PadRight0(sBuffer, Hex$(g.D3), 4, True)
     sBuffer = PadRight0(sBuffer, Hex$(g.D4(0)), 2)
     sBuffer = PadRight0(sBuffer, Hex$(g.D4(1)), 2, True)
     sBuffer = PadRight0(sBuffer, Hex$(g.D4(2)), 2)
     sBuffer = PadRight0(sBuffer, Hex$(g.D4(3)), 2)
     sBuffer = PadRight0(sBuffer, Hex$(g.D4(4)), 2)
     sBuffer = PadRight0(sBuffer, Hex$(g.D4(5)), 2)
     sBuffer = PadRight0(sBuffer, Hex$(g.D4(6)), 2)
     sBuffer = PadRight0(sBuffer, Hex$(g.D4(7)), 2)
     CreateGUID = sBuffer
 End Function


Public Function PadRight0( _
                           ByVal sBuffer As String _
                          ,ByVal sBit As String _
                          ,ByVal nLenRequired As Integer _
                          ,Optional bHyp As Boolean _
                          ) As String
     PadRight0 = sBuffer & _
                 sBit & _
                 String$(Abs(nLenRequired - Len(sBit)), "0") & _
                 IIf(bHyp = True, "-", "")
 End Function

Command1 Click Event Handler

Private Sub Command1_Click()
     Print CreateGUID
 End Sub

Notice that the optional Boolean argument in PadRight0 is set to False if it is missing in Visual Basic 6 (as it was in 5); that is, it is never actually missing. (See IsMissing in the Visual Basic 6 online help.) In Visual Basic 6, an optional argument typed as anything other than Variant is never missing. An Integer is set to 0, a String to "", a Boolean to False, and so on. Bear this in mind if you really need to know whether or not the argument was passed. If you do, you'll need to use Optional Thing As Variant and IsMissing. Even in Visual Basic 4 an object is never really missing; rather, it is set to be of type vbError (as in VarType will yield 10). I've no idea what the error's value is.

In Chapter 1, I mentioned using object instances as constants and referenced this chapter for the code. Well, here it is along with some explanation.

In Visual Basic you cannot initialize a constant from a variable expression. The Help file in Visual Basic 6 says, "You can't use variables, user-defined functions, or intrinsic Visual Basic functions, such as Chr, in expressions assigned to constants." In other words, the value of the constant must be derivable by the compiler at compile time. In Chapter 1, I wanted to use a constant to hold a value returned from the Windows API, like this:

vbObjectiSingle  = WinGlobalAddAtom(CreateGUID)

I said that the object type of vbObjectiSingle was a constant Smartie type. That said, here's the code.…