Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Variants and COM

0.00/5 (No votes)
11 Oct 2007 1  
Tips on using Variants with COM

Introduction

COM is a good technology, but using COM with .NET can become a hair hazard as you rip it out in frustration. Too many COM components use Variant data types. Oh, how I hate Variants. I never found Variants acceptable in Visual Basic and they are just plain problematic with strongly typed languages. I like strongly typed languages; I want to know exactly what data types I am working with. I believe that Variants were a big mistake, a mistake that is now difficult to work with, especially since COM components are still widely used.

This article provides tips when using Variants with COM Interops in C#. I needed to interact with a COM component to a proprietary database. This COM component was only supported on Visual Basic 6.0. Because my application required the use of Web Services, I did not want to implement the Web Services in Visual Basic. So, I tried to force the COM to work in C#. To my amazement, it worked extremely well. The problem was not the technology, but rather the documentation.

Prior to working on the project that led me to write this article, every time I saw a project that could use COM and .NET I either tried really hard to avoid COM or pumped extra money into the budget on handling COM. Now, after working on that project, COM and .NET do not scare me as much anymore. Hopefully, after you read this article, you will not have the same fear of COM and .NET that I had and you will not make the same mistakes that I did. I really hope that some of these tips will work for you.

Background

The easiest method of creating your COM Interops is to let Visual Studio do it for you. These instructions are for Visual Studio 2003. They may be slightly different on newer versions of the IDE.

  1. Create a new project.
  2. From Solution Explorer, right click on References and select Add Reference...
  3. The dialog box below will appear. Click on the COM tab.
    Add Reference
  4. Go through the COM components, double click the ones that you want and then click OK.
  5. In Solution Explorer, you will now see the COM Interop libraries under References.

That was easy, wasn't it? Now all you need to do to use those Interop libraries is to employ the using statement in your classes. Microsoft did this right.

Specifications

The COM component that I was using came with documentation. It was good documentation if you were using Visual Basic, but a bit frustrating if using C#. This was their documentation (without the bulk of the function description):

Syntax
ReturnCode = 
    RecipeVar.GetRecipeHistory(NumVersions, Dates, Authors, Comments)

where

Parameters        Data Type     Description
NumVersions       Integer       Number of recipe versions available.
Dates             Variant       Array of dates for each recipe version.
Authors           Variant       Array of authors for each recipe version.
Comments          Variant       Array of comments for each recipe version.

The Interop's method through Object Browser was defined as:

GetRecipeHistory(ref short, ref object, ref object, ref object)

Initialization

Microsoft's .NET Framework SDK Documentation states that:

An argument passed to a ref parameter must first be initialized. 
Compare this to an out parameter, whose argument does not have to 
be explicitly initialized before being passed to an out parameter.

The documentation stated that when using ref, the parameter needed to be initialized as compared to out, which does not need to be explicitly initialized. The problem is that these objects are arrays and the exact data type cannot be pre-defined. It will compile, but when you run the application, an exception will be generated stating that the wrong data type was referenced. Where I believe the documentation fails is that you can initialize the variable to null. Initializing a variable to null is considered initialization. I guess that seeing the words "explicitly initialized" in the sentence right after "initialized" made me think that the memory for the variable needed to be allocated through an instantiation. Thus, the usage is:

int numVersions = 0;
object dates = null;
object authors = null;
object comments = null;
bool err = recipe.GetRecipeHistory(ref numVersions, 
    ref dates, ref authors, ref comments);

Collections

Now that I've got the data, how can I use it? Well, the COM documentation stated that it was an array, so I can use the array to get the data out.

string[] arr = new string[numVersions];
Array.Copy(comments, arr, numVersions);

With the power of .NET, I can also use some other components

string[] arr = new string[numVersions];
System.Collections.ICollection collection = 
    (System.Collections.ICollection) dates;
int i = 0;
foreach(object o in collection) 
{
    arr[i++] = "" + i + "\t" + o.ToString();
}

Conclusion

This article illustrated some methods for using Variants with C#. I spent many hours on the web Googling all sorts of combinations of Variants, COM, .NET and C# and I could not find an answer. The solution that I showed here may not work with your COM components, but giving them a go may be worth a try and save you some time. Happy coding.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here