InterOp: Using a .NET based component from a non .NET platform by creating Isolated Application
April 14, 2009
Whenever we try to use a .NET component from VB6 or VC++ applications we tend to expose the .NET classes as COM components and register them and from the VB6 or VC applications so that we can instantiate and use the COM components written in .NET. One downside to doing interOp this way is the use of Registry to store the COM information as COM uses registry to lookup the prog id and clsid. This hassle can be avoided by using xcopy deployment with Registry Free COM.
Isolated Applications and Side by Side Assemblies
.NET is not the sole platform to come up with xcopy deployment and freedom from dll hell. Cpp and Delphie had this for long time. Isolated Applications and Side by side Assemblies have been invented as a solution to the versioning problem.
According to MSDN, Isolated Applications are self-describing applications installed with manifests. The benefits of Isolated Applications are that these are more stable and reliable since they are not affected by installation or change in other software, they will always run with the component version they were originally intended for, they can take advantage of Side by Side Assemblies feature, can be installed with xcopy deployment without impacting the registry. A side by side assembly can be a dll, windows class, COM server, type library or interface defined by manifests.
Private and Shared Assembly
There are two types of Side By Side Assemblies. Private Assemblies are those which are for consumption of one single application, usually placed in the application folder or sub folder. But a Shared Assembly can be used by multiple applications. A fully Isolated application uses only side by side assemblies. If you want to find the Shared Assemblies installed in your computer look in \Windows\WinSxS folder. The shared assemblies are installed here.
Manifests
Manifests are xml files that accompany assemblies with extra information like dependency, binding, activation. A manifest can be an external file or can be embedded as a resource within the assembly. In older operating systems like Windows XP, manifests need to be embedded inside the side by side (denoted SxS) assemblies to work properly. Assembly Manifests describe side by side assemblies and thus needs to be embedded to work properly in operating systems like Windows XP. Application Manifests describe isolated applications and do not need to be embedded inside the application.
Normal Registry Based COM Component Load Procedure
If we look up a COM self registering dll we will find that it usually* has four stdcall calling convention functions. Look at the dependency walker image below of a standard self registering COM server dll.
When we use regsvr32.exe to register a COM dll, the register server application calls the DllRegisterServer function of the dll and that function call inside the dll takes care of putting information in the windows registry so that it can be used by any user application. Now lets have a look at the registry where all these information is recorded. Let us take a standard windows COM component and see its registry structure. The COM component that we will look up today is FileSystemObject from Micorsoft scripting runtime. The progid of the object is Scripting.FileSystemObject. Lets say we are using script code like this
Set fso = CreateObject( “Scripting.FileSystemObject” )
So lets try to have an understanding how this object is created from the code above. If we go and try looking up the string “Scripting.FileSystemObject” under the HKEY_CLASSES_ROOT key then we would see this.
As you can see there is a node called CLSID and it contains the Class ID ( GUID of the class) inside the node. Now lets go and visit that Class ID node under the HKEY_CLASSES_ROOT\CLSID registry node. See below
As we can see that this is how the dll containing the class object is found, COM infrastructure then calls the DllGetClassObject function to retrieve a pointer to the object we are looking for. As like all COM interfaces the object implements IUnknown interface and all scriptable COM objects implement IDispatch interface. However how COM identifies and uses the object beyond the scope of this article. The point that I wanted to make is that the windows registry has a very important function here and to have any COM component usable by other applications we had to register it in windows registry.
Registry Free COM Access in an Isolated Application
In an Isolated Application we can skip entering all the information in the registry and rather enter them in the manifest. We need to create an application manifest which will have the filename in the format of application.exe.manifest. Then we need to create an assembly manifest and embed that assembly manifest inside the dll. Then we would have created an Isolated Application and would not need to register to windows registry to access the functions of the COM dll.
The side by side assemblies are searched in the following order
1. In the executable folder
2. Subfolder of the executable folder, subfolder must have the same name as the assembly. For example see inside your Windows\WinSxS folder
3. In language specific or culture specific subfolder of the executableFor more information on assembly search order look here in MSDN.
Activation Contexts are data structures that allows the OS to redirect loading. For example it can redirect the loader to load a specific version of a dll, or redirect COM object loading process. We will use the COM object loading redirection to avoid using windows registry. For more information on Activation Contexts read this.
Doing it by example
I have setup a sample application with source that will show how we can create a registry free COM component. Please note that there is already a practical example in the following article in MSDN, Registration-Free Activation of .NET-Based Components: A Walkthrough by Steve White and Leslie Muller. You might want to read that article if you find my example not clear enough.
Here is what we are going to do in the sample application
1. Create C# based class that serves funny quotes and expose that as a COM component and register it.
2. Create a VB6 executable that uses the COM dll to show quotes
3. Unregister the COM dll to show that without COM registration in windows registry the application is no longer working
4. Create an application manifest, then create an assembly manifest and recompile the C# application with the embedded assembly manifest to create our isolated application.
5. Move the isolated application to a different folder and prove that the application is using COM without registry.
1. C# COM Dll
We are going to create a dll called QuoteSource and a class that serves Quotes called QuoteProvider and it is going to implement the IQuoteProvider interface. The methods in the interface will be exposed.
Here is how the interface looks like.
Here is the class that serves quotes and implements the interface above
The assembly info contains the assembly guid
We need to make sure that a tlb file is generated and the assembly we created is registered. We will select “Register for COM interop” option from the build properties screen. See below …
2. VB6 Client Executable that uses the C# Library
We have created a simple VB6 application that refers and calls the C# assembly dll. See below:
Let compile the executable and it becomes VB6Client.exe
3. Unregister the C# COM dll to make sure that we a re not using the reference
We will use the following command line in the folder where the dll resides
regasm /u QuoteSource.dll
Lets run our VB6Client.exe and press the Get Quote button… walla! It does not work anymore. The executable exits with automation error since we unregistered it from windows registry.
4. Create the Application and Assembly Manifest and embed Assembly Manifest inside the QuoteSource.dll
First we are going to create an application manifest. The application manifest has to have the name in the format of exetutable full name + .manifest. Since our executable is called VB6Client.exe our application manifest will be called VB6Client.exe.manifest. Here are the contents of the manifest.
Now lets create the assembly manifest and embed it inside out QuoteSource.dll. First we will create an xml file called QuoteSource.manifest. Please observe that we have put in the progid and clsid of the COM exposed class.
Now we need to convert this assembly into a resource file. We will use rc.exe that comes with windows SDK, or VC++ or VB6 installation.
We will create a text file called QuoteSource.rc will put in the following line here.
1 24 QuoteSource.manifest
Here 1 is the manifest resource id and 24 means that it is a type of manifest resource. We will now invoke the Windows SDK resouce compiler from the command line. Check where in you computer you have the resource compiler installed. Here is the command line
rc.exe QuoteSource.rc
After invoking this it will create a file called QuoteSource.res. This is a windows resource file.
Now we will use a custom build command to create the dll. Observe the command line below
csc /t:library /out:QuoteSource.dll /win32res:QuoteSource.res IQuoteProvider.cs QuoteProvider.cs Properties\AssemblyInfo.cs
See the win32res switch, it tells the compiler that it is a win32 resource.
Now copy the dll to the same folder as the exe, also copy the application manifest. There is no need to copy the assembly manifest as we have already embedded it inside the dll.
Run the the application and press the Get Quote button, it works!
5. XCopy Deployment
Copy or move the folder elsewhere, even to another computer. It will still work without any need to register the .NET COM dll. This is because we have created the application and assembly manifest and windows is treating our application as a Isolated application.
Last Words
This way you can create XCopy deployment for even COM based applications and avoid storing information in registry. Even a multi dll VB6 or VC++ application can be made Isolated Application.