Versioned classes appears to be created by REGASM - how to use them? - com

When I register a .NET assembly enabled for COM interop using the REGASM tool, the tool creates a separate registry key for each component version. For example, I get:
HKEY_CLASSES_ROOT\CLSID\{myCLSID}\InprocServer32\1.0.0.0
HKEY_CLASSES_ROOT\CLSID\{myCLSID}\InprocServer32\1.1.0.0
etc.
Each of these registry contains roughly the same structure values as it is under HKEY_CLASSES_ROOT\CLSID{}\InprocServer32, except that the entries point to different locations, depending on the component version. The HKEY_CLASSES_ROOT\CLSID{myCLSID}\InprocServer32 apparently contains the latest registered version, and that's what COM consumers will normally use, of course, and they ignore the rest.
This structure apparently allows different versions of the component coexist on the same computer (I know it is against the originally specified COM rules). I would like to use it, but I could not find any documentation about it anywhere in the Microsoft documentation or Googling for it. Does anybody know? I am looking for something like CoCreateInstance/CoCreateInstanceEx with the version specifier.
Thanks

Related

Get importlib directives from type library

How can one programmatically determine which type libraries (GUID and version) a given native, VB6-generated DLL/OCX depends on?
For background: The VB6 IDE chokes when opening a project where one of the referenced type libraries can't load one of its dependencies, but it's not so helpful as to say which dependency can't be met--or even which reference has the dependency that can't be met. This is a common occurrence out my company, so I'm trying to supplement the VB6 IDE's poor troubleshooting information.
Relevant details/attempts:
I do have the VB source code. That tells me the GUIDs and versions as of a particular revision in the repo, but when analyzing a DLL/OCX/TLB file I don't know which version of the repo (if any--could be from a branch or might never have been committed to a branch) a given DLL/OCX corresponds to.
I've tried using tlbinf32.dll, but it doesn't appear to be able to list imports.
I don't know much about PE, but I popped open one of the DLLs in a PE viewer and it only shows MSVBVM60.dll in the imports section. This appears to be a special quirk of VB6-produced type libraries: they link only to MSVBVM60 but have some sort of delay-loading mechanism for the rest of the dependencies.
Even most of the existing tools I've tried don't give the information--e.g., depends.exe only finds MSVBVM60.dll.
However: OLEView, a utility that used to ship with Visual Studio, somehow produces an IDL file, which includes the importlib directives. Given that VB doesn't use IDL files, it's clearly generating the information somehow. So it's possible--I just have no idea how.
Really, if OLEView didn't do it I'd have given it up by now as impossible. Any thoughts on how to accomplish this?
It turns out that I was conflating basic DLL functionality and COM. (Not all DLLs are COM DLLs.)
For basic DLLs, the Portable Executable format includes a section describing its imports. The Optional Header's directory 1 is about the DLL's imports. Its structure is given by IMAGE_IMPORT_DESCRIPTOR. This is a starting point for learning about that.
COM DLLs don't seem to have an equivalent as such, but you can discover which other COM components its public interface needs: for each exposed interface, list out the types of their properties and their method arguments, and then use the Registry to look up where those types come from. tlbinf32.dll provides some of the basic functionality for listing members, etc. Here's and intro to that.

Will having two different versions of a DLL cause issues?

I have a vb6 program that needs to use MSOLAP80.dll to display its pivot tables properly. But because MSOLAP90.dll has some compatibility issues with this I cannot use MSOLAP90.dll and still have the pivot tables display.
I have registered MSOLAP90.dll and then registered MSOLAP80.dll again and everything seems to be fine. I however don't know if both are actually registered or if MSOLAP80.dll is the only one registered, because I have no reference point as to what is new in MSOLAP90.dll. Is it possible that both are registered and the program is just using MSOLAP80.dll and if there are programs that need MSOLAP90.dll then it will know to use that one?
I guess I am just confused about how registering DLL's work and if it is possible to have both of these registered at the same time. Can somebody help with an explanation?
If you want to know for sure which one is registered, you can:
Look at the References dialogue for a type library which matches your DLLs' paths.
Open up RegEdit, and search for MSOLAP80.DLL or MSOLAP90.DLL (uncheck "Match whole string only").
If you find references for both DLLs, then you are safe because you can bind to a specific version. If you find a reference to the wrong DLL, then unregister the wrong one, and register the right one.
COM originall only allowed one version of a set of CLSIDs (which uniquely identify classes), IIDs (which uniquely identify classes' interfaces) at any one time. It is possible to have more than one reference to a LIBID (which identifies a type library - a resource embedded in the DLLL) but they have to have different versions.
From Windows XP onwards, it became possible to do side by side DLL access in which an executable can access a specific version of a DLL, overriding the value in the registry. You need to embed or have a .manifest file in the same folder as the EXE file.
Unfortunately, the documentation for this seems to have disappeared from MSDN, and is only referred to by a couple of Knowledge Base articles:
http://support.microsoft.com/kb/828629
http://support.microsoft.com/kb/843524

COM surrogate for third party component

I'm writing a small DLL component that needs to access two third party components to combine data, one of which is 32 bit only and the other is 64 bit only. Both are registered with a TypeLib and are Automation compatible, so marshalling should not be an issue.
If I understood the documentation correctly, then there is no way to force loading in a surrogate unless the component also has an AppID and the DllSurrogate key; since both are third party components, I'm somewhat reluctant to modify their registration.
Is there a way to activate an object in a component without an AppID in a surrogate process from a DLL component that ideally does not have any extra dependencies, or can anyone explain to me why this would be a bad idea?
Yes, you can load a (for example) 32-bit only DLL in a surrogate, and access it from a 64-bit process, in the following manner. This will work provided there is a marshaller available, which there generally will be for a component with a typelib because they usually use the standard marshaller. It will not work if the object requries a custom prox/stub because 64 bit versions won't exist, or you wouldn't have this problem in the first place.
First you need an AppID. If the DLL already has an AppID, you should use that. You can find out by checking under the CLSID key for the CoClass you are interested in.
The example used here is the Capicom.HashedData and Capicom.EncryptedData classes. Capicom is 32-bit only.
You should use the 32-bit version of Regedit to do this, as it is a 32-bit component. If you have a 64-bit component you want to access from 32-bits, use the other one. (This is because of the registry virtualisation for the 32-bit compatibility layer- using the the matching bitness version of regedit takes care of this issue for you, by making sure you edit the correct virtualised version of the registry).
Windows Registry Editor Version 5.00
;;; Capicom AppID - just using the Capicom.EncryptedData CLSID
;;; Use default surrogate = empty string
[HKEY_CLASSES_ROOT\AppID\{A440BD76-CFE1-4D46-AB1F-15F238437A3D}]
"DllSurrogate"=""
;;; Capicom.EncryptedData
[HKEY_CLASSES_ROOT\CLSID\{A440BD76-CFE1-4D46-AB1F-15F238437A3D}]
AppID="{A440BD76-CFE1-4D46-AB1F-15F238437A3D}"
;;; Capicom.HashedData - use same AppID for all!!!!!
[HKEY_CLASSES_ROOT\CLSID\{CE32ABF6-475D-41F6-BF82-D27F03E3D38B}]
AppID="{A440BD76-CFE1-4D46-AB1F-15F238437A3D}"
Save to a myComponent-dllhost.reg file, and away you go.
c:\windows\sysWow64\regedit.exe "myComponent-dllhost.reg"
You should now be able to access Capicom.HashedData and Capicom.EncryptedData from 64-bit script/COM hosts.
Notes:
This only works for basic OLE Automation types. Any object compatible with Windows Scripting Host scripts in VBScript or JavaScript should be OK.
You only have to add the AppID to directly creatable objects. That's basically those with an InprocServer32 entry. Objects which are generated from factories or which are only available as child objects do not have to have an AppID added.
If there is already an AppID all you need to do is add the empty-string "DllSurrogate" entry. That's it!
this will NOT affect normal clients of the DLL. As long as the bit-ness matches, they will continue to be loaded in-process as before. The only difference it will make is that it will become possible to instantiate it out-of-process from a client of a different bitness.

COM OCX registration - 2 DLL's with same name

I have a native app that has an .OCX file that needs to be registered for it to be used in a .NET application.
Now currently there's different versions of this .OCX on the machine. Can someone please explain how this can affect the registration of this new (updated) .OCX file registration?
And how does my .NET app know which object to create from which .OCX file?
COM servers are required to change their CLSID guids if their interfaces are no longer compatible. So if your supplier did it right, you should be able to register both of them and get the right one when you use the right reference in your project.
Like any rule, this one got violated often and is presumably the reason you started this question in the first place. The back-up plan is to use registry-free COM, you write a manifest and add it to your program so it always uses the local copy of the COM server DLL instead of the one that was registered. Find out how to do this by googling "regfree COM", I see many relevant and useful hits at the top.
I believe COM class registrations include the entire path to the "server" providing the COM component. If the two versions of the .OCX have different class GUIDs, then there should be no issues.

VB6 Error - Cannot load .ocx File

I have been trying to load a OCX file into one of my VB6 projects for most of the day today. I've tried checking the COM registration in the registry the best that I know how, and have attempted several times using REGSVR32 on the file to no avail. All I keep getting from VB6 when I try to load the component (Under Project --> Components) is 'FilePath\FileName.ocx' could not be loaded. Has anyone else seen this before, and if so, any ideas how to fix it?
Just a couple of tips to help isolate the problem....
Look at the control with OleView
Examine the name: if it is one of the reserved words such as 'Menu', vb6 will fail to load it. (Although vb6 will happily let you create (and use) one with a bad name until it is saved and reloaded)
Examine the interface: does it describe the functionality? You may have a damaged or unlicensed ocx.
Attempt to load it with the ActiveX Control Test Container...
If you can, the problem is with VB6 and not the ocx.
This it may be a dependency issue -- some other component needed by the OCX is not present. Dependency Walker will find any static dependencies.
We fixed similar error recently. In our case the error was in the Visual Basic project (.vbp) file. Project file had been edited outside standardized build machine and contained references to OCX components - including workstation specific paths & versions of the components.
You can either edit the the project file in text editor or get a working version from version control.
Un-registering and registering again worked for me too.
Please note that you need to register this component using this syntax:
regsvr32 /i:design olch2x8.ocx
When you say you have used "REGSVR32 on the file to no avail" do you mean that you get a file name succeeded message, or an error message? If registering the file succeeds CMB is likely right about the ocx being unlicensed.
Licensing aside, there are a couple of other trip points with vb6. Especially if the OCX was developed in VB6.
If so, the 'officially' system registered version may conflict with the specific ocx you're using. In other words, both of them might have the same proper name (or classid) but the one you're attempting to use may not implement all the functionality described in the system registered one (i.e. you have a less evolved version). This arises when the author desires to maintain binary compatibility while enhancing the functionality of a control. As long as the public interfaces remain compatible, vb will not recalculate the classid.
You can fix this by forcibly unregistering the specific control (actually unregister all instances of the control). (regsvr32 /u control.ocx ) Then re-register the one you intend to use. Be certain that no running instance of VB6 exists when you do this or the results might not work. (Check your task list)
Hope that helps...
The control may be reliant on another DLL or OCX that may be missing or not registered and this could manifest itself as VB reporting that the control you're trying to use is missing. However, I'm not sure how you would identify the dependencies. As far as I know, dependency walker identifies static dependencies; I'm not sure if it can identify COM dependencies.
Un register the Ocx
re register the ocx
then loaded the project again in VB6, it worked for me.
Thanks everyone