Examples of COM Automation in Silverlight 4


Introduction

In the previous article we talked about COM automation support introduced in Silverlight 4 and we said that COM automation is available only for Silverlight OOB (Out-of-Browser) applications that have Elevated Trust, and that's one of the security restrictions imposed by Silverlight.

Today, we're going to talk about COM automation in more details and give few Silverlight examples that make use of this great feature.

Concepts

Finding COM Components
 

COM components expose their interfaces and classes via Windows Registry. COM classes exposed to public available in this machine are registered in the Registry at HKCR\CLSID (which is a repository for all COM classes registered in this machine.) Because the machine may have thousands of COM components installed, every COM class is identified with a GUID (Globally Unique Identifier.) This GUID is very long and difficult to remember (it's something like {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}) so COM classes are using another way to identify themselves; that is the ProgID (Programmatic ID.)

ProgID for a COM class is a simple and clear string that identifies that class and represents it. For example, Microsoft Word exposes its functionalities through a COM class that you can reach it using the ProgID Word.Application. So, instead of the GUID of a class, you simply refer to it using its simple and easy-to-remember ProgID.

Then, how to find the right COM component? Or how to know if a COM component exposes a certain functionality that I need? Google it, that's the only way! If you are looking for a COM component that does something you need just google it. And always have the COM component in your right hand, and have its documentation in the other. And don't miss a chance to ask MSDN for help.

Accessing the COM Component
 

Now you have the COM component and know what to do with it. The next step is to create a new instance from the COM class using its ProgID. This is can be done using the AutomationFactory class found in the namespace System.Runtime.InteropServices.Automation (exist in System.Windows.dll.) This class exposes a few functions and only one property. The only property is IsAvailable that returns whether or not COM is supported by the operating system (COM is supported only in Windows.) Of the few functions AutomationFactory supports, we care about only CreateObject() that takes the ProgID as an input and returns the created object.

COM and Late Binding
 

When you assign an object to a variable that assignment can be made as early-binding or late-binding.

Early-binding is that what you make every day and all the time. By default, object assignment is made as early-binding, means that you create a variable of specific type and bind that object to that variable. Then, the compiler always knows the type of object assigned and the members (methods, properties, etc.) it supports and that allows him to do some checks, optimizations, and perform some memory allocations before application start.

In addition, early-bound variables can be thought as strongly-typed objects, means that you can check for their exposed members, use some IDE features like Intellisense and Object Explorer, and also receive compiler errors when you try to make calls to members that don't exist (for instance.)

Late-binding on the other hand is made at runtime, means that the compiler doesn't have enough information about the type at compile time. That means that no type checks, no method lookups or Intellisense, no verifications, no optimizations, and also no compilation errors from the late-bound object.

Is there any benefit from late-binding? Does it have anything to do with COM? Actually, it's not as ugly as you think, it has lots of benefits and it also the core of COM automation in Silverlight (and .NET 4.0 too.)

Late-binding allows you not to embed COM types and interfaces in your .NET assembly, and that would help reduce your application size dramatically, and also protects you from versioning fails and falling in the DLL Hell.

Worth mentioning that late-binding was introduced in .NET 4.0 via the dynamic keyword and DLR (Dynamic Language Runtime) libraries. Before .NET 4.0, late-binding was supported only via reflection. Regarding Silverlight, late-binding was introduced in version 4 supporting easier COM automation and HTML DOM.

After all, to create a COM object in Silverlight you first ensure that Microsoft.CSharp.dll and Microsoft.Core.dll are referenced to your project. After that, you can call AutomationFactory.CreateObject() and assign the returned object to a dynamic variable and start coding with it.

Preparing Your Project
 

Now, let's get to work. We'll now prepare a Silverlight application for communication with COM components. Remember that this process requires a Silverlight 4 application running as OOB and having the elevated trust.

Start with a Silverlight project and ensure that you have selected version 4 from the New Application dialog. (The application will run as OOB, so you can safely uncheck the web application hosting option.)

Figure 1 - Creating New Silverlight Application

Figure 1 - Creating New Silverlight Application

After creating the project, open project properties and from the bottom of the Silverlight tab check the option "Enabling running application out of browser" (check figure 2.)

Figure 2 - Configuring Silverlight to run as OOB

Figure 2 - Configuring Silverlight to run as OOB

Then click Out-of-Browser Settings button and from the bottom of this dialog too check the "Require elevated trust when running" option (check figure 3.)

Figure 3 - Enabling Elevated Trust

Figure 3 - Enabling Elevated Trust

Now click OK and close project properties and save the project.

Next, add support for dynamic variables and late-binding feature to the project by referencing Microsoft.CSharp.dll (and System.Core.dll too if it's not currently referenced) in the project.

Figure 4 - Adding Reference to Microsoft.CSharp.dll

Figure 4 - Adding Reference to Microsoft.CSharp.dll

OOB Characteristics

First of all, you can launch your OOB application by clicking Run or pressing F5 (figure 5.)

Figure 5 - Running OOB Application

Figure 5 - Running OOB Application

OOB applications can also run in a web page (by default, you'll redirect the user to a web page where he can install the application to his PC.) Try browsing to TestPage.html (in Bin\<debug|release>, check figure 6) or referencing the project in web application Keep in mind that COM support is not available for OOB applications running in the web.

Figure 6 - OOB Applications from the Web

Figure 6 - OOB Applications from the Web

When running OOB application from a web page the user can right click the application and chooses to install it on his machine (figure 7.) This behavior is the default, but you can disable it from the Out-of-Browser Settings dialog (check figure 3.)

Figure 7 - Installing Silverlight OOB App

Figure 7 - Installing Silverlight OOB App

When trying to install an OOB application that requires elevated trust the user may accept a security warning before the installation goes on (figure 8.)

Figure 8 - Installing Elevated Trust App

Figure 8 - Installing Elevated Trust App

You can also order the application to launch the installation process via Application.Install(), but this requires to be called in response to a user-initiated action (e.g. clicking a button.)

  • Another great feature of ApplicationClass is IsRunnignOutOfBrowser that returns whether the application is running OOB.

Sample 1: Talking Apps

Our first example is an application that makes use of the speech API and speech COM library, sapi.dll, to read a textual input from the user. The code uses the SAPI.SpVoice class that has the Speak() function that we'll make use of.

First, design a window that has an input text box and a button to read the text. You might get help from the following XAML:

<Grid Background="White">

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <TextBlock Grid.Row="0" Margin="10" Text="Enter the text to read:" />

    <TextBox Grid.Row="1" Margin="10" x:Name="inputTextBox" />

    <Button Grid.Row="2" Margin="10" Width="150" Click="Button_Click" Content="Read" />

</Grid>
 

The application might look like this:

Figure 9 - The Talking App

Figure 9 - The Talking App

Now, start coding the Click event of the button:

  • Remember to include a using statement for System.Runtime.InteropServices.Automation.

private void Button_Click(object sender, RoutedEventArgs e)
{
    
if (!Application.Current.IsRunningOutOfBrowser)
    {
        MessageBox.Show(
"This application cannot be run from the browser.");
       
return;
    }
   
if (!AutomationFactory.IsAvailable)
    {
        MessageBox.Show(
"Your operating system does not support COM.");
       
return;
    }
    try
    {
       
using (dynamic obj = AutomationFactory.CreateObject("SAPI.SpVoice"))
        {
            obj.Speak(inputTextBox.Text);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(
"An error has occurred.\n" + ex.Message);
    }
}

In the previous code we have checked first for whether the application is running as OOB or not (using Application.IsRunningOutOfBrowser property.) After that, we made a second check for ensuring that COM automation is supported by the operating system (i.e. the user must be working on Windows.)

Then, we have created our first COM object using AutomationFactory.CreateObject() function specifying the class ProgID which isSAPI.SpVoice. As you see, we have assigned the created object to a dynamic variable and we have also encapsulated the object in ausing statement to ensure that system resources get released quickly as soon as we finish working with the object.

You can try an updated version and download it from here:

Preview - Download

Sample 2: Microsoft Office Automation

We won't dig into Microsoft Office SDK or even one of its products, we don't have much space here, and it also requires a punch of articles in its own. Instead, we'll have just a few examples and two samples that clear up the ambiguities of COM automation. More help can be found in the documentation of the Office programming model available in MSDN.

Word Automation
 

Microsoft Word exposes its programming model via COM components that you can reach its main Application object via the ProgIDWord.Application. This model allows you to almost do everything programmatically from creating and opening documents to saving and printing them, even running macros and recording them is available through this model.

The following code creates a Word document and writes some text to it:

using (dynamic app = AutomationFactory.CreateObject("Word.Application"))
{
    dynamic doc = word.Documents.Add();

    dynamic par = document.Content.Paragraphs.Add();
    par.Range.Text =
"Hello, World!";
    par.Range.Font.Bold =
true;
    word.Visible = true;
}

More information about Word object model can be found here: http://msdn.microsoft.com/en-us/library/kw65a0we.aspx.

Outlook Automation
 

Like all other Microsoft Office products, Microsoft Outlook can be managed completely by the code using its programming model exposed through the ProgID Outlook.Application. The following code sends an email using Outlook (thanks to Jeff Prosise for providing the code):

using (dynamic app = AutomationFactory.CreateObject("Outlook.Application"))
{
    dynamic mail = app.CreateItem(0);
    mail.Recipients.Add(
"");
    mail.Subject =
"Hello, World!";
    mail.Body =
"Silverlight COM Automation is so cool ;)";
    mail.Save();
    mail.Send();
}

A full documentation of Outlook programming model can be found here: http://msdn.microsoft.com/en-us/library/ms268893.aspx.

Excel Automation
 

The following sample uses Excel automation to export some data of a DataGrid to an Excel file:

Figure 10 - The FeaturedBlogs App

Figure 10 - The FeaturedBlogs App

Preview - Download

More about Excel programming model can be found here: http://msdn.microsoft.com/en-us/library/wss56bz7.aspx.

Sample 3: File Surfer

The last sample here makes use of the most powerful file managing COM component exposed through the ProgIDScripting.FileSystemObject. This class gives your application the power to do almost everything on file system even if your Silverlight application lonely (without COM support) that runs with elevated trust don't have such those privileges (remember what we have said about COM automation? It's the ultimate power for Silverlight.)

The next is an example of a code that creates a text file on drive C: and writes some text to it:

using (dynamic fso = AutomationFactory.CreateObject("Scripting.FileSystemObject"))
{
   
string path = "C:\\file.txt";
    dynamic file = fso.CreateTextFile(filePath, true);
    file.WriteLine(
"Hello, World!");
    file.Close();
    file = fso.OpenTextFile(filePath, 1, true);
    file.Close();
}

And the following is an application that helps you surfing the file system with no restrictions as if you were using File Explorer:

Figure 11 - The FileSurfer App

Figure 11 - The FileSurfer App

Preview - Download

What's next

You might like to check Justin Angel's hot article about COM automation in Silverlight, lots of examples are available there.


Similar Articles