Programming Microsoft Outlook and Microsoft Exchange, Second Edition (DV-MPS Programming)

[Previous] [Next]

Before we see an example of how to modify the Team Folders HTML pages, let's take a closer look at the Outlook View control. This control ships as part of the Team Folders Wizard, plus you can download it from Microsoft's Web site. The Team Folders Wizard provides a reference to the Internet location of the Outlook View control as part of the control's CodeBase property in the Team Folders HTML pages. For those of you who don't want to look at the Team Folders HTML pages, the location is http://activex.microsoft.com/activex/controls/office/outlctlx.cab.

You must install Outlook on your local machine before you can take advantage of the Outlook View control. This differs from the requirements for the Office Web Components, which only mandate that you have a license for Office 2000 on the local machine, not the actual Office application.

Programming the Outlook View Control

To take full advantage of the Outlook View control, you have to program it to meet your needs. This section highlights the most common methods and properties you can use with the View control. (For the full documentation for the Outlook View control, see the companion CD.) This section will also show you how to program the View control within HTML pages. You can also use and program the control in other ActiveX containers, such as Visual Basic or Outlook forms. The techniques for programming the View control in these other environments will be the same, except you won't need to instantiate the control using an <OBJECT> tag.

Instantiating the Outlook View Control

Before you can program the Outlook View control, you need to instantiate it. You can do this in one of two ways. You can use a tool such as Microsoft Visual InterDev to insert the control, which will provide the <OBJECT> tag needed to create the View control in your HTML application. Your other choice is to create the <OBJECT> tag for the Outlook View control yourself. The following <OBJECT> tag shows your Outlook calendar:

<OBJECT classid=CLSID:0006F063-0000-0000-C000-000000000046 codebase="http://activex.microsoft.com/activex/controls/office/ outlctlx.CAB#ver=9,0,0,3203" height="84%" id=oViewControl style="BORDER-BOTTOM: silver 1px solid" width="100%"> <PARAM NAME="View" VALUE=""> <PARAM NAME="Folder" VALUE="Calendar"> <PARAM NAME="Namespace" VALUE="MAPI"> <PARAM NAME="Restriction" VALUE=""> <PARAM NAME="DeferUpdate" VALUE="0"></OBJECT>

No matter which technique you use to create the Outlook View control, you need to understand the parameters that are passed to the control. Notice the ID for the control in this code. The text you specify for the ID (in this case, oViewControl) will dictate how you refer to the control in your code. The code also contains a number of parameters: View, Folder, Namespace, Restriction, and DeferUpdate. Each parameter corresponds to a property of the control that you can set either in the <OBJECT> tag or programmatically. These properties are important for applications that use the Outlook View control. (We're not going to discuss the Namespace property below since—let's face it—the only namespace that the View control supports is MAPI.) Let's take a look at the other properties now.

View Property

The View property specifies the Outlook view you want to use in the View control—for example, Messages, Messages with AutoPreview, and Day/Week/Month. How do you obtain the list of current views to display in the control? Unfortunately, the Outlook object model doesn't have a Views collection that you can retrieve from. Instead, there are two ways you can programmatically determine which views are in the folder to which the View control is pointing.

The first way, depicted in Figure 9-9, is to grab the list of views from the Current View control on the Outlook Advanced toolbar. To grab the list, you must automate Outlook using the Outlook object model in your application. Get a reference to the Outlook Application object, which you can easily do by using the OutlookApplication property of the View control.

Figure 9-9. Dynamically determining which views are available in a folder.

