Programming Microsoft Outlook and Microsoft Exchange, Second Edition (DV-MPS Programming)
The last application we will look at is a CDO application built using Microsoft Visual Basic. This application allows users to log on to their Exchange Server using CDO, query the server for other users, and retrieve information about those users. This application shows you how to program CDO with Visual Basic, which is different from programming CDO with VBScript and ASP. This application also shows you how to use the AddressEntryFilter object. Figure 11-35 shows the application in action.
Figure 11-35 The Visual Basic CDO application.
Setting Up the Application
Before you can install the application, you must have a Windows NT 4.0 Server and a client with certain software installed. Table 11-5 describes the installation requirements.
Table 11-5 Installation Requirements for the CDO Visual Basic Application
Software Requirements | Installation Notes |
---|---|
Exchange Server 5.5 SP1 | |
CDO library (cdo.dll) | Exchange Server 5.5 SP1 installs CDO library 1.21. Outlook 98 installs CDO library 1.21. |
For the client: Outlook 98 |
To install the Visual Basic CDO application, run the Setup.exe file in the CDO VB folder on the companion CD and follow the instructions.
Programming CDO with Visual Basic
The main differences between programming CDO with VBScript and ASP and programming CDO with Visual Basic is that Visual Basic allows you to use early binding of objects in the CDO library. By declaring your variables as a specific type of object, the variables will be bound early. For example, in Visual Basic, you can use the Dim statement to declare a variable as a CDO Session object by using the following statement:
Dim oSession as MAPI.Session |
Once you declare a variable, you can take advantage of some of the powerful features of the Visual Basic development environment, such as Auto List Members, which lists the available properties and methods for an object, and Auto Quick Info, which displays the syntax for a statement. For example, if in the code window you start typing the name of the oSession variable and then the dot operator (.), Visual Basic will automatically display the properties and methods for the CDO Session object. Also, using early binding allows your application to execute faster. This is because the binding takes place at compile time rather than at run time. VBScript and ASP cannot use early binding and therefore always default to late binding when creating objects.
To use CDO in Visual Basic, add a reference to the CDO library. By adding this reference, you can declare variables of a specific CDO type in your code, and you make the CDO objects appear in the Visual Basic object browser. You use the object browser to view information about libraries, such as properties, methods, events, constants, classes, and other information.
To add the reference to the CDO library, in Visual Basic select References from the Project menu. Scroll down until you find Microsoft CDO 1.21 library, and add a check mark next to it. If you want to add a reference to the CDO Rendering library, add a check mark next to Collaborative Data Objects Rendering library 1.2, and click OK. Now you can take advantage of early binding with your CDO objects, and the CDO library will be available in the Visual Basic object browser. Most of the time, you will not use the CDO Rendering library in your client-based applications. Instead, you will use this library in your web-based applications.
Logging On the User
As we have discussed throughout this chapter, you cannot create any other objects in the CDO library without first creating a CDO Session object and successfully logging on with that Session object. Because we are developing a Visual Basic application, we do not have to worry about a Global.asa file or authenticating the user—CDO will leverage the Windows NT credentials of the user currently logged on. This makes logging on as a user much easier, as you can see in the following authenticated logon code:
Dim oRecipients As MAPI.Recipients Dim oRecipient As MAPI.Recipient Dim oInfoStores As MAPI.InfoStores Dim oInfoStore As MAPI.InfoStore Dim oInbox As MAPI.Folder Dim boolUseCurrentSession, boolLogonDialog Private Sub cmdLogon_Click() On Error Resume Next Err.Clear 'Check to see if user wants to use a current session. 'If so, piggyback on that session. If boolUseCurrentSession = 0 Then If (txtServerName.Text <> "") And _ (txtAliasName.Text <> "") Then strProfileInfo = txtServerName & vbLf & txtAliasName oSession.Logon NewSession:=True, NoMail:=False, _ showDialog:=boolLogonDialog, ProfileInfo:=strProfileInfo strConnectedServer = " to " & txtServerName.Text Else MsgBox "You need to enter a value in the " & _ "Server or Alias name.", _ vbOKOnly + vbExclamation, "CDO Logon" Exit Sub End If Else oSession.Logon NewSession:=False, showDialog:=boolLogonDialog strConnectedServer = "" End If If (Err.Number <> 0) Or _ (oSession.CurrentUser.Name = "Unknown") Then 'Not a good logon; log off and exit oSession.Logoff MsgBox "Logon error!", vbOKOnly + vbExclamation, "CDO Logon" Exit Sub End If 'Check store state to see if online or offline Set oInbox = oSession.Inbox strStoreID = oInbox.StoreID Set oInfoStore = oSession.GetInfoStore(strStoreID) If oInfoStore.Fields(&H6632000B).Value = True Then strConnectedServer = " Offline" End If 'Enable other buttons on the form cmdLogoff.Enabled = True cmdLogon.Enabled = False txtUserName.Enabled = True cmdSearch.Enabled = True cmdViewAB.Enabled = True lblUserName.Enabled = True 'Change the label to indicate status lblConnected.Caption = "Connected" & strConnectedServer _ & " as " & oSession.CurrentUser.Name End Sub |
To support early binding, a number of variables are declared as specific CDO object types. The code tries to log on to the Exchange Server by using the CDO Logon method. Unlike the ASP code we saw earlier, in this code we can leverage existing sessions between the client and the Exchange Server rather than always create new sessions. The user can enable this functionality by checking the Use Existing Exchange Session check box. (See Figure 11-35.) The existing session, typically an Outlook client session, is used by CDO to connect to the Exchange Server.
After the user logs on, the code finds the InfoStore object associated with the user's mailbox. The Fields collection on InfoStore is used to look up a specific property, PR_STORE_OFFLINE (&H 6632000B), which contains either True or False; True indicates that the current InfoStore is an offline replica. This value for this property is used in the status text, which indicates the connection state of the user, as shown in Figure 11-36.
Figure 11-36 If the user is working offline, the connection status message displays this information.
Finding the Details of the Specific User
After logging on, the user can type in a name in the User Name text box. The name entered is used by the application to search the directory or distribution list. The search is implemented by using the AddressEntryFilter object in the CDO library. The AddressEntryFilter object is very similar to the MessageFilter object, which we examined in the Calendar of Events application. The only difference between them is that the AddressEntryFilter object is used with objects in the directory, and the MessageFilter object is used with messages in a folder. Following is the code that searches for the user using the AddressEntryFilter object and displays the results:
Private Sub cmdSearch_Click() On Error Resume Next 'The On Error is to handle the user canceling the 'details dialog box Err.Clear If txtUserName.Text = "" Then MsgBox "No User Specified", vbOKOnly + vbExclamation, _ "User Search" Exit Sub Else Set oAddressList = oSession.GetAddressList(CdoAddressListGAL) Set oAddressEntries = oAddressList.AddressEntries Set oAddEntryFilter = oAddressEntries.Filter oAddEntryFilter.Name = txtUserName.Text If oAddressEntries.Count < 1 Then MsgBox "No entries found", vbOKOnly, "Search" ElseIf oAddressEntries.Count > 1 Then MsgBox "Ambiguous entries found", vbOKOnly, "Search" Else Set oAddressEntry = oAddressEntries.GetFirst oAddressEntry.Details End If End If End Sub |
This code gets the Global Address List, either offline or online, by using the GetAddressList method on the Session object. It then instantiates an AddressEntryFilter object by using the Filter property on the AddressEntries collection. To specify the condition for the filter, the Name property on the AddressEntryFilter object is set to the name typed in by the user. This name can either be the user's display name, such as Thomas Rizzo (Exchange), or the alias of the user, such as thomriz. CDO also supports direct matches when you place the equals (=) sign before your text, as in =Thomas Rizzo.
Once the filter is set, the code retrieves the count of the newly restricted AddressEntries collection to determine how many AddressEntry objects were returned. If more than one AddressEntry object was returned, the code displays an ambiguous name error to notify the user that more specific criteria is needed. If less than one AddressEntry object is returned, the code displays that no entries meet the criteria of the user. If exactly one AddressEntry object is returned, the code uses the Details method of the AddressEntry object to display the information about the directory object, as shown in Figure 11-37.
Figure 11-37 The details page of an AddressEntry object. You can see not only the name and alias of the user but also organizational information such as the manager of the user.
Finally, a subroutine is included to handle the run-time error thrown by CDO when the user clicks Cancel in the Properties dialog box displayed by the Details method.