tags:

views:

83

answers:

2

I have existing managed and unmanaged software using an ActiveX component supplied by a third party to perform some communications, but it is now required that this communication be routed through my application.

Ideally I'd be able to install a .NET component which will expose exactly the same interface, and will be usable as a drop-in replacement.

However, I am running into the limits of my understanding of COM, which admittedly is quite minimal.

  • How best to ensure that my implementation of the interface is 100% binary compatible with the existing object?

  • How do I ensure that applications use my implementation of the interface instead of the legacy implementation? Is it simply a matter of registering my implementation, and unregistering the legacy one?

  • How do I ensure it's a "drop-in" replacement, and requires no changes to existing software?

  • How do I ensure unmanaged code can use it without issue?

Note: I am able to require that .NET 4.0 be used, if that will make things simpler.

Edit: Bounty will be moved here http://stackoverflow.com/questions/3280273/how-to-debug-why-a-vb6-application-using-my-net-activex-control-does-not-registe after 2 days.

+3  A: 
  1. Use the type library of the ActiveX component. Import it with Tlbimp.exe to get the interop library, you probably already have it if you use this component yourself. Implement your own code by inheriting the interfaces in that type library.

  2. Your implementation must use the exact same GUIDs and ProgIDs as the ActiveX component. Use OleView.exe, File + View Typelib and select the ActiveX DLL to see the GUIDs. The ProgIDs are more difficult, best thing to do is to watch how the registry is modified with the SysInternals' ProcMon utility when you register the ActiveX DLL with Regsvr32.exe. Ultimately, the exact same changes need to be made by Regasm.exe when you register your replacement.

  3. As point 2.

  4. Same, the registration gets unmanaged code to use yours instead.

To make this work out well, you really have to know what the interfaces do. You cannot make this work if the ActiveX component is actually an out-of-process server (an EXE).

Hans Passant
Thanks, this is exactly the kind of response I was hoping for. As it happens, the component is shipped as a .ocx. As a matter of interest, what is different about an out-of-process server that makes it hard/impossible to implement using .NET?
Leon Breedt
The marshaling is a problem, you can't get .NET to generate the proxy/stubs you'd need. Then again, if you do it exactly right then you could use the ones from the original component. Not an issue with a .ocx
Hans Passant
A: 

Well, I've gotten a lot further along with this, but I seem to have encountered an intractable problem.

The object I am replacing uses COM events. When one of the client applications (VB6 I believe, as depends.exe tells me it uses msvbvm60.dll) instantiates and uses my replacement, it does not register for any of the events, and unfortunately, the way it works is that after a particular method call has completed, the client application does nothing until an event fires.

Note: My replacement ActiveX control inherits from System.Windows.Forms.Control, and sets MiscOptions of 131457 on the coclass registry entries as suggested by http://ondotnet.com/pub/a/dotnet/2003/01/20/winformshosting.html, the reason being that the thing I am replacing was an honest to goodness ActiveX control, and I could not get these existing clients to instantiate my object successfully without any code changes at all until I inherited from WinForms control.

I have tried the approach where my coclass declares public events with the same name as the interface specified by ComSourceInterfaces, this works 100% from a C# app that uses AxHost, events are triggered.

I have also tried instead to implement IConnectionPointContainer and all supporting interfaces on my replacement control, and this works 100% from a C# app, but in the VB app, it never actually attempts to Advise() the connection point of the client sink interface to call, it only calls Unadvise() with an invalid cookie value of 0.

One issue with the typelib that I have noticed is that I cannot get tlbexp.exe to export one of the properties on the coclass interface as OLE_HANDLE, it just ends up being a long in the TLB generated from the assembly (this TLB is referenced by the TypeLib entry in the registry). Could this cause issues with eventing?

Any ideas how to debug this?

Leon Breedt
You should ask this as a different question, not as an answer. Otherwise it's difficult for people to answer.
Amnon
Good idea, will do.
Leon Breedt