views:

714

answers:

5

Say we have an existing process (or application) that calls a COM object from an ocx file such as "MyCOMLibrary.ocx".

Is there a way to write a C# library to exactly replicate the ocx file? So that the original application can call your C# code rather than the original COM object?

You would, of course, have to use identical CLSID and ProgIDs as the original ocx. And assuming there is no signing involved, such as a SNK in the .Net world.

Also, are there any tools that exist to automate this? Something that takes in an ocx and spits out a C# file with methods to implement.

EDIT: I want to add that the original application is VB6, and does not use .Net at all. They are most likely loading the ocx as a VB6 app would (ProgId or Guid). Does this cause any issues?

We also have no problem with completely rewriting the ocx--we will most likely just return success error codes for all methods and only use methods/events required by our situation.

EDIT: You would think this would not be too difficult to accomplish. Can we make a VB6 ocx file that could replace the old ocx, and just pass all calls to a .Net assembly?

EDIT: I tried using the following open source library: EasyHook

But it seems like this question should still be viable. VB6 seems to load COM objects in a way that prevents hooking. I don't see a way to hook instance methods on a class/interface or a class's constructor with EasyHook.

+2  A: 

You can use ActiveX Import AxImp to import the OCX, create a wrapper class and then call that. The program is described here: http://msdn.microsoft.com/en-us/library/8ccdh774%28VS.80%29.aspx Basically, what you need to do is execute the following on the commandprompt:

c:/>AxImp MyControl.ocx

result is a MyControl.dll and an AxMyControl.dll. The first you can use as a normal .NET DLL in your projects (i.e., without a graphical user interface), the second can be used to be drawn on a form as you normally would with any other control like a TextBox or a Label.

To use it, go to Visual Studio, rightclick your project and select Add Reference. Browse to the newly created DLL and add it. That's all.

Abel
TlBimp.exe, does the same thing without spitting out the ActiveX control. You do realize, I'm trying to replace the COM object not call it, right? I can see where I could open the resulting Interop.??.dll in Reflector and export it as a C# file to implement the methods. Is this what you mean?
Jonathan.Peppers
You can only replace a binary COM object completely (i.e., without wrapper) if you have the source: convert it to .NET. The .NET architecture and COM are very different. You can create COM with .NET and you can import COM for .NET. But a COM binary itself is not CLR compliant in any way and cannot be converted to .NET itself without rewriting.
Abel
On: "Is there a way to write a C# library to exactly replicate the ocx file" the answer is: yes, but only as full rewrite (use `ComVisible` et al). It may be possible to add the OCX and the wrapper as a resource and divert the `AppDomain` Assembly loading process by registering to the ``AssemblyLoad event. But this gets very complex and requires in-depth understanding of `Domain`, assembly loading and possibly dynamic OCX wrapping.
Abel
The existing app is VB6, is there anything we need beyond using ComVisible, Guid, ProgId on our class and using RegAsm to register our assembly (of course we'd unregister the original one). We have not gotten this to work.
Jonathan.Peppers
There are some post that discuss the whole process. Here's one: http://foxsys.blogspot.com/2007/03/activex-controls-in-vs2005-and-c-part-1.html have you gone through all these steps?
Abel
The only thing extra we weren't doing was adding a strong name to our assembly and sticking it in the GAC. We still get a generic popup: "OurOcx.oxc is not registered" from the VB6 app when it loads.
Jonathan.Peppers
+1  A: 

Apparently VBMigration Partner can automatically upgrade a VB6 COM component to a VB.Net component that has binary compatibility with the original VB6 component. I don't know whether it supports OCXs. If it does, I'd suggest use that first and then try to go to C# later (if necessary).

MarkJ
A: 

Moved to new question: New Question

Jonathan.Peppers
A: 

Our Deviare Hook Library can be used for hooking COM objects. You can see an article from our blog related to this topic: Hooking Outlook COM objects with Deviare

sw
A: 

Not really a complete answer to the question, but something I think might be useful. If you add a key called 'TreatAs' under the CLSID of the object you want to replace and set the default value to the CLSID of the object you want to create instead, this instructs the COM runtime to create your object instead of the original one. No need then to force your new, replacement object to have the same CLSID and ProgID of the old one.

For example, if your original object had ProgID "MyComLibrary.Object" and CLSID "{ABC}", and your new object has ProgID "MyDotNet.Object" and CLSID "{123}", then under HKLM/CLSID/{ABC} add a key called TreatAs with a default value of {123}. Then any request for "MyComLibrary.Object" or "MyDotNet.Object" will get a copy of the new object (assuming they implement the same interfaces).

Eddie Deyo
In our final solution we implemented a C# COM object that was binary compatible and set it up for the target application with Reg-Free COM. So our target application loaded our assembly through COM, thinking it was still talking to the original COM object.
Jonathan.Peppers