Problem:
Traditionally, the use of multiple versions of the same COM Object on a single machine has proved difficult to maintain and implement. In addition, tighter security requirements have made the registering of a COM DLL more difficult. It may be a hardened server with a deduced permissions set that does not allow the registry to be updated.
Resolution:
Windows XP/Windows 2003, and above, introduced a solution to this issue called Side-by-Side assemblies. This allows you to use application manifest files to specify what COM components are available to the application. At runtime the operating system (OS) will use the information contained in the application manifest to locate the COM DLL for a specific "progid" (or GUID).
(Note: A .ZIP archive file containing the full demo supporting the subject of this article is available for downloading at the bottom of this page.)
What is the "manifest" and what does it look like?
A Manifest is an XML configuration file that matches the application name. For example if you have an application "testcomfreereg.exe" then the XML configuration file should be "testcomfreereg.exe.manifest" in the same directory as the application exe ( just add a .manifest extension).
Manifests are automatically loaded and handled by the OS so no source code changes are needed or COBOL runtime configuration. A manifest also needs to be created for the COM Component. In this case the manifest would be called something like "mycomclass.X.manifest" for "mycomclass.dll". The X is required for Windows XP and matches the name specified in the .exe.manifest.
An example exe.manifest file from the attached demo looks like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="X86"
name="testregfreecom"
type="win32" />
<description>MicroFocus Demo Aplication.</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="mfadder.X"
version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>
As you can see the manifest specifies that there is a dependant called "mfadder.X". Therefore there needs to be an "mfadder.X.manifest". In the example this contains:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="mfadder.X"
version="1.0.0.0" />
<file name = "mfadder.dll">
<comClass clsid="{EA899266-8254-4C43-9EAB-835FF203CCDD}" progid = "MFAdder" threadingModel = "Apartment" />
<typelib tlbid="{367F911A-C65A-4D5A-88BD-2F6A6ECD2B09}" version="1.0" helpdir=""/>
</file>
<comInterfaceExternalProxyStub
name="IMFAdder"
iid="{CC4BE712-6D84-4712-B4E5-DB4F53B9B29A}"
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
baseInterface="{00000000-0000-0000-C000-000000000046}"
tlbid = "{367F911A-C65A-4D5A-88BD-2F6A6ECD2B09}" />
</assembly>
There are some highlighted items above that need to be explained.
"
The name "mfadder.X matches the value specified in the exe.manifest.
"
The physical name is specified as mfadder.dll.
"
A COM progid of "MFAdder" is specified. This matched the name specified in the "$OLE$MFAdder" that is coded in the COBOL program
"
IMFAdder is the COM Interface name that was generated and was taken from the MFAdder_if.idl that was generated.
"
367F911A-C65A-4D5A-88BD-2F6A6ECD2B09 and the other similar numbers are the unique generated IDs for the Type Library, COM Class and Interface.
"
The values for proxyStubClsid32 and baseInterface values are standard values for the Type Library marshaler and the IDispatch interface.
To test this out, download the demo and load the project in the Net Express IDE:
1.
First use the "Debug Build" and run the demo. This should give you an error as the COM DLL has not been registered and the manifests have not been setup.
2.
Change to the "Release Build". When you run this you should find this works correctly as the manifests have been setup correctly. No regsvr32 (or .reg file) was required to setup and configure the COM Object!
3.
Look in the release directory for your project and you should find "testregfreecom.exe.manifest" , "testregfreecom.exe" , "mfadder.dll" and mfadder.X.manifest". These are the only required application files.
On the same machine, a different version of the COM object could be used with exactly the same progid and guids. Because they are configured using Side-by-Side, the 2 applications are completely isolated from each other. Changes in one COM DLL would not impact the other application. This would allow you to run completely different versions of the same applications.
Advanced Setup
It is possible to embed these manifests within the EXE and DLL. The same programs are in the EmbeddedRegFreeCOM folder of the demo, but the EXE and DLL have the manifest specified in the resource file (.rc) so it gets built into the EXE and DLL. If you edit the .rc file for the EXE and DLL then you can see that they have a similar format. For the DLL it looks like:-
#include "mfadder_tlb.rc"
#include "mfres.h"
#define _MFRES_INC_
#define RT_MANIFEST 24
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
/* Micro Focus Resource File. */
/* Version 4.00.017 */
#include <mfrcwin.h>
/*MF_BITMAP*/
/*MF_CURSOR*/
/*MF_DIALOG*/
/*MF_ICON*/
/*MF_MENU*/
/*MF_RCDATA_END*/
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "mfadder.dll.manifest"
Much of this was auto-generated when the COM object was created. The lines:-
#define RT_MANIFEST 24
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "mfadder.dll.manifest"
- were added to specify that the manifest was to be embedded into the binary executable.
Side-by-Side is not restricted to just the COBOL world. It is language independent so you could use this technique in a mixed language application with VB, C , etc. You can specify a COBOL COM module in the manifest of a C application or specify a C COM DLL and VB COM DLL in a COBOL application manifest.
You can also use this on COM DLLs from third parties where you do not have control over how the application is published or developed. You could use a tool such as OLEVIEW to get the GUID information from its Type Library. This would enable you develop a manifest file even if you don't have the source.
Summary
It is possible to isolate COM DLLs to a specific application and escape from the DLL hell created with multiple applications using different versions of the same COM DLL.
Using Manifests you can use COM, but do not need to register the components within the registry. This may help to simplify deployments.
Links and Further Reading
http://msdn.microsoft.com/msdnmag/issues/05/04/RegFreeCOM/
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sbscs/setup/isolated_applications_and_side_by_side_assemblies_start_page.asp?frame=true