Domain Isolation for Folder Home Page Customization in Outlook 2007

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Summary: Learn how to provide application domain isolation for managed controls hosted in folder home pages in Microsoft Office Outlook 2007. (12 printed pages)

Hulya Pamukcu, Microsoft Corporation

October 2008

Applies to: Microsoft Office Outlook 2007

Download: Domain Isolation for Folder Home Page Customization in Outlook 2007

Contents

  • Overview

  • Introduction to Domain Isolation for Folder Home Page Customization in Outlook

  • Exposing the Managed Control to be Used by Native Code

  • Using a Managed Control in a Native Proxy

  • Hosting a Native Proxy in an Outlook Folder Home Page

  • Performing Cleanup for the Windows Forms User Control

  • Using the Sample Code

  • Conclusion

  • Additional Resources

Overview

Microsoft Office Outlook 2007 folders support folder home pages, which can be associated with an Internet Web page, an HTML file, or an Active Server Pages (ASP) file that is displayed when a user selects the folder. An example of a folder home page is Outlook Today, which is displayed when the user clicks the top-level Mailbox folder.

To view the file that is associated with the Outlook Today page, go to the Properties dialog box and select the Home Page tab. In this case, an address similar to the following, which points to an HTML file, is displayed.

res://C:\Program Files\Microsoft Office\Office12\1033\OUTLWVW.DLL/outlook.htm

Similarly, you can create HTML and associate it with a folder in Outlook 2007 to provide custom views of Outlook items. To access Outlook 2007 data, you can embed an ActiveX control named the Outlook View Control.

The following HTML code example can be used to create a calendar view with the specified properties. The ViewCtlFolder object is the Outlook View Control, which accesses Outlook 2007 data through an ActiveX control.

<html>
<head>
</head>
<body>
<OBJECT classid=CLSID:0006F063-0000-0000-C000-000000000046
        id=ViewCtlFolder
        width="100%"
        height="430"
codebase="http://activex.microsoft.com/activex/controls/office/outlctlx.CAB#ver=9,0,0,3203">
   <param name="Namespace" value="MAPI">
   <param name="Folder" value="Calendar">
   <param name="View" value="Day/Week/Month View With AutoPreview">
   <param name="Restriction" value="">
   <param name="DeferUpdate" value="0">
</OBJECT>
</body>
</html>

Using the Outlook View Control is not the only way to customize a folder home page. A folder home page can instantiate and interact with any ActiveX control. For example, the implementation outlined in the article Outlook Customization for Integrating with Enterprise Applications customizes a folder home page using Windows Forms controls, by taking advantage of the fact that Windows Form UserControl can also be hosted using ActiveX interfaces. The ability to use managed controls enables more complex folder view customization scenarios. However, as discussed in Outlook Customization for Integrating with Enterprise Applications, hosting managed controls in the home page requires that components of the solution load into the default application domain. Another add-in that also loads components into the default application domain could conflict with your add-in and cause Outlook instability. This article proposes a solution to provide application domain isolation for managed controls hosted in folder home pages, eliminating the problems that would arise from loading them into the default application domain.

Introduction to Domain Isolation for Folder Home Page Customization in Outlook

The domain isolation requirement in Outlook 2007 is not specific to folder home pages. If you are familiar with Outlook 2007 add-in programming, you know that this issue is also valid for Outlook 2007 add-ins. If you do not use a standard COM shim (such as the Microsoft Visual Studio Tools for the Microsoft Office System, Version 2008 loader available from the Office Development with Visual Studio Developer Center) or provide your own custom COM shim (for more information, see Isolating Office Extensions with the COM Shim Wizard) your extension (add-in) DLL loads into the default application domain along with all other unshimmed extensions. For more information about why it is important to isolate managed Microsoft Office extensions from each other and how you can do so by using COM shims, see Isolating Office Extensions with the COM Shim Wizard.

To isolate the application domain of managed controls hosted in folder homepages, this article will use a similar approach to the one used to isolate managed add-ins. Therefore, this article will address how a COM shim works, before presenting the solution for folder homepages. A COM shim, basically, is a Visual C++ Active Template Library (ATL) COM DLL. It exposes a COM-creatable class that acts as a proxy to the real managed extension class. When the host Office application starts, it checks the registry to verify which add-ins to load, and then uses standard COM object creation to instantiate the registered proxy class. This action loads the COM shim DLL that is registered to act as a proxy for one of the add-ins. When the proxy class is created after the COM shim is loaded, it in turn creates an instance of a second class: the common language runtime (CLR) loader class. The CLR loader object loads the Microsoft .NET Framework CLR. It then creates a new application domain and loads the managed extension assembly into the new application domain. It creates an instance of the managed extension class that implements the target interface (that is, IDTExtensibility2, ISmartTagRecognizer and/or ISmartTagAction, or IRtdServer) and caches the interface pointer. Subsequently, any calls from an Office 2007 application into this interface are handled first by the proxy class. The proxy class passes those calls through the cached pointer to the actual extension class in the managed extension assembly.

Similarly, to provide domain isolation for the managed controls hosted in a folder home page, ensure that they are instantiated and loaded into a separate application domain. We will not have to create our own domain, because we will use the domain created by the Visual Studio Tools for Office loader. However, we still must create a native COM shim to act as a proxy for the calls to the managed controls. To use the Visual Studio Tools for Office isolated domain, we will start with a Visual Studio Tools for Office Outlook add-in. The add-in DLL, which is loaded to an isolated domain by the Visual Studio Tools for Office loader, will create the managed control and pass the reference to the native shim (an ActiveX control). Using this reference, the native ActiveX control, which is hosted by folder home page, acts as a proxy for the calls to managed control.

Figure 1 summarizes the basic flow for creating the native proxy between a folder home page and a managed control. The next section presents information about how the specific pieces are implemented.

Figure 1. Folder Home Page/ActiveX Control Interaction Logic

Folder Home Page/ActiveX Control Interaction Logic

Exposing the Managed Control to be Used by Native Code

You must expose the Windows Form User Control to the native code to make it available to the native ActiveX control. This requires an entry point into the add-in to be exposed. To do this in Visual Studio Tools for Office, override the AddIn.RequestComAddInAutomationService Method (2007 System) method as shown in the following C# code example.

protected override object RequestComAddInAutomationService()
{
   if (utilities == null)
   {
     utilities = new AddInUtilities();
   }

   return utilities;
}

[System.Runtime.InteropServices.ComVisible(true)]    [System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)]
    public class AddInUtilities
    {
        public FolderHomepageWinFormsControl GetWinFormsControl()
        {
            return new FolderHomepageWinFormsControl();
        }
    }

Using a Managed Control in a Native Proxy

The following sections discuss how to obtain and use the reference to the managed control in a native proxy.

Getting a Reference to Outlook Application Instance

To get a reference to the add-in object exposed in the previous step from the native code, you must find the correct Outlook application instance. When the SetClientSite method is called on the IOleObject interface object; it gets a reference to the IOleClientSite interface object. The IOleClientSite interface is the primary means by which an embedded object obtains information about the location and extent of its display site, its moniker, its user interface, and other resources provided by its container. Using this object, you can retrieve a reference to the host application (Outlook) instance as shown in the following C++ code example.

STDMETHODIMP CFolderHomepageCtl::Initialize(IOleClientSite* pClientSite)
{
    HRESULT hr = S_OK;

    CComPtr<IWebBrowserApp> srpWebBrowserApp;
    CComPtr<IDispatch> srpDocument;
    CComPtr<IServiceProvider> srpSP;
    CComPtr<IDispatch> srpScript;
    CComVariant cvarExternal;
    CComPtr<IDispatch> srpExternal;
    CComVariant cvarOutlookApplication;
    CComPtr<Outlook::_Application> m_srpApp;
    CComVariant cvarScript;

    hr = pClientSite->QueryInterface(__uuidof(srpSP), (void**)&srpSP);
IfFailGo(hr)

    hr = srpSP->QueryService(SID_SWebBrowserApp, IID_IWebBrowserApp, (void **)&srpWebBrowserApp);
IfFailGo(hr)

    hr = srpWebBrowserApp->get_Document(&srpDocument);
IfFailGo(hr)

    hr = srpDocument.GetPropertyByName(L"Script", &cvarScript);
IfFailGo(hr)

    srpScript = V_DISPATCH(&cvarScript);
    hr = srpScript.GetPropertyByName(L"external", &cvarExternal);
IfFailGo(hr)

    srpExternal = V_DISPATCH(&cvarExternal);
    hr = srpExternal.GetPropertyByName(L"OutlookApplication", &cvarOutlookApplication);
IfFailGo(hr)

    hr = V_DISPATCH(&cvarOutlookApplication)->QueryInterface(__uuidof(m_srpApp), (void**)&m_srpApp);
IfFailGo(hr)

    hr = CFolderHomepageCtl::GetWinFormsControl(m_srpApp);
IfFailGo(hr)

Error:
    return hr;
}

Getting a Reference to an Exposed Managed Object

When the corresponding Outlook application instance is found, a reference to the managed object, from the add-in-exposed object, can be obtained as shown in the following C++ code example.

STDMETHODIMP CFolderHomepageCtl::GetWinFormsControl(Outlook::_Application* pApp)
{
    HRESULT hr = S_OK;

    CComPtr<COMAddIns> srpAddIns;
    CComPtr<COMAddIn> srpAddIn = NULL;
    VARIANT varResult;

    // Get the Outlook COM AddIn Collection.
    hr = pApp->get_COMAddIns(&srpAddIns);
IfFailGo(hr)

    // Find the FolderHomepage Addin.
    hr = srpAddIns->Item(&CComVariant(L"FolderHomepageSampleAddIn"), &srpAddIn);
IfFailGo(hr)

    // Get the addin object.
    ATLASSERT( m_srpAddInObject == NULL);
    if (m_srpAddInObject != NULL) {
        m_srpAddInObject.Release();
    }

    hr = srpAddIn->get_Object(&m_srpAddInObject);
IfFailGo(hr)

    if (m_srpAddInObject == NULL) {
        hr = E_FAIL;
        return hr;
    }

    hr = m_srpAddInObject.Invoke0(L"GetWinFormsControl", &varResult);
IfFailGo(hr)

    ATLASSERT( V_VT(&varResult) == VT_UNKNOWN || V_VT(&varResult) == VT_DISPATCH );

    if (!(V_VT(&varResult) == VT_UNKNOWN || V_VT(&varResult) == VT_DISPATCH))  {
        hr = E_UNEXPECTED;
        goto Error;
    }

    // Save the reference into the global variable.
    m_srpWinFormsDashboardControl = V_UNKNOWN(&varResult);

    hr = CFolderHomepageCtl::QueryAndGetObjects();
IfFailGo(hr)

Error:
    return hr;
}

Getting Proxy Interface Objects

After you obtain a reference to the control, you can query the implemented interfaces to get the corresponding interface objects. Then you can relay the calls on the IDispatch, IPersist, IOleControl, IOleWindow, IOleInPlaceActiveObject, IOleInPlaceObject, IOleObject, IViewObject, IViewObject2, and IDisposable interfaces as shown in the following C++ code example.

STDMETHODIMP CFolderHomepageCtl::QueryAndGetObjects()
{
    HRESULT hr = S_OK;
    
    CComPtr<IUnknown> srpControl;

ATLASSERT(m_srpWinFormsDashboardControl);

    srpControl = m_srpWinFormsDashboardControl;

    hr = srpControl->QueryInterface(&m_srpOleControl);
IfFailGo(hr)

    hr = srpControl->QueryInterface(&m_srpOleInPlaceObject);
IfFailGo(hr)

    hr = srpControl->QueryInterface(&m_srpOleObject);
IfFailGo(hr)

    hr = srpControl->QueryInterface(&m_srpOleInPlaceActiveObject);
IfFailGo(hr)

    hr = srpControl->QueryInterface(&m_srpViewObject);
IfFailGo(hr)

    hr = srpControl->QueryInterface(&m_srpViewObject2);
IfFailGo(hr)

    hr = srpControl->QueryInterface(&m_srpDisposable);
IfFailGo(hr)

Error:
   return hr;
}

Hosting a Native Proxy in an Outlook Folder Home Page

The following HTML code example shows the content of the HTML file displayed by folder home page that allows native proxy to interact with Outlook Application. Be aware that the CLSID value is set to the class ID of the native proxy control.

<html>
  <head>
    <style type="text/css">body{overflow: hidden}</style>
  </head>
  <body rightmargin = '0' leftmargin ='0' topmargin ='0' bottommargin = '0'>
     <object classid='clsid:8948818E-10C7-4F07-91B8-D928D413DEA9' ID='FolderHomepageCtl' VIEWASTEXT width='100%' height='100%'/>
  </body>
</html>

Performing Cleanup for the Windows Forms User Control

Ensure that when the home page is unloaded, the Dispose() method on the Windows Form User Control is called to prevent a memory leak. In the sample implementation, this call is made in the FinalRelease method of the native proxy. To perform additional cleanup on the managed code, call the WinFormsControlCleanUp method as shown in the following C++ code example.

void FinalRelease()
    {
HRESULT hr = S_OK;

DISPPARAMS dp = {NULL, NULL, 0, 0}; 

// Call Dispose on WinFroms control.
raw_Dispose();

// m_srpAddInObject is NULL when the addin is disabled
if(m_srpAddInObject != NULL)
{
// Invoke cleanup method on WinForms control.
m_srpAddInObject.Invoke0(L"WinFormsControlCleanUp");
}
    }

Using the Sample Code

A Visual Studio 2008 solution is provided as a sample implementation of the ideas presented in this article. You must modify the code examples for your specific add-in and managed controls.

To use the sample code

  1. Replace the add-in name in the CFolderHomepageCtl::GetWinFormsControl method.

    STDMETHODIMP CFolderHomepageCtl::GetWinFormsControl(Outlook::_Application* pApp)
    {
        HRESULT hr = S_OK;
    
        CComPtr<COMAddIns> srpAddIns;
        CComPtr<COMAddIn> srpAddIn = NULL;
        VARIANT varResult;
    
        // Get the Outlook COM AddIn Collection.
        hr = pApp->get_COMAddIns(&srpAddIns);
    IfFailGo(hr)
    
        // Find the FolderHomepage Addin.
        hr = srpAddIns->Item(&CComVariant(L"[YOUR ADD-IN NAME]"), &srpAddIn);
    IfFailGo(hr)
    
  2. Modify the Windows Form control and the WPF control file to create your controls.

Conclusion

This article presents an approach for providing domain isolation for folder home page customization in Outlook. Use the sample code as a reference for your specific implementation to customize folder home pages and application domain isolation in Outlook 2007. Application domain isolation ensures that your folder home page and embedded WPF or WinForm User Controls operate as expected.

Additional Resources

For more information, see the following resources: