Chapter 12: Advanced CDO Topics and Tips
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.
The CDO Visual Basic Application
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.

Figure 12-1: The CDO Visual Basic application
Setting Up the Application
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.
Programming CDO with Visual Basic
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.
Logging On the User
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.

Figure 12-2: If the user is working off line, the connection status message will display this information.
Finding the Details of the Specific User
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 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.

Figure 12-3: The details page of an AddressEntry object
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.