Chapter 3. Helping Out with Interop

In This Chapter

  • Using Dynamic Import

  • Deploying without primary Interop assemblies

  • Skipping the ref statement

The Component Object Model, usually called COM, is a standard for the interface of software bits at the binary level. Because it is binary, it is language-neutral, which was Microsoft's goal when the company introduced COM in 1993. COM is a language-neutral way to implement objects in a lot of different environments.

COM is as an umbrella term for a lot of different technologies in the Microsoft world. OLE, OLE2, ActiveX, COM+, and DCOM are all versions of the same idea — just implemented in different ways.

The problem with COM is networking. Although a thorough explanation is outside the scope of this book, it is important to understand that Microsoft's answer to broadly distributed applications in the 1990s was less than good. DCOM, or Distributed COM, was fraught with problems.

When XML Web services entered the scene in the late 1990s with SOAP, Microsoft just put a wrapper around COM that translated to and from SOAP. In the background, however, they were planning a much more sophisticated messaging system for Windows. That system eventually became ASP.NET Web services, and then WCF in its latest iteration.

Applications that are sewn to the desktop don't really use DCOM, though, so they have been slow to move to services, and therefore slow to move to .NET. These applications still live in COM, so we still need to interact with COM — even in this service-oriented, .NET world we live in.

What applications could be so Neanderthal? How about Microsoft Office. Yup — Microsoft Office is the biggie, and it is why C# 4.0 includes a bunch of COM interoperability features, collectively called Interop Improvements.

Principally, the optional parameters discussed in Chapter 2 of this book were implemented for COM Interop. We cover three other major improvements here: using Dynamic Import, deploying without primary Interop assemblies (PIAs), and skipping the ref statement.

If you plan on coding against Microsoft Office, trust me — this is information you need.

Using Dynamic Import

Many COM methods accept and return variant types, which are represented in the primary Interop assemblies as objects. In most cases, a programmer calling these methods already knows the static type of a returned object from context, but explicitly has to perform a cast on the returned value to make use of that knowledge. These casts are so common in day-to-day development that they constitute a major nuisance.

To create a smoother experience, you can import these COM APIs in such a way that variants are represented using the type dynamic. In other words, from your point of view, COM signatures have occurrences of dynamic instead of object in them.

This means that you can easily access members directly off a returned object, or you can assign an object to a strongly typed local variable without having to cast. To illustrate, you can now say

excel.Cells[1, 1].Value = "Hello";

instead of

((Excel.Range)excel.Cells[1, 1]).Value2 = "Hello";

and

Excel.Range range = excel.Cells[1, 1];

instead of

Excel.Range range = (Excel.Range)excel.Cells[1, 1];

Why is this a big deal? One reason is that it simplifies the programmer's work. Code from Microsoft Office is tremendously difficult to read. Take a look at this code block from an Office application I wrote for the VSTO For Dummies book:

Office.CommandBars commandBars = default(Office.CommandBars);
Office.CommandBar commandBar = default(Office.CommandBar);
Office.CommandBarButton runStoreReport = default(Office.
   CommandBarButton);
commandBars = (Microsoft.Office.Core.CommandBars)Application.
   CommandBars;
commandBar = commandBars.Add("VSTOAddinToolbar", Office.
   MsoBarPosition.msoBarTop, , true);
commandBar.Context = Visio.VisUIObjSets.visUIObjSetDrawing +
   "*";
runStoreReport = (Microsoft.Office.Core.CommandBarButton)
   commandBar.Controls.Add(Office.MsoControlType.
   msoControlButton);
runStoreReport.Tag = "Store Report";
runStoreReport.Click += VisualizeSales;

Here's what the code block looks like in C# 4.0:

Office.CommandBars commandBars = Office.CommandBars;
Office.CommandBar commandBar = Office.CommandBar;
Office.CommandBarButton runStoreReport = Office.
   CommandBarButton;
commandBars = Application.CommandBars;
commandBar = commandBars.Add("VSTOAddinToolbar", msoBarTop, ,
   true);
commandBar.Context = Visio.VisUIObjSets.visUIObjSetDrawing +
   "*";
runStoreReport =commandBar.Controls.Add(msoControlButton);
runStoreReport.Tag = "Store Report";
runStoreReport.Click += VisualizeSales;

It's a lot simpler to read. Keep in mind, though, that all those casts still exist — they are just handled by the compiler. Microsoft didn't redo the Office components into .NET; the company just made the compiler communicate better. The compiler still builds code that speaks to the primary Interop assemblies as they are.

Working without Primary Interop Assemblies

Speaking of PIAs (excuse the similarity to another well-known, three-letter acronym), they are handled a lot better in .NET 4.0 in general.

PIAs are large .NET assemblies generated from COM interfaces to facilitate strongly typed interoperability. They provide great support at design time, where your experience of the Interop is as good as if the types were really defined in .NET. However, at runtime these large assemblies can easily bloat your program and also cause versioning issues because they are distributed independently of your application.

The no-PIA feature allows you to continue to use PIAs at design time without having them around at runtime. Instead, the C# 4.0 compiler bakes the small part of the PIA that a program actually uses directly into its assembly. The PIA doesn't have to be loaded at runtime.

To see how this works, try these steps in both Visual Studio 2010 and Visual Studio 2008 (if you have it):

  1. Create a new console application by choosing File

    Working without Primary Interop Assemblies
  2. After the project loads, right-click on References.

  3. Click Add Reference.

  4. Select Microsoft.Office.Interop.Excel, version 12, if you have it. Otherwise, use the latest version you have loaded.

  5. Click OK.

  6. Add using Microsoft.Office.Interop.Excel; to the header.

  7. Change the Main procedure to the following (just enough to get Excel rolling):

    static void Main(string[] args)
    {
        Microsoft.Office.Interop.Excel.Application
    xl = new Application();
             xl.Quit();
    }
  8. Right-click on the Solution and select Add Project.

  9. Add a new Setup project.

  10. Right-click on the Setup project and choose Add

    Working without Primary Interop Assemblies
  11. Select Primary Output.

  12. Click OK.

The setup project will automatically determine what to deploy with the application. In Visual Studio 2008, with C# 3.0, it will deploy the primary Interop assemblies, as shown in Figure 3-1.

In Visual Studio 2010, the setup doesn't deploy the PIAs. The specific parts being used are compiled right into the EXE for the application. This is demonstrated in Figure 3-2.

Deploying the PIAs in C# 3.0.

Figure 3-1. Deploying the PIAs in C# 3.0.

Deploying without PIAs in C# 4.0.

Figure 3-2. Deploying without PIAs in C# 4.0.

Skipping the Ref Statement

Because of a different programming model, many COM APIs contain a lot of reference parameters. Contrary to refs in C#, these are typically not meant to mutate a passed-in argument for the subsequent benefit of the caller but are simply another way of passing value parameters.

It therefore seems unreasonable that a C# programmer should have to create temporary variables for all such ref parameters and pass these by reference. So let's delete them.

Instead, specifically for COM methods, the C# compiler allows you to pass arguments by values to such a method and automatically generates temporary variables to hold the passed-in values, subsequently discarding these when the call returns. In this way, the caller sees value semantics and doesn't experience any side effects, but the called method still gets a reference.

You can see this in action in the canonical optional parameter example from Chapter 2. In the usual SaveAs from Microsoft Word, everything is a reference parameter.

object filename = "test.docx";
object missing = System.Reflection.Missing.Value;

doc.SaveAs(ref filename,
           ref missing, ref missing, ref missing,
           ref missing, ref missing, ref missing,
           ref missing, ref missing, ref missing,
           ref missing, ref missing, ref missing,
           ref missing, ref missing, ref missing);

In C# 4.0, you can skip both the "missing" optional parameters and the ref statement.

object filename = "test.docx";
doc.SaveAs(filename);
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.112.90