You can then use the ActiveExplorer property to retrieve the active Explorer object in Outlook. Next, you can use the Explorer object's CommandBars property to retrieve the Office CommandBars collection. From that collection, you can retrieve the Advanced CommandBar object. From that object in turn you can retrieve the current View control. You can now retrieve all the views from that control. In the following code sample, the views are added to a drop-down list in an HTML page. This allows you to force the Outlook View control on the Web page to change views depending on which view you select from the list by using the View property on the View control.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD> <META content="text/html; charset=unicode" http-equiv=Content-Type> <META content="MSHTML 5.00.2919.3800" name=GENERATOR></HEAD> <BODY> <P>This sample gets the custom views in the folder.</p> <P><SELECT id=select1 name=select1() onChange="ChangeView()" style="HEIGHT: 22px; WIDTH: 333px"></SELECT></P> <P> <OBJECT classid=clsid:0006F063-0000-0000-C000-000000000046 height="100%" id=OVCtl1 width="100%" VIEWASTEXT></OBJECT> <!-- By passing no parameters to the View control, you can make it display the default folder it's in --> <SCRIPT language="VBScript"> Set oApplication = OVCtl1.OutlookApplication Set oCurrentFolder = oApplication.activeExplorer.currentfolder set oFolder = oCurrentFolder strPath = strFullPath MsgBox "The Current Folder Path is: " & strPath OVCtl1.Folder = strPath Set oExplorer = oApplication.Explorers.Add(oFolder,0) Dim oAdvancedCB For each oCB in oExplorer.CommandBars if oCB.Name = "Advanced" then set oAdvancedCB = oCB exit for End If next set oCBCombo = oAdvancedCB.Controls("Current View") for x= 1 to oCBCombo.ListCount AddToSelect(oCBCombo.List(x)) next 'Set the default view for the control to the 'currently selected item in the drop-down list ChangeView() Sub AddtoSelect(strViewName) set oOption = document.createElement("OPTION") oOption.text=strViewName oOption.value=strViewName document.all.Select1.add(oOption) End Sub '****************************************************** 'Function StrFullPath() ' 'This function creates and returns the full path to the 'folder '****************************************************** Function StrFullPath() strFolderName = "" Set olRoot = oCurrentFolder While (olRoot <> "MAPI") strFolderName = oCurrentFolder.Name & "\" & strFolderName Set olRoot = oCurrentFolder.Parent If olRoot <> "MAPI" Then Set oCurrentFolder = oCurrentFolder.Parent End If Wend strFullPath = "\\" & strFolderName end Function Sub ChangeView() if select1.value <> "" then 'Change the View control view OVCtl1.View = select1.value End If End Sub 'Make sure to kill the Explorer or else 'Outlook will remain in memory! set oExplorer = Nothing </SCRIPT> </BODY></HTML>

The second way you can determine which views are contained in the folder is to use Collaboration Data Objects (CDO). One drawback of this technique is that although CDO can recognize the custom views in the folder, it cannot detect standard Outlook views such as the Messages view or the Messages with AutoPreview view. This is because Outlook stores custom views as hidden messages inside the folder while storing standard Outlook views in a central location. Therefore, CDO doesn't offer you a good way to determine the default view names unless you hard-code them into your application. As you'll see, you can determine whether the default views should be used in the folder.

The advantage of using CDO to detect views is that you can use this technique from Active Server Pages (ASP) or other non-Outlook applications and can detect what the default view is for the folder. Outlook provides no easy way to detect what the folder owner has set as the folder's default view. The only caveat for detecting the folder's default view is that this technique will work only in an online mode. If users are working with an offline version of your application, you won't be able to detect the default view for the folder.

