Previous | Index | Next 

[HOWTO] Use different versions of same COM type library or ActiveX control

A large VB6 application consisting of multiple EXE files – and that has been developed over many years – might easily use different versions of a given type library or ActiveX control, even if all the EXEs reside in the same directory. This arrangement is possible in the COM world because libraries and controls are located by using their GUID to search the registry for a key that holds the path of the DLL or TLB file.

A similar arrangement is possible in the .NET world as well – more precisely, by registering an assembly in the GAC – but many developers prefer to keep all the ancillary DLLs in the application’s main folder. If you prefer this approach, you should take a few extra steps if the original VB6 application uses different versions of the same ActiveX control.

First and foremost, if the application uses two different versions of a given ActiveX control, you must use the AxWrapperGen twice, one for each distinct version. The problem that raises at this point is that AxWrapperGen generates one file with same name for the two controls.

For example, say that your VB6 application consists of two projects: App1.vbp uses version 1.0 of the ABC ActiveX control and App2.vbp uses version 1.1 of the same control. By running AxWrapperGen on the two versions of the control you get the following files:

Version 1.0: AxAbc10.dll, Abc10.dll, AbcLib.Dll
Version 1.1: AxAbc11.dll, Abc11.dll, AbcLib.Dll

As you can notice, the AbcLib.dll file is in common to both versions. This means that you must store them in different folders, for example C:\MyControls\Abc\v.1.0 and C:\MyControls\Abc\v.1.1.

Once you have run AxWrapperGen and stored the result in different problem you face the problem of letting VB Migration Partner know where these controls are, so that references to the ActiveX controls can be resolved correctly. You can’t just drop the files in VB Migration Partner’s main folder (because two files have same name), thus you need an AddLibraryPath pragma:

        ' use this pragma inside App1.vbp
        '## AddLibraryPath c:\mycontrols\abc\v1.0
        ' use this pragma inside App2.vbp
        '## AddLibraryPath c:\mycontrols\abc\v1.1

Notice that the effect of the AddLibraryPath pragma extends to all the projects being migrated in a given session, therefore you can’t migrate a .vbg file in a single operation if the group contains projects that use different versions of the same ActiveX control. In this case, you must migrate each project separatedly.

Once you have migrated both App1 and App2, everything works well if you store the corresponding EXE files in different directories, with all the files related to version 1.0 of the control in the same folder as App1.exe and all the files related to version 1.1 in the same folder as App2.exe. If you can live with storing the two EXE files in separate folders, this is by far the best and simplest solution.

However, there might be cases when you need to keep both App1.exe and App2.exe in the same folder, for example if the share a set of data files. If this is the case you are forced to rename one of the AbcLib.dll files. For example, the AbcLib.dll file generated by AxWrapperGen when converting version 1.1 of the ABC control should be renamed as AbcLib11.dll.

After renaming one of the AbcLib.dll file you can store all the necessary files in the same directory used for App1.exe and App2.exe, but you have one last problem to solve, because App2.exe will throw an exception when trying to load the AbcLib.dll, because this file references version 1.0 of the control. To solve this problem you need to change the assembly resolve policy used by App2, which you do by intercepting the AssemblyResolve event of the AppDomain object, as follows:

        ' this code goes in the VisualBasic6.Support.vb file (in My Project folder)
        ' of the App2 project

        Sub New()
            ' prepare to handle the AssemblyResolve event
            AddHandler AppDomain.CurrentDomain.AssemblyResolve, _
                       AddressOf AppDomain_AssemblyResolve
        End Sub

        Private Function AppDomain_AssemblyResolve(ByVal sender As Object, _
            ByVal e As ResolveEventArgs) As Assembly

            ' if the application is trying to resolve the AbcLib assembly
            ' redirect the request to the AbcLib11.dll file, if it exists.
            If e.Name.ToLower.StartsWith("abclib") Then 
                Dim dllPath As String = Application.StartupPath & "AbcLib11.dll"
                If System.IO.File.Exists(dllPath) Then
                    Return Assembly.LoadFile(dllPath)
                End If
            End If
        End Sub

Note: This article shows how you can solve problems caused by AxWrapperGen generating files with same name but related to different versions of the same ActiveX control. The same strategy can be used to solve problems caused by completely different ActiveX controls (by different vendors) whose DLLs coincidentally have same name.


Previous | Index | Next