none
Out-of-process invocation of .NET COM visible object does not work RRS feed

  • Question

  • Hello everybody,

    we have an unmanaged MFC / C++ application (.exe), that exposes it's object model via COM / automation like the MS office applications do. This is used by clients written in LabView, C++, VB6, etc. to automate the application, via COM / DCOM. Moreover it is possible to automate the application with a built-in Visual Basic like editor and programming language (SAX basic).

    During our effort to slowly migrate to .NET we decided to develop an new software component (.NET assembly, .dll) that controls external hardware in C# and use it in the unmanaged C++ application using COM interop. I.e. the component is COM visible and exposes it's (rich) object model via COM. We expose the object model of the component through our application object model (a property of an object in the application model returns a type from the component). This works fine when accessed from the built-in, in-process basic engine.

    The problem is, that this scenario does not work when using an out-of-process client (managed or unmanaged). The managed client (C# .exe) references the primary interop assembly of the main application and is able to start and control the main application. It references the assembly of the new managed software component, not the COM type library and generated interop assembly, because Visual Studio does not allow this:

    A reference to 'D:\STDev\Polytec.IO\Include\Polytec.IO.Vibrometer.tlb' could not be added. The ActiveX type library 'D:\STDev\Polytec.IO\Include\Polytec.IO.Vibrometer.tlb' was exported from a .NET assembly and cannot be added as a reference. Add a reference to the .NET assembly instead.

    When we first access the property in the application object model, that returns an object from the managed component we get an invalid cast exception:

    System.InvalidCastException was unhandled
      Message="Das Objekt des Typs \"System.__ComObject\" kann nicht in Typ \"Polytec.IO.Vibrometer.ControllerGroup\" umgewandelt werden."

    If we use an unmanaged client (C++ .exe), that #imports the type library of the application and of the managed component, we get an access violation as soon as we call into one of the methods of the managed component.

    So my question is: is this scenario supported? Is there any workaround for the problem?

    If an RCW can apparently use DCOM to communication with an unmanaged out-of-process server (our main application) why can't a CCW created from a managed COM object be accessed via DCOM?

    I have reproduced the described scenario and errors with a small sample, that I can provide on request:

    ManagedCOM.dll (C#) is used by UnmanagedServer.exe (ATL/C++) using COM interop and exposes an object of ManagedCOM through it's object model. UnmanagedClient (C++ Win32 .exe) crashes with access violation, ManagedClient (C# Win32 .exe) gives invalid cast exception when accessing the object.

    Thanks for any help.

    Best regards,
    Bernd

     

    Tuesday, May 19, 2009 3:44 PM

All replies

  • COM requires a proxy/stub to marshal the call across the process boundary.  That's generally not a problem for an unmanaged COM server, MIDL automatically generates the source code.  But there's no MIDL for a .NET server.  If you are just reusing your old unmanaged proxy/stub DLLs, that would likely explain the crash.

    Hans Passant.
    Tuesday, May 19, 2009 9:33 PM
    Moderator
  • Hans,

    as I have reproduced the problem with a small sample application with all new IDL files and interface definitions (managed and unmanaged), I am sure, that I am not using any outdated proxy/stub dll's. We are using only automation compatible data types so the default proxy/stub implementation is enough to run our application. We do not have any custom proxy/stub dll's.

    Any other suggestions?

    Regards,
    Bernd
    Wednesday, May 20, 2009 6:25 AM
  • There is no default proxy/stub implementation.  Using the standard marshaller requires making late-bound calls through IDispatch and restricting argument types to OLE Automation compatible types.  Was any of this done?

    Hans Passant.
    Wednesday, May 20, 2009 10:46 AM
    Moderator
  • Hans,

    sorry for being not precise: we are using the standard (universal, automation) marshaler with OLE Automation compatible types, therefore we have no proxy/stub dlls.

    I am not sure, if this means that we are using late binding, though. In the unmanaged client I am using #import to get the type-library in and make calls through the generated C++ classes (not explicitly through IDispatch), in the managed client I reference a primary interop assembly. So it feels like early-binding.

    Bernd
    Wednesday, May 20, 2009 2:29 PM
  • Yes, that's an early bound call.  Using the std marshaller for early bound calls is technically possible through type library marshaling.  You would have to add the registry entries in the HKCR\Interfaces key by hand.  On my machine, HKEY_CLASSES_ROOT\Interface\{00020863-0000-0000-C000-000000000046} is an example.  You'll need to add the IIDs that the managed interfaces use.  I've never done this myself, good luck.

    Hans Passant.
    Wednesday, May 20, 2009 3:42 PM
    Moderator

  • Hans,

    I should have mentioned, that we are creating the type library for the managed COM object, embed it as a ressource into the assembly, install the assembly to the GAC and then register the type library.

    I have checked the registry entries for the ProxyStubClsid / ProxyStubClsid32 of the relevant interface and they look as expected:

    Windows Registry Editor Version 5.00

    [HKEY_CLASSES_ROOT\Interface\{4984B892-B2CC-3ED1-8132-312380D04BB9}]
    @="ITestObject"

    [HKEY_CLASSES_ROOT\Interface\{4984B892-B2CC-3ED1-8132-312380D04BB9}\ProxyStubClsid]
    @="{00020420-0000-0000-C000-000000000046}"

    [HKEY_CLASSES_ROOT\Interface\{4984B892-B2CC-3ED1-8132-312380D04BB9}\ProxyStubClsid32]
    @="{00020420-0000-0000-C000-000000000046}"

    [HKEY_CLASSES_ROOT\Interface\{4984B892-B2CC-3ED1-8132-312380D04BB9}\TypeLib]
    @="{B1CEC20C-3279-4BBC-91B1-DF54DB26E42B}"
    "Version"="1.0"

    I did some more experiments within the unmanaged client:

    - calling the method of the managed COM object out-of-process via IDispatch->Invoke() works.
    - Marshalling the interface of the managed COM object in the unmanaged server, passing it to the unmanaged client in a safearray and unmarshaling it in the unmanaged client, works too (CoMarshalInterface / CoUnmarschalInterface succeeded, and I am getting an Interface pointer). But the early-bound call to the method crashes as before.
    - It seems, that simply the entry in the v-table of the interface pointer for the method of the managed COM object is 0, which is the cause for the access violation.

    Any other suggestions?

    Regards,
    Bernd

    Monday, May 25, 2009 11:37 AM