The following example of an HTML page containing some CDO code shows the views contained in the folder:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD> <META content="text/html; charset=unicode" http-equiv=Content-Type> <META content="MSHTML 5.00.2919.3800" name=GENERATOR></HEAD> <BODY> <P>This sample gets the custom views in the folder. It first detects the type of items in the folder and then displays some default views for the type of folder as well as the custom views:</P> <P><SELECT idselect=1 name=select1 onChange="ChangeView()" style="HEIGHT: 22px; WIDTH: 333px"></SELECT></P> <P>The default view is currently: </P> <span id="defaultview"> </span> <P> <OBJECT classid=clsid:0006F063-0000-0000-C000-000000000046 height="100%" id=OVCtl1 width="100%" VIEWASTEXT><PARAM NAME="View" VALUE=""> <PARAM NAME="Folder" VALUE="inbox"> <PARAM NAME="Namespace" VALUE="MAPI"><PARAM NAME="Restriction" VALUE=""><PARAM NAME="DeferUpdate" VALUE="0"></OBJECT> <SCRIPT ID=clientEventHandlersVBS LANGUAGE=vbscript> '****************************************************** 'Inline code ' 'These lines of code are run when the browser reaches 'them when parsing the document. They set up the global 'variables that are needed throughout the application. '****************************************************** const ActMsgPR_IPM_PUBLIC_FOLDERS_ENTRYID = &H66310102 const ActMsgPR_STORE_ENTRYID = &H0FFB0102 const ActMsgPR_STORE_SUPPORT_MASK = &H340D0003 const ActMsgSTORE_PUBLIC_FOLDERS = &H00004000 const ActMsgPR_DEFAULT_ENTRYID = &H36160102 Set oApplication = OVCtl1.OutlookApplication Set oNS = oApplication.GetNamespace("MAPI") Set oCurrentFolder = oApplication.activeExplorer.currentfolder strPath = strFullPath OVCtl1.Folder = strPath 'Log on to CDO set oSession = oApplication.CreateObject("MAPI.Session") oSession.Logon "","",False,False 'Have Outlook get the EntryID for the folder set oCurrentFolder = OVCtl1.ActiveFolder strEntryID = oCurrentFolder.EntryID strStoreID = oCurrentFolder.StoreID 'Have CDO get the item 'You can try this code if EntryID, StoreID aren't working 'Set objStores = oSession.InfoStores 'For i = 1 to objStores.Count ' Set objStore = objStores.Item(i) ' szID = objStore.Fields.Item(ActMsgPR_IPM_PUBLIC_FOLDERS_ENTRYID) ' lMask = objStore.Fields.Item(ActMsgPR_STORE_SUPPORT_MASK) ' Err.Clear ' If lMask And ActMsgSTORE_PUBLIC_FOLDERS Then ' STORE_PUBLIC_FOLDERS ' strStoreID = objStore.ID ' End if 'Exit for 'Next set oFolder = oSession.GetFolder(strEntryID,strStoreID) On Error Resume Next 'Figure out the folder type from PR_CONTAINER_CLASS 'This application understands only mail folders strContainerClass = oFolder.Fields(&H3613001E).value 'Load up the default views for this content type If strContainerClass = "IPF.Note" Then AddtoSelect("Messages") AddtoSelect("Messages with AutoPreview") End If 'Load up the custom views…stored as hidden 'messages with MsgClass 'IPM.Microsoft.FolderDesign.NamedView 'Get the HiddenMessages collection Set oHiddenMsgs = oFolder.HiddenMessages 'Create a filter, but first clear it oHiddenMsgs.Filter = Nothing Set oFilter = oHiddenMsgs.Filter oFilter.Type = "IPM.Microsoft.FolderDesign.NamedView" 'Scroll through and add hidden messages For Each oHidden In oHiddenMsgs AddtoSelect(oHidden.Subject) Next 'Figure out the current default view for the folder 'This may fail if it's an Outlook normal view 'If a custom view, say what it is err.clear On Error Resume Next strViewEntryID = "" strViewEntryID = oFolder.Fields(ActMsgPR_DEFAULT_ENTRYID).Value If strViewEntryID = "" Then 'It's a standard Outlook view defaultview.innerHTML = "Built-in Outlook View" Else set oDefaultView = oSession.GetMessage(strViewEntryID,null) defaultview.innerhtml = oDefaultView.Subject End If Sub AddtoSelect(strViewName) set oOption = document.createElement("OPTION") oOption.text=strViewName oOption.value=strViewName document.all.Select1.add(oOption) End Sub '****************************************************** 'Function StrFullPath() ' 'This function creates and returns the full path to the 'folder '****************************************************** Function StrFullPath() strFolderName = "" Set olRoot = oCurrentFolder While (olRoot <> "Mapi") strFolderName = oCurrentFolder.Name & "\" & strFolderName Set olRoot = oCurrentFolder.Parent If olRoot <> "MAPI" Then Set oCurrentFolder = oCurrentFolder.Parent End If Wend strFullPath = "\\" & strFolderName End Function Sub ChangeView() If select1.value <> "" then 'Change the view control view OVCtl1.View = select1.value End If End Sub </SCRIPT> </BODY></HTML>

This code contains some important techniques. Contrary to what you might expect when you use CDO in a Web application, you won't receive an E_ACCESSDENIED error because CDO isn't allowed to be created by HTML client-side code. Why? Imagine you visit an Internet site and a malicious site administrator includes the call CreateObject("MAPI.Session"). He scrolls through your Outlook Inbox looking for passwords, credit card numbers, and so on. Then suppose that, posing as you, he sends an e-mail message containing a virus attachment to the addresses on your contacts list. This potential for security problems is why CDO is disabled in client-side HTML script.

Usually when developers need to use CDO, they wrap their CDO code in an ActiveX control that they sign and distribute. This works well for Internet applications; however, on intranet applications—specifically folder home pages in Outlook 2000—you don't want to create an ActiveX control just so that you can use CDO. Instead, you can use the CreateObject method of the Outlook Application object in the Outlook object model, which allows you to create the CDO object in your folder home page. Now before you start screaming security violation, note that this technique will not work if you run the HTML page outside Outlook, either on an intranet or the Internet. Since you're probably linking to trusted content in your folder home pages, you have nothing to worry about. Later in this chapter, you'll see some other ways Outlook locks down its object model when you run Outlook controls in other environments.

The code uses the MAPI property PR_CONTAINER_CLASS to determine the default item type in the folder. The code then uses the CDO MessageFilter object to search for all hidden messages in the folder that are of the message class IPM.Microsoft.FolderDesign.NamedView. Next, the code scrolls through each of these messages (each of which corresponds to a view) and adds the subject of the message (the name of the view) to the HTML page. Finally, the code uses the PR_DEFAULT_VIEW_ENTRYID property on the folder. This property contains the EntryID of the folder's default view. If the default view is an Outlook built-in view, this property will not contain any value.

Folder Property

The Folder property specifies which folder you want the View control to display in its interface. When you set this property, you need to pass in the path to the folder that you want to display. You might be wondering how you find the path to a folder. Unfortunately, Outlook doesn't provide a FolderPath property in its object model, meaning you must programmatically figure out the path for the folder at which you want to point the View control. You can do this easily by using the StrFullPath function listed in the previous code sample. This function generates the folder path by simply walking the folder hierarchy until it reaches the topmost Outlook folder.

If you leave blank the Folder property in an HTML application's <OBJECT> tag, the View control defaults to your Inbox. If you prefer to have the control default to the current folder that the user is looking at in Outlook, do not pass any parameters to the View control inside your folder home page. Be aware that this is a departure from what the View control documentation says to do.

Restriction Property

The Restriction property specifies the restriction on the items contained in the folder. This property takes the same format as the Restrict method in the Outlook object model. Be aware that when you use the equal sign in this property, Outlook performs a search for strings that contain the criteria you specified. If you want to obtain an exact match for a string, you need to use the "greater than, less than" format. The following example shows the difference between these two formats:

'Does a contains oVCtl1.Restriction = "[Subject] = 'Exchange'" 'Does an exact match oVCtl1.Restriction = "[Subject] <= 'Exchange' AND [Subject] >= 'Exchange'"

DeferUpdate Property

When set to True, the DeferUpdate property prevents the View control from displaying its contents until you reset the property to False. DeferUpdate is useful if you're dynamically modifying a folder's restriction or view; it prevents the user from seeing one set of items appear in the control and then suddenly disappear.

OpenSharedDefaultFolder Method

The OpenSharedDefaultFolder method allows you to open other user's folders, if you have permissions for those folders, inside the View control. Using this method along with multiple View controls on a single page, you could open up multiple calendars, task folders, or any other folders in your mailbox and other users' mailboxes for which you have permissions. OpenSharedDefaultFolder takes the name of the recipient's mailbox that you want to open and the folder type. Figure 9-10 shows how you can use the CDO address book with this method.

Figure 9-10. A sample application that shows how to use the CDO address book with the OpenSharedDefaultFolder method.

The following code allows you to select a user from the address book, and then adds a new View control to display that user's Calendar folder. This sample is limited to only three View controls, but you can add more in your code.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD> <META content="text/html; charset=unicode" http-equiv=Content-Type> <META content="MSHTML 5.00.2919.3800" name=GENERATOR></HEAD> <BODY> <P> This sample shows how you can use OpenSharedDefaultFolder: <BR><BR> <INPUT id=AddressBook name=AddBook type=button value="Address Book" nclick="ShowAddBook()"> </P> <SPAN ID=View1> <OBJECT classid=clsid:0006F063-0000-0000-C000-000000000046 height="100%" id=OVCtl1 width="30%" VIEWASTEXT><PARAM NAME="View" VALUE="">< PARAM NAME="Folder" VALUE=""><PARAM NAME="Namespace" VALUE="MAPI">< PARAM NAME="Restriction" VALUE=""><PARAM NAME="DeferUpdate" VALUE="0"></ OBJECT> </SPAN> <SPAN ID=View2> <OBJECT classid=clsid:0006F063-0000-0000-C000-000000000046 height="100%" id=OVCtl2 width="30%" VIEWASTEXT><PARAM NAME="View" VALUE="">< PARAM NAME="Folder" VALUE=""><PARAM NAME="Namespace" VALUE="MAPI">< PARAM NAME="Restriction" VALUE=""><PARAM NAME="DeferUpdate" VALUE="0"></ OBJECT> </SPAN> <SPAN ID=View3> <OBJECT classid=clsid:0006F063-0000-0000-C000-000000000046 height="100%" id=OVCtl3 width=30% VIEWASTEXT><PARAM NAME="View" VALUE="">< PARAM NAME="Folder" VALUE=""><PARAM NAME="Namespace" VALUE="MAPI"> <PARAM NAME="Restriction" VALUE=""><PARAM NAME="DeferUpdate" VALUE="0"></ OBJECT> </SPAN> <SCRIPT ID=clientEventHandlersVBS LANGUAGE=vbscript> '****************************************************** 'Inline code ' 'These lines of code are run when the browser reaches 'them when parsing the document. They set up the global 'variables that are needed throughout the application. '****************************************************** Set oApplication = window.external.OutlookApplication 'Log on to CDO 'Use CDO to pop up an Address book so that the person can select 'the user they want to open the calendar for Set oSession = oApplication.CreateObject("MAPI.Session") oSession.Logon "", "", False, False iNumFolders = 0 Sub ShowAddBook() On Error Resume Next 'to catch the cancel Set oRecips = oSession.AddressBook(, "Select a User", True, _ True, 1, "User") If oRecips.Count <> 0 Then On Error GoTo 0 strRecipName = oRecips.Item(1).Name If iNumFolders = 0 Then On Error Resume Next Err.Clear OVCtl1.OpenSharedDefaultFolder strRecipName, 9 If Err.Number = 0 Then 'Bump up the folder count iNumFolders = iNumFolders + 1 Else MsgBox "Error: " & Err.Number & " " & Err.Description End If ElseIf iNumFolders = 1 Then On Error Resume Next Err.Clear OVCtl2.OpenSharedDefaultFolder strRecipName, 9 If Err.Number = 0 Then 'Bump up the folder count iNumFolders = iNumFolders + 1 Else MsgBox "Error: " & Err.Number & " " & Err.Description End If ElseIf iNumFolders = 2 Then On Error Resume Next Err.Clear OVCtl3.OpenSharedDefaultFolder strRecipName, 9 If Err.Number = 0 Then 'Bump up the folder count iNumFolders = iNumFolders + 1 Else MsgBox "Error: " & Err.Number & " " & Err.Description End If Else MsgBox "No more view controls left!" End If End If End Sub </SCRIPT></P> </BODY></HTML>

Hosting the Outlook View Control in Internet Explorer

When you host the Outlook View control directly inside Internet Explorer, the functionality you can perform in the control's object model is locked down. For example, you can't access the Namespace object from the View control, and you can't use the CreateObject method of the Application object. You can, however, create items, delete items, or change views in the folder via the user interface of the View control. Remember, when you host the View control in Internet Explorer, only the object model is locked down. Figure 9-11 and the following code show what happens when you attempt to perform restricted methods while hosting the View control in Internet Explorer.

Figure 9-11. Hosting the View control in Internet Explorer restricts the methods you can use with the control. Notice the errors you receive when attempting certain actions.

<p>This sample shows how View controls are locked down in Internet Explorer: <BR><BR> Trying to get the Namespace object <LABEL ID=NameErr></LABEL> <BR><BR> Trying to create an object <LABEL ID=ObjErr></LABEL> </P> <OBJECT CLASSID="clsid:0006F063-0000-0000-C000- 000000000046" id=OVCtl1 VIEWASTEXT width=100% height=100%> <param name="View" value> <param name="Folder" value="inbox"> <param name="Namespace" value="MAPI"> <param name="Restriction" value> <param name="DeferUpdate" value="0"> </OBJECT> <SCRIPT defer for=window event=onload ID=clientEventHandlersVBS LANGUAGE=vbscript> '****************************************************** 'Inline code ' 'These lines of code are run when the browser reaches 'them when parsing the document. They set up the global 'variables that are needed throughout the application. '****************************************************** On Error Resume Next Set oApplication = OVCtl1.OutlookApplication err.clear 'Try to get Namespace Set oNS = oApplication.GetNamespace("MAPI") document.all.NameErr.innerHTML = "<BR>" & err.number & " " & _ err.description err.clear 'Try creating an object Set oSession = oApplication.CreateObject("CDO.Session") document.all.ObjErr.innerHTML = "<BR>" & err.number & " " & err.description </SCRIPT>

Категории