Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling COM visible managed component from managed code through COM wrapper

I have a 3rd party component, lets say FIPreviewHandler to handle preview, which implements IPreviewHandler. FIPreviewHandler is implemented as a Managed Component, and uses the IPreviewHandler interface and related interfaces through means of an interop. FIPreviewHandler is registered using regasm.exe as COM.

I have a client application which is also Managed. I want to create an instance of FIPreviewHandler as a COM component in my application.

I have an interop assembly that defines IPreviewHandler and related interfaces.

When I create an instance of FIPreviewHandler, using Activator.CreateInstance(), on a type returned by GetTypeByCLSID(), which uses the correct CLSID for FIPreviewHandler, it returns me a managed instance, as it has the actual assembly available, and skips COM. When I try to QI/cast this instance as any of the interfaces, IPreviewHandler for example, it returns null because, it is loaded as a managed object, and although the IPreviewHandler interface implemented by FIPreviewHandler is the same interface as I have in my interop, but its in a difference namespace/assembly, hence null. If it were to return me a COM instance/RCW (System.__ComObject), it would not take namespace into account, and would cast fine, and return a valid instance.

FIPreviewHandler is a 32 bit component, and on a 64bit Win7 machine, if I compile my client application as "Any CPU", Activator.CreateInstance() returns a COM instance/RCW (System.__ComObject), as it cudnt find a 64bit implementation of FIPreviewHandler, hence returns a proxy. In this scenario, my application works fine. But when I compile it for x86, it gets the 32bit implementation, and returns a managed instance of the actual managed class, and not a COM instance, hence fails.

I cannot use the interfaces defined in FIPreviewHandler's assembly, as I have to write a generic client for IPreviewHandler, and my application will work with any component implementing IPreviewHandler, which would work great for C++ based clients accessing FIPreviewHandler as a COM object, but is failing for Managed clients.

I hope I make sense and I would be really grateful for any help.

like image 660
shaibee Avatar asked Jun 25 '10 16:06

shaibee


2 Answers

So clearly this a fail on .NET's part as I'm finding there is no way to use a COM wrapper around a managed COM object.

The "solution" (and I use that term very loosely) is the use of a PIA or 'Primary Interop Assembly'. The PIA provides a single strong-named assembly imported with TlbImp.exe that is GAC registered. Basically I guess we then must rely on GAC publisher policies to force clients to the correct interface assembly.

see also

http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/b11a0f90-fcc5-487a-b057-632f5415bfc2

http://www.codeproject.com/KB/COM/BuildCOMServersInDotNet.aspx

like image 161
csharptest.net Avatar answered Oct 13 '22 01:10

csharptest.net


Man, if I were you, I would just make the wrapper myself, only when the type is NOT a COM type. To know if the type created is a COM type, use the IsCOMObject from the Type of the object:

myObject.GetType().IsCOMObject

If this is FALSE create a wrapper, that uses reflection to call the managed type. Reflection is slow, but you can cache the MethodInfo objects that you get... otherwise you can generate IL code, and create a wrapper that will have no reflection at all.

Of course there are other methods, of doing it... this is up to you.

As I am in love with dynamic run-time IL generation, I can provide you with a code that does this... if you are interested!

like image 35
Miguel Angelo Avatar answered Oct 13 '22 01:10

Miguel Angelo