views:

958

answers:

3

I'm working the open source library EasyHook.

What I'm trying to do, is hook into when a VB6 app calls CoCreateInstance from ole32.dll on a particular CLSID, return my own C# implementation for the object rather than the true COM object. My C# implementation derives from the same interface that tlbimp.exe spits out for the COM object I want to replace.

My hook works, and I'm able to hook into calls, log data about the call, and then p/invoke CoCreateInstance from C# to allow the VB6 application to run as normal.

I'm noticing that the COM object that I want to replace isn't passed through my hook.

Does anyone know how VB6 loads ocx files under the hood? Am I hooking into the proper native api call?

Or is what I'm trying to do impossible due to the nature of .Net?

UPDATE: An alternate solution is to write a COM object to replace the old one, but we cannot get this to work. Here is an old post that I closed on the subject: Replace COM object

UPDATE: After further inspection, we are able to regsvr32 /u the old ocx file and use regasm to register our .Net dll. We put a MessageBox in the constructor of our COM object and the VB6 app loads and pops the box, but it crashes as soon as it makes the first method call on the object.

I suspect that we have some method signatures wrong, also we are using what tlbimp.exe gave us when we ran it on the target ocx we want to replace. Is it possible that tlbimp is making changes to the signatures that is preventing VB6 apps from loading our assembly?

For example sometimes COM signature will look like:

HRESULT MyMethod(IUnknown* ppv);

And tlbimp.exe will give C# something like:

IUnknown MyMethod();

Which looks much cleaner to a C# developer. Does anyone know about this, or a good article that could explain how to write a "binary compatible" COM assembly from C# to replace an ocx file?

+2  A: 

Couple of comments: First, VB6 does not use CoCreateInstance on "local" classes, i.e. classes from the same project -- it calls "constructor" directly. Second, you have to hook CoCreateInstance on the import section of every dll/ocx the CLSID can be cocreated from.

A better way is just to register you "upgraded" COM component with the same coclass CLSID. This way it will be automagically used by the client app.

Edit: Or take a look at CoTreatAsClass function.

wqw
We have tried merely writing a C# COM component with the same CLSID and ProgID as what is used by the vb6 application, but it for some reason does not work. This question is really plan B, as I have not found a good example of directly replacing an ocx file with a C# dll. I'll put an edit to link to my old question.
Jonathan.Peppers
Also, I'd like to comment that EasyHook hooks all calls to a function within a process--no matter how many dlls or modules are loaded.
Jonathan.Peppers
My point is COM dlls/ocxes are loaded "dynamicly" so their import section has to "patched" during process lifetime. It's not a single task you do upfront. But you or EasyHook probably already takes care of this.
wqw
+1  A: 

If you have the source code for the original component, apparently VBMigration Partner can 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.

MarkJ
It looks like this tool takes source code and spits out source code. I don't a tool would be possible that upgrades compiled VB6 to VB.Net, VB6 decompiled comes out as assembler at best.
Jonathan.Peppers
@Jonathan: true, I am assuming the source code is available. Maybe that's overoptimistic.
MarkJ
OCX = ActiveX control DLL with its extension renamed to OCX. They're functionally the same. (However .net assemblies have more in them even if they export activex controls.)
Jason D
A: 

Moved to new question: New Question

Jonathan.Peppers