|
The CDO Rendering library 1.x (CDOHTML.DLL) is used with Microsoft Active Server Pages applications (e. g. Microsoft Outlook Web Access). Note that the documentation states that it is possible to use it in e. g. Microsoft Visual Basic applications. Unfortunately this is not possible to use it in a Microsoft Visual Basic application. There is a Microsoft Knowledge Base article CDO Rendering library Not Available Outside of ASP describing this behavior. For more information, please take a look at Knowledge Base Articles about CDO & Scripting and Routing.
The CDO Rendering library 1.x includes a rendering application object to provide a framework for the Microsoft Active Server Pages application. You can set options on this rendering application object that are inherited by all rendering objects created by the CreateRenderer method. The rendering application object also provides methods for event logging and performance monitoring. A rendering application object is considered a top-level object, meaning it can be created directly from a Microsoft Visual Basic Scripting Edition application.
A user's access to Microsoft Exchange Server information is handled in a thread of execution within the Microsoft Internet Information Server process. If the user wants authenticated access, to open a mailbox for example, this thread must impersonate a Microsoft Windows NT security context. In other words, to be granted authenticated access to the Microsoft Exchange information store, a thread must be associated with a set of valid security credentials.
At the time the Microsoft Active Server Pages application is started the CDO HTML Rendering library application should be instantiated. The following code snippet creates a rendering application object and stores it into an application variable. Note that you cannot use early binding in Microsoft Visual Basic Scripting Edition:
| Dim objRenderApplication Set objRenderApplication = Server.CreateObject ("AMHTML.Application") If Err.Number = 0 Then Set Application("RenderingApplication") = objRenderApplication End If |
This code is normally placed in the Application_OnStart event of the GLOBAL.ASA Microsoft Active Server Pages application configuration file.
The rendering application provides access to configuration information from different sources. The following table shows the possible source values:
| Constant | Value | Description |
|---|---|---|
| CdoConfigRegistry | 1 | The standard registry key name for the CDO Rendering library 1.x |
| CdoConfigDS | 2 | The Microsoft Exchange directory server |
At the time the Microsoft Active Server Page session starts, create a MAPI.Session and log the user on using authenticated access, as shown in the following code:
| Set objSession =
Server.CreateObject("MAPI.Session") Set objRenderApplication = Application( "RenderingApplication" ) strProfileInfo = strServer + vbLF + strMailbox objSession.Logon "", "", False, True, 0, True, strProfileInfo Err.Clear Set objInboxFolder = objSession.Inbox If Err.Number <> 0 Then objSession.Logoff Else Session("hImp") = objRenderApplication.ImpID End If |
This code is normally placed in the Session_OnStart event of the GLOBAL.ASA Microsoft Active Server Pages application configuration file.
Note that it is necessary to open an information store at least once after the logon, because the logon method of the session does not return an error if you do not have permissions to logon to the particular mailbox. You need to force an information store open to ensure that you have the appropriate permissions. This is a known behaviour. For more information, please take a look at the Knowledge Base Articles about CDO & Scripting and Routing.
When rendering a page, or as a session is ending (such as in the method Session_onEnd in the file Global.asa), retrieve the saved security context handle from the Session object like the following code shows:
| hImp = Session("hImp") |
Get the RenderingApplication object, as shown in the following code:
| Set objRenderApplication = Application("RenderingApplication") |
If the session already timed out the session variable with the saved security context is empty. So you need to check if the session is not already timed out, as shown in the following code:
| If Not IsEmpty(hImp) Then objRenderApplication.Impersonate(hImp) End If |
Destroy all objects and close the MAPI.Session to make sure nothing is left over on the Microsoft Internet Information Server, as shown in the following code:
| Set objSession = Session("CDOSession") If Not objSession Is Nothing Then Set Session("CDOSession") = Nothing objSession.Logoff Set objSession = Nothing objRenderApplication.Impersonate(0) End If |
This code is normally placed in the Session_OnEnd event of the GLOBAL.ASA Microsoft Active Server Pages application configuration file. By ignoring this important part a crash of Microsoft Internet Information will occur, maybe not immediately but it'll happen because the resources used in your Microsoft Active Server Pages application are not freed up from memory.
When the Microsoft Active Server Pages application terminates you must close the CD HTML rendering application, as the following code shows:
| Set objRenderApplication =
Application("RenderingApplication") hImp = Session("hImp") If Not IsEmpty(hImp) Then fRevert = objRenderApplication.Impersonate(hImp) End If If (fRevert) Then Session("hImp") = Empty objRenderApplication.CloseSysHandle(hImp) objRenderApplication.Impersonate(0) End If |
This code is normally placed in the Application_OnEnd event of the GLOBAL.ASA Microsoft Active Server Pages application configuration file. By ignoring this important part a crash of Microsoft Internet Information will occur, maybe not immediately but it'll happen because the resources used in your Microsoft Active Server Pages application are not freed up from memory.
The following code snippet shows how to access the Microsoft Exchange configuration parameters (which are including the Microsoft Exchange Organization, Site and Server name) from the Microsoft Windows NT registry of the local machine:
| Dim intSource Dim strSection intSource = 1 strSection = _ "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\MSExchangeWeb\Parameters" objRenderApplication.LoadConfiguration intSource, strSection |
The following code snippet shows how to access the Microsoft Exchange directory:
| Dim intSource Dim strSection intSource = 2 strSection = "" objRenderApplication.LoadConfiguration intSource, strSection, objSession |
If the intSource parameter is set to CdoConfigDS, the strSection parameter is ignored because the directory server only has one configuration object. The registry information must already be loaded before you call LoadConfiguration with CdoConfigDS, since the Organization, Site, and Server must be set in order to read from the Microsoft Exchange server directory.
When intSource is CdoConfigDS, the LoadConfiguration method normally does an anonymous logon to obtain Microsoft Exchange server directory information. If you are already logged on to a session, you can pass the Session object in the objSession parameter so that LoadConfiguration does not have to log on again. This can improve performance.
The ConfigParameter property of the rendering application object provides access to this information. Use it by passing a single parameter, called parameter, to specify the configuration value you want to retrieve:
| strExchOrg = objRenderApplication.ConfigParameter("Enterprise") strExchSite = objRenderApplication.ConfigParameter("Site") strExchServer = objRenderApplication.ConfigParameter("Server") |
Note that this information is only available at the Microsoft Windows NT 3.x/4.x server registry if Microsoft Outlook Web Access is installed on the same machine.
The CDO Rendering library 1.x consists of two main objects. The ObjectRenderer object and the ContainerRenderer object. Because these are the objects at the highest level of the CDO HTML Rendering library, they are called top level objects. For more information about the available objects, properties and methods, please take a look at 'All you ever wanted to know about ASP & CDO but were afraid to ask', CDO Rendering Object Model.
The CreateRenderer method creates a rendering object, which can be attached to the rendering application. But it is also possible to create standalone rendering objects. This is described later on this page.
The following code snippet shows how to create a container renderer object on top of an existing rendering application:
| Dim intRenderingClass intRenderingClass = 3 Set objContainerRenderer = objRenderApplication.CreateRenderer(intRenderingClass) |
The intRenderingClass parameter can have one of the following values:
| Constant | Value | Description |
|---|---|---|
| CdoClassContainerRenderer | 3 | Create a ContainerRenderer object to render CDO collections |
| CdoClassObjectRenderer | 2 | Create an ObjectRenderer object to render single CDO objects |
Note that for Microsoft Visual Basic CDO 1.x define 32-bit type library constants. This type library constants are not available if you use this code in your Microsoft Active Server Pages application because the Microsoft Visual Basic Scripting Edition does not support type library constants. You need to declare them yourself or use the decimal values.
Also the rendering object created by the CreateRenderer method inherits the code page and formats from this application, as well as logging capability. You could create a container renderer or object renderer directly by calling the Microsoft Visual Basic Scripting Edition CreateObject function.
The ContainerRenderer and ObjectRenderer objects are known as top-level objects because they can be created directly, without having to be derived from another object. When created directly such an object is known as a standalone renderer object because it has no parent link.
In general, standalone renderer objects are best used for single operations, such as rendering certain properties of the current object. When you use standalone renderer objects, you generally do not intend to read more data from the object or access it in other ways.
The following code snippet shows how to create a standalone ContainerRenderer object:
| Dim objContainerRenderer Set objContainerRenderer = Server.CreateObject("AMHTML.ContainerRenderer") |
You must set the correct kind of data source, an object or a collection, when rendering an individual object or a collection. To render a collection, use a ContainerRenderer object.
The following table shows which collections can be rendered with a ContainerRenderer:
| Collection | Description |
|---|---|
| Folders | A collection of folder objects |
| Messages | A collection of messages inside a folder |
| AddressEntries | A collection of address entries |
| Recipients | A collection of recipient objects of a message |
To specify which collection should be rendered you need to set the DataSource property of the newly created renderer object, which is available to both, the ContainerRenderer and the ObjectRenderer.
The following code snippet shows how to set the DataSource property:
| objContainerRenderer.DataSource = objFolders |
Because of similarly named objects, take care when setting the DataSource. It is possible to pass a folder object as the DataSource on the ObjectRenderer object but if passed as the DataSource on a ContainerRenderer object, the call will fail.
After the DataSource property is specified on the container renderer, a Views collection is available through the container renderers Views property.
For a folder object there are predefined views available. You can also create views within your Microsoft Active Server Pages application. The following table shows which type of views are available:
| View | Description |
|---|---|
| Common Views | Defined globally for all folders and all messaging users. Modifications to common views last until the ContainerRenderer object is released |
| Personal Views | Defined for each individual messaging user. Modifications to personal views last until the ContainerRenderer object is released |
| Folder Views | Defined for each individual folder. Modifications to folder views last until the DataSource property is changed |
| Custom Views | Created by your custom Microsoft Active Server Pages application, with the Views collection Add method. A custom view is non persistent and cannot be saved |
Note that simply changing the CurrentView property does not reset a view into it's original state.
The view to be applied to the container object is specified in the container renderers CurrentView property. A new instantiated Views collection always has a default current view. If it is not specified, the CDO Rendering library 1.x sets it to the first view in the collection.
The following table shows which classes are available in a Views collection and can be rendered by a ContainerRenderer object:
| Class | Description |
|---|---|
| CalendarView | Messages collection containing AppointmentItem objects |
| TableView | AddressEntries collection, Folders collection, Messages collection, or Recipients collection |
Note that a CalendarView can only be used with appointment items stored in the primary calendar folder of a mailbox. Public folders or any other folder in a mailbox than the primary calendar folder are not supported by CDO 1.x and therefore also by the CDO Rendering library 1.x.
The TableView in turn contains a collection of Column objects. The collection is obtainable from the table view's Columns property. Each Column object specifies a property to be rendered in its Property property and the manner of rendering that property in its RenderUsing property. The display order of the columns is determined by the ordering of the table view's Columns collection. The leftmost column is the one obtained from the collection's Item property with an index value of 1, and the rightmost is obtained with an index value equal to the collection's Count property.
The following code snippet shows how to create a custom view and add two columns:
| Set objView =
objRenderer.Views.Add("CustomView") Set objColumns = objView.Columns objColumns.Add "Received", CdoPR_MESSAGE_DELIVERY_TIME, 18, 0, 2 objColumns.Add "Subject", CdoPR_SUBJECT, 50, 32, 3 objRenderer.CurrentView = "CustomView" |
The rendering of each property of an object is controlled by the various formats contained in the renderer object. Each format in the collection corresponds to a single property, except for special-purpose formats, which do not represent specific properties. Every property to be rendered should be represented by exactly one Format object.
The following code snippet shows how to create new formats:
| Set objFormat =
objRenderer.Formats.Add(CdoPR_SUBJECT) Set objPatterns = objFormat.Patterns objPatterns.Add "*", "<font face='Arial, Helvetica, sans-serif' size='-1'>%value%</font>" Set objFormat = objRenderer.Formats.Add(CdoPR_MESSAGE_DELIVERY_TIME) objPatterns.Add "*", "<font face='Arial, Helvetica, sans-serif' size='-1'>%value%</font>" |
If the character string between the percent signs is not a valid substitution token or format name, the property is rendered by data type. If a token is valid but does not apply to the property being rendered, for example a %kvalue% token for a string property, nothing is rendered in place of the token. There are a couple of substitution tokens that have special meaning in the CDO Rendering library 1.x.
The following table shows the most common substitution tokens:
| Token | Description |
|---|---|
| %kvalue% | For numeric properties, the value/1024. Does not include "KB" symbol |
| %rowid% | Index of row in the rendered table. Ranges from 0 to RowsPerPage - 1 |
| %obj% | PR_ENTRYID or PR_LONGTERM_ENTRYID_FROM_TABLE of object |
| %parentobj% | PR_PARENT_ENTRYID of the object |
| %value% | The value of the property being rendered, based on usage of Format objects |
Finally after all parameters are set and the custom view is created you can render the container with the following single line of code:
| <% objRenderer.Render 1, 1, 0, Response %> |
The CreateRenderer method creates a rendering object, which can be attached to the rendering application. But it is also possible to create standalone rendering objects. This is described later on this page.
The following code snippet shows how to create an object renderer object on top of an existing rendering application:
| Dim intRenderingClass intRenderingClass = 2 Set objContainerRenderer = objRenderApplication.CreateRenderer(intRenderingClass) |
The intRenderingClass parameter can have one of the following values:
| Constant | Value | Description |
|---|---|---|
| CdoClassContainerRenderer | 3 | Create a ContainerRenderer object to render CDO collections |
| CdoClassObjectRenderer | 2 | Create an ObjectRenderer object to render single CDO objects |
Note that for the convenience of the Microsoft Visual Basic programmer CDO 1.x define 32-bit type library constants. These type library constants are not available if you use this code in your Microsoft Active Server Pages application because the Microsoft Visual Basic Scripting Edition does not support type library constants. You need to declare them yourself or use the decimal values.
Also the rendering object created by the CreateRenderer method inherits the code page and formats from this application, as well as logging capability. You could create a container renderer or object renderer directly by calling the Microsoft Visual Basic Scripting Edition CreateObject function.
The ContainerRenderer and ObjectRenderer objects are known as top-level objects because they can be created directly, without having to be derived from another object. When created directly such an object is known as a standalone renderer object because it has no parent link.
In general, standalone renderer objects are best used for single operations, such as rendering certain properties of the current object. When you use standalone renderer objects, you generally do not intend to read more data from the object or access it in other ways.
The following code snippet shows how to create a standalone ObjectRenderer object:
| Dim objObjectRenderer Set objObjectRenderer = Server.CreateObject("AMHTML.ObjectRenderer") |
You must set the correct kind of data source, an object or a collection, when rendering an individual object or a collection. To render a single object, use a ObjectRenderer object.
The following table shows which collections can be rendered with a ObjectRenderer:
| Object | Description |
|---|---|
| AddressEntry | A single address entry object |
| Attachment | A single attachment object |
| Folder | A single folder object |
| InfoStore | A single infostore object |
| Message | A single message object |
| Session | A single session object |
To specify which object should be rendered you need to set the DataSource property of the newly created renderer object, which is available to both, the ContainerRenderer and the ObjectRenderer.
The following code snippet shows how to set the DataSource property:
| objObjectRenderer.DataSource = objMessage |
Because of similarly named objects, take care when setting the DataSource. It is possible to pass a folder object as the DataSource on the ObjectRenderer object but if passed as the DataSource on a ObjectRenderer object, the call wilAfter the DataSource property is specified on the object renderer a RenderProperty property is available. The RenderProperty can be a long integer designating the property by property tag, or a string designating it by custom name. If the RenderProperty is a custom name, it can optionally be prefixed with a GUID string identifying its property set. In this case, the GUID should be enclosed in braces. For more information about GUIDs, please take a look at Property Tags and Types.
The following code snippet shows how to render the information of an e-mail message:
| <font face="arial"
color="000000" size="2">From: </font> <% objObjectRenderer.RenderProperty CdoPR_SENT_REPRESENTING_NAME, 0, Response %> <font face="arial" color="000000" size="2">To: </font> <% objObjectRenderer.RenderProperty CdoPR_SUBJECT, 0, Response %> <font face="arial" color="000000" size="2">Received: </font> <% objObjectRenderer.RenderProperty CdoPR_CLIENT_SUBMIT_TIME, 0, Response %> <font face="arial" color="000000" size="2">Text: </font> <% objObjectRenderer.RenderProperty CdoPR_RTF_COMPRESSED, 0, Response %> |
Finally don't forget to destroy all objects after they are no longer necessary by using the following code snippet:
| Set objRenderApplication =
Nothing Set objContainerRenderer = Nothing Set objObjectRenderer = Nothing |