In this chapter, I will cover some advanced CDO topics, such as working with property sets from Microsoft Outlook, and offer tips for working with CDO. I will also explain how to program against CDO from the Microsoft .NET environment.
We will look at an application built using Microsoft Visual Basic that allows users to log on to their Exchange servers using CDO, query the server for other users, and retrieve information about those users. This application shows how to program CDO with Visual Basic, which is different from programming CDO with VBScript and Microsoft Active Server Pages (ASP). It also shows how to use the AddressEntryFilter object. Figure 12-1 shows the application in action.
Before you can install the application, you must have a client with Outlook installed and a Microsoft Windows 2000 server with the following software installed:
Exchange Server 2000 or later (with the latest service pack recommended)
CDO library (cdo.dll)
To install the CDO Visual Basic application, run the Setup.exe file in the CDO VB folder (included with the book's companion content) and follow the instructions.
The main difference 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 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, you add a reference to the CDO library. You can then declare variables of a specific CDO type in your code, and the CDO objects will 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 choose 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. 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.
As you know, 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 don't have to worry about a Global.asa file or authenticating the user ”CDO uses the Windows NT credentials of the user who is currently logged on. This makes logging on much easier for users, 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 whether 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 whether 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 you saw earlier, in this code we can use existing sessions between the client and the Exchange server rather than always creating new sessions. The user can enable this functionality by selecting the Use Existing Exchange Session check box (as shown earlier in Figure 12-1). 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 ( &H6632000B ), which contains either True or False . True indicates that the current InfoStore is an offline replica. The value for this property is used in the status text, which indicates the connection state of the user, as shown in Figure 12-2.
After logging on, the user can type a name in the User Name text box. The application uses this name to search the directory or distribution list. The search is implemented by using the AddressEntryFilter object in the CDO library. This object is similar to the MessageFilter object, which we examined in the Calendar of Events application in Chapter 11. The only difference 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 by 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 (GAL), either off line or on line, 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 be either 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 equal 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 12-3. You can see not only the name and alias of the user but also organizational information, such as the user's manager.
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.