none
How to publish COM Class/Interface from managed EXE RRS feed

  • Question

  • What I'm trying to do doesn't sound all that unusual to me, but I can't seem to find much about this.  I have defined a class with one interface which I wish to publish as COM visible.  Further, I am publishing this from an EXE, not a dll.  So here's what I did.  I defined a class and an interface (see below) in an assembly that is built as an EXE.  The ultimate goal is that it will run as system service, but for now it's a console app until I can get this to work.  In the main routine of the EXE, I use RegistrationServices.RegisterTypeForComClients().

    First problem is that RegAsm does create the LocalServer32 registry key, but rather always creates InprocServer32.  I renamed the key and that seems to work.  Second problem is that RegAsm does not do anything with the interface (IFoo) or its GUID.  RegistrationServices.GetRegistrableTypesInAssembly() only lists the class.   In my client app (also C#) I use the ComImport attribute with the CLSID_GUID, and I also declare the Interface IFoo with its IID_GUID.   When I instantiate MyClass (e.g.  MyClass cl = new MyClass()), I do indeed get a CoClass representing the class implemented in the server (if the server's not running I get an error, and if I don't register the server I get an error - as expected).  However, when I try to cast that class to the interface type (e.g.  IFoo pi  = (IFoo)cl), all I can get is a cast exception with COM error E_NOINTERFACE.  This does not surprise me since it looks to me like COM doesn't know anything about the interface IFoo because RegAsm didn't register it.

    So, the question is:  What's going on here and how do I make it work?  Below is the code for the server side.

     [ComVisible(true)]
     [Guid("D14AD5C8-83D8-4797-B0F3-8B1DA69EDF82")]
     public interface IFoo
     {
      bool Function1(string aParameter);
      bool Function2(string anotherParamater);
     }

     [ComVisible(true)]
     [ClassInterface(ClassInterfaceType.None)]
     [Guid("C08E6A75-0E26-43eb-9947-666B67D5077B")]
     public class MyClass : IFoo
     {
      public MyClass()
      {
        // do some constrcutor stuff
      }

      public bool Function1(string aParameter)
      {
        // do some stuff and return the result
      }

      bool Function2(string anotherParamater)
      {
        // do some different stuff and return the result
      }
     }

    Monday, March 29, 2010 6:38 AM

All replies

  • Where do you do your casting to IFoo? In C++, C# or some other language?

    Anyway according to this tutorial example it works (from C++).

    Re: LocalServer32 vs. InprocServer32 - according to this blog post it should really work.

    -Karel

    Tuesday, March 30, 2010 5:44 AM
    Moderator
  • Thanks, Karel, for the reply.  Everything is C#.  I had already read both of those COM tutorials – that’s how I got as far as I got.

    I went ahead and implemented the solution from the blog post on AntiMail.  Unfortunately, he didn’t supply a very helpful client side example.  Anyway, what I got was exactly the same problem as I had before, except now I can see the inner workings of what’s going on.  When I call new CMyClass from my C# client, I can see in the server that it enters the CreateInstance function in the class factory, passing in the IID for IUnknown.  The class factory checks the IID and accepts it if it’s either the GUID for IMyInterface or IUnknown, and then it does this:

        ppvObject = Marshal.GetComInterfaceForObject(
            new CMyClass(), typeof(IMyInterface));

    Back on the client side, I get my new object.  I then try to cast it to IMyInterface with the same result – E_NOINTERFACE.  I can see where this might be a problem since the server does not seem to implement QueryInterface.  On the other hand, it has returned an object that should implement IMyInterface even though the IID passed into CreateInstance was for IUnknown.  The problem is there’s no way to expose that interface on the client side.  I can’t declare the class with member functions or else the compiler wants me to supply the body.  Similarly, I can’t have the class inherit from IMyInterface for the same reason.  There’s still something missing here (presumably on the server side), but I don’t know what it is.  Here’s my client side code for consuming the example COM server’s class:

    [Guid("F9F8CBB8-1D9E-4d26-82DA-EFE4E6C6BB0A")]
    interface IMyInterface
    {
     string GetDateTime(string prefix);
    }

    [ComImport]
    [Guid("6A6272F9-CFA7-4580-BED4-9253BA76B5D5")]
    class CMyClass
    {
    }

    CMyClass c = new CMyClass();  // create the CoClass
    IMyInterface pI = (IMyInterface)c; // get the interface  (results in E_NOINTERFACE)
    string str = pI.GetDateTime("My Prefix");

    Tuesday, March 30, 2010 5:48 PM