Search code examples
c#.netcom

How do I add support for typed calls to a remote COM+ application


I am in the process of replacing a COM+ hosted application with a .Net variant.

The steps I took are roughly:

  • Generate an Interop assembly of the old dll
  • Create a new class in C# .Net that derives from ServicedComponent and implements the IMyClass interface from the interop.
  • I have annotated the class with a [Guid("...")] and a [ProgId("...")] attribute to match the class in the old dll

The end result looks like this:

[ProgId("MyComponent")]
[Guid("...")]
public class MyClass : ServicedComponent, IMyClass
{

    public MyClass()
    {

    }

    public object Open(string arg1, string arg2)
    {
        /* trace arguments*/
    }

    public object Run()
    { 
        /* implementation here */ 
    }

    public void Close()
    {
        return;
    }
}

This assembly is installed on a remote machine using regsvcs.exe

Now most clients use code similar to this unittest code:

Type typeFromProgID = Type.GetTypeFromProgID("MyComponent", "remoteMachine", true);
dynamic comInstance = Activator.CreateInstance(typeFromProgID);
comInstance.Open(string.Empty, string.Empty);
comInstance.Run();
comInstance.Close();

This works perfectly, the .Net tracing on the remote machine tells me everything is working as it should. Other clients use code similar to this:

Type typeFromProgID = Type.GetTypeFromProgID("MyComponent", "remoteMachine", true);
MyClass comInstance = (MyClass)Activator.CreateInstance(typeFromProgID);
comInstance.Open(string.Empty, string.Empty);
comInstance.Run();
comInstance.Close();

The first line is the same and seems to work fine, the rest acts weird. The VS debugger shows the lines are being executed. The remoteMachine shows that no methods are being executed.

The last call to Close(), which actually just returns, throws an exception:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. Result StackTrace: at Interop.MyComponent.IMyClass.Close() at UnitTestProject1.UnitTest1.temp()

What have I missed in my implementation to support this last (typed) scenario?


Solution

  • This sounds like mismatched metadata, e.g. marshaling is different between the one that happens with the original type library and the one that happens with your server registered .NET assembly.

    My guess is that the untyped case runs well because it depends solely on IDispatch, which .NET implements quite well, but the typed test fails (and I'm surprised it doesn't fail earlier) because of this mismatch.