4
votes

First, I realize that there are many posts here that discuss this topic. I must have read 20+ of them, easily. But none of them give the answer that I seek.

I have written a tiny C# test COM DLL with a single method in it that prints "I am alive!" in a message box. Using VStudio as admin, I can build and register the COM object. I have successfully called the object from VBA and run the method. And I can see the name of the COM Interface in the VStudio Add Reference / COM dialog box. This all makes me think the object is properly constructed, registered, and usable.

Now I'm trying to call it from a console C# app. Like many others, I'm trying to figure out the equivalent of the VBA "CreateObject("DLLName.ClassName")" code to get hold of the object in C#.

One way is to just add a reference to the DLL to my console app project. I point to the assembly through the Projects section of the Add Reference dialog, not through the COM section of the dialog. Then I can simply say var o = new MyComImplementationClass(); and treat it like any other class. That works, but it means my console app is cheating and not using the COM object through the usual COM GAC interface.

Another way (that doesn't work, but I wish it did), is to add the reference through the COM tab on the Add Reference dialog. I can see it but VS protests that "the XXX.tlb file was exported from a .NET assembly. Add a reference to the assembly instead." Which brings me back to the solution above, which I think means that my app is cheating. (I didn't have to add references to my VBA test app, for example.)

Another way is to use Type.GetTypeFromProgId as shown by this code fragment below. But I can't get that to work either. I must be passing in the incorrect ProgID string - I get the sense it has something to do with registry info and is not the same "DLLName.ClassName" string that I feed CreateObject() in VBA.

  public static dynamic ComObjectGet () {
    const string progID = "ComExampleDLLName.ComImplementationClassName";
    Type foo = Type.GetTypeFromProgID (progID);
    dynamic COMobject = Activator.CreateInstance (foo);
    return COMobject;
  }

Worse yet, on this MSDN example page it says "This method is provided for COM support. Program IDs are not used in Microsoft .NET Framework because they have been superseded by the concept of namespace." So probably I should not be using the GetTypeFromProgID at all.

If it helps any, I can use VSTO in C# to call the MSOffice primary interop assemblies. But they load from the COM tab of the add reference dialogs (which is where I want my COM library to load from).

For clarity, my COM DLL name is ComExampleLibrary.dll. The default namespace is ComExampleNamespace. The interface name is IComInterface, and the implementation classname is ComImplementation. The internal method name is Run.

Could someone give me instructions or a code snippet that does the "right, approved" thing for calling COM objects (not just the ones I write) from C#? Thank you.

1
Instead of Type.GetTypeFromProgID, you might also use Type.GetTypeFromCLSIDKlaus Gütter
I understand that you want to deploy your COM into GAC and be able to add it from VS>Reference>COM>ComExampleLibrary.dll, is this right ?Clint
Using dynamic will work. You can force the progid using ProgIdAttribute otherwise it's automatically generated: docs.microsoft.com/en-us/dotnet/api/… but why do you want to use COM to call C# objects from C# objects in the first place?Simon Mourier
@KlausGütter, thank you, GetTypeFromCLSID works because I have the GUID of the COM implementation class that I wrote. But is that cheating too? I want to add a reference to the COM object listed in the COM section of the AddReference dialog like I would for any other COM object.Kevin
@Clint, yes, you understand correctly. I want to treat my little COM object like any other COM object in the list of COM objects in the VS>AddReference>COM>* section. But I get that error message about "the .tlb has been exported from a .NET assembly; Add a reference to the assembly instead."Kevin

1 Answers

7
votes

Thanks to the people who helped me out, here is the answer. Both GetTypeFromProgID and GetTypeFromCLSID work as shown below. My problem was that I was using "AssemblyName.ClassName" instead of "Namespace.ClassName" in the call to GetTypeFromProgID.

 public static dynamic ComObjectGet () {
    const string progID = "ComExampleNamespace.ComImplementation";
    Type foo = Type.GetTypeFromProgID (progID);

    //var bar = Guid.Parse ("99929AA7-0334-4B2D-AC74-5E282A12D06C");
    //Type foo = Type.GetTypeFromCLSID (bar);

    dynamic COMobject = Activator.CreateInstance (foo);
    return COMobject;
  }

So my original code was correct, but I was passing in the wrong argument. This snippet is the equivalent of the VBA CreateObject("Namespace.ClassName") call.

I still don't know why I cannot add a reference to the COM item in the COM tab of the Add Reference dialog like I would for any other COM object. I suppose that's a different question.