August 2006 - Posts

The comment I received from Microsoft regarding the OWC issue is this:

ActiveX controls are not supported on the design surface in Visual Studio 2005. We intentionally do not load or render the controls because of security reasons. The browser has a sophisticated system for managing the rights and permissions of the controls which we did not want to replicate in the Visual Studio IDE, just to make it safe to edit pages containing controls. To add to the complication, for patent reasons the browser does not automatically activate ActiveX controls specificed using the object or embed tag. To make a control active it needs to be inserted by script. For more details see
http://www.microsoft.com/windows/ie/ie6/using/techinfo/activexupdate.mspx

Abstract

Any application running on the client computer can be automated from a web page. The following article will provide detailed steps on accomplishing this using ASP.NET and C#. The approach shows how to automate a third party control such as Microsoft Outlook or Windows Media player.

 

Use automation from web pages for data exchange between disparate applications.

 
Consider an application that needs to run embedded in an ASP.NET web form. One of the design requirements is that the application should be able to automate Microsoft Outlook and exchanging data as needed. For simplicity, the article will create a windows control that uses MAPI to read a specific folder in Outlook. Note that the automation will use the current user's session. You must have Outlook installed for the automation to succeed. If you do not have Outlook installed, you may use another common application such as Windows Media player and make the necessary adjustments in code.
 
Create the user control.
     Open Microsoft Visual Studio 2005 (Microsoft Visual Studio 2003 may be used also). Create a Windows Control Library project. Call it Outlooker. Add a button named "Mapi" with title set to "MAPI". Add a treeview control to the webform called outlookFolders. Double-click the "Mapi" button to generate an event handler. Inside the event handler, add code to retrieve the Outlook folders. The code is simple to understand and requires no further explanation.
 
            //create an automation object
            Outlook._Application olApplication = new Outlook.ApplicationClass();
            Outlook._NameSpace oMapi = olApplication.GetNamespace("MAPI");
            Outlook._Folders oFolders;
            oFolders = oMapi.Folders;
            Outlook.MAPIFolder oPublicFolder = oFolders["Public Folders"];
            oFolders = oPublicFolder.Folders;
            Outlook.MAPIFolder oAllPFolder = oFolders["All Public Folders"];
            oFolders = oAllPFolder.Folders;

            //add the folders to the outlook tree
            for (int i = 1; i < oFolders.Count; i++)
            {
                outlookFolders.Nodes.Add(oFoldersIdea.Name);
            }
 
Add a reference to the project for Microsoft Outlook. To do this, right click the project in Microsoft Visual Studio solutions explorer and choose Add reference. In the COM tab, select Microsoft Outlook Object 12 library and click OK. If object library 12 is not installed, user the next available object library for Microsoft Outlook.

 
Run the application in Visual Studio .NET. The ActiveX container will appear with the windows user control embedded in it. Click on the MAPI button. The application displays the appropriate Outlook folders for the current user session.

 
The previous step creates the client application. The next step is to embed this application in a web form. After embedding the control in a web form, the application will execute on the client. It will not execute on the server. It is important to understand this difference. The application does not automate Outlook on the server.

 
Create a web application called Tester using Microsoft Visual Studio 2005. You may use Microsoft Visual Studio 2003 as well. Accept the defaults. Navigate to the html view of default.aspx and add the following tag.

 

<font face=arial size=1>  
  <OBJECT id="myControl1" name="myControl1" classid="http://localhost/tester/outlooker.dll#outlooker.UserControl1"> </OBJECT>
</font>

 
The object tag contains the classid that points to a fully qualified name of the assembly. The fully qualified name is necessary to locate the control when IIS serves the request.
 
 Navigate to the bin\debug folder of outlooker project created in the earlier steps above and copy the assemblies. Paste these assemblies into the same directory of tester. It's important that the dll's and default.aspx file reside in the same place. All the *.dll files should be copied.

 
 Request the page from Internet Explorer. The control should display. If the control does not display, verify that the assemblies are in the same directory as the default.aspx page. Verify also that the classid path points to the assembly.

 
 Click on the MAPI button. If you have a default profile setup in Outlook, the application will automate object, read the folders and populate the tree control in the web page.

A few notes:
Automating applications may fail if an html file is used instead of an aspx page. This is because the framework is required to handle these automation requests.
There may be a file not found error when the MAPI button is clicked. If you examine the details of the exception, it shows that the CLR is trying to load the Outlook assembly at http://localhost/tester. You must add the Outlook assembly to that exact location.
During development, you may need to purge the download cache occasionally to keep your user interface up to date. Run gacutil /cdl at a Visual Studio .NET 2005 command prompt.
By default, Internet Explorer does not allow ActiveX controls to run. From the Internet Explorer tools tab, select options.
Examine the ActiveX settings and modify appropriately to allow ActiveX controls to execute.
Managed ActiveX controls require CAS policy in order to execute. To add the appropriate CAS policy, run mscorcfg.msc from the start > run menu. Note that the security policy setup by default is sufficient to cause the ActiveX control to run. In any case, add the appropriate full trust permissions set to the LocalIntranet_Zone under Code Groups in the Machine Node of the Runtime Security Policy.
If you have substituted Windows Media player for Outlook, you can add the appropriate Windows Media player assembly at c:\winnt\system32\wmp.dll. Instantiate the object by using

            using WMPLib;
            …
            //test to see if windows media is already running
            private System.Int32 iHandle = Win32.FindWindow("WMPlayerApp", "Windows Media Player");
 
            //its not so start it
            if (iHandle == 0)
            {
                 // get Window handle
                 System.Diagnostics.Process retVal = System.Diagnostics.Process.Start(@"C:\Program Files\Windows Media
                 Player\wmplayer.exe");
                retVal.WaitForInputIdle();
            }
 
           Win32.SendMessage(iHandle, Win32.WM_COMMAND, 0x00004978, 0x00000000);        

 
The important point to note is that Win32.SendMessage is used to fire a command on the client. The third parameter fires the play event in Windows Media player. The exact value is retrieved by using Microsoft Spy++, a utility that ships with Microsoft Visual Studio. Notice that Win32 is a class library. A brief outline of the Win32 class follows.
 

using System.Runtime.InteropServices;
 
public class Win32
{
       publicconstint WM_COMMAND = 0x111;
       [DllImport("User32.dll")]
       publicstaticexternInt32 SendMessage(int hWnd, int Msg, int wParam, [MarshalAs(UnmanagedType.LPStr)] string
      lParam);
 
       [DllImport("User32.dll")]
       publicstaticexternInt32 SendMessage(int hWnd, int Msg, int wParam, int lParam);
   
      public Win32()
      {
      }
 
     ~Win32()
      {
      }
}


 
The button on your form will simply need to call the code listed above. If Windows media is running, it will play the last file loaded. Otherwise, the code will start Windows Media player on the client.