How To: ClickOnce deployment for unmanaged app with COM component in managed assembly

Recently I worked with a global ISV in Europe on re-architecting some of their products from competitive platforms to Microsoft platform. In some cases only the server side was being re-architected and the server had to support existing client applications. Some of these existing client applications are written in Delphi and their deployment is painful.

The ISV was aware of ClickOnce; however they assumed that ClickOnce couldn’t solve their problems, because of the following preconceptions:

- they thought that ClickOnce couldn’t help with deployment of unmanaged applications

- their applications uses COM components implemented in .NET and they thought that ClickOnce couldn’t help with deployment of COM components, because they thought that in order to deploy COM components users would have to have admin rights, be able to write to Windows Registry and be able to upload files to GAC.

I clarified these misconceptions and stated that it should be possible to use ClickOnce to deploy Delphi apps with COM components implemented in .NET and that it should work even for users with no admin rights and it wouldn’t require updating Registry or placing assemblies in GAC.

Individual pieces of this concept are documented; however, I couldn’t find any end-to-end solution addressing all the requirements of this ISV, so I created a sample proof of concept demonstrating the end to end scenario and wanted to share it in case someone else will find it useful as well. The source code of the sample is available at MSDN Code Gallery.

My idea leverages a mechanism called registration-free activation of COM components, which is available on Windows XP SP2 and newer versions of Windows. This piece of my solution is quite well documented at MSDN and for instance there is a nice walkthrough available here.

One of the most important steps is to write a manifest for the managed assembly that exposes COM components. The manifest can be very simple – in my sample it looks like that:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

  <assemblyIdentity

      name="AssemblyWithComComponents"

      version="1.0.0.0"

      processorArchitecture="MSIL" />

  <clrClass

      clsid="{F1D4EF3D-7E94-4F45-887F-7CA3E76021A3}"

      progid="DemoNamespaceProgId.DemoNamespaceProgId"

      threadingModel="Both"

      name="DemoNamespace.DemoComponent"

      runtimeVersion="v2.0.50727">

  </clrClass>

  <file name="AssemblyWithComComponents.dll">

  </file>

</assembly>

The next step is to embed this manifest as a RT_MANIFEST unmanaged resource directly into the assembly dll. In Visual Studio 2008 it can be done as easily as by creating a one line rc file:

1 24 AssemblyWithComComponents.manifest

and setting its Build Action to “Resource” in the Solution Explorer.

The last key step is to create a manifest file for the client application (e.g., your Delphi app or a VB6 app as in my sample). In my sample this is as simple as this:

<?xml version="1.0" encoding="utf-8"?>

<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:dsig="https://www.w3.org/2000/09/xmldsig#" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">

  <assemblyIdentity version="1.0.0.0" name="Client.exe"/>

  <dependency>

    <dependentAssembly >

      <assemblyIdentity name="AssemblyWithComComponents" version="1.0.0.0" processorArchitecture="MSIL" />

    </dependentAssembly>

  </dependency>

</asmv1:assembly>

By having these manifest files we can use registration-free activation of COM components - in our case a COM component implemented in a managed assembly.

When the following components: the client application, the client manifest file and the assembly dll with the embedded manifest are deployed together (for instance using ClickOnce with a help of a managed launcher application as in my sample) we achieve the goal of exposing COM components implemented in managed code without putting the assemblies into GAC, and without touching Registry and without having admin rights.

The zip file that I uploaded to MSDN Code Gallery contains the full source code of my sample and all ClickOnce deployment files. The sample consists of:

-          AssemblyWithComComponents project – a .NET assembly (implemented in C#) that implements a COM component,

-          Client project - unmanaged client applications (in my sample it is a VB6 app, but it could be also a Delphi app or other unmanaged app) that use the above COM component,

-          ClientLauncher project – a tiny managed app (implemented in C#) that simply launches the proper client application (Client.exe) and its role is to allow deploying the whole solution through ClickOnce

-          Publish folder for ClickOnce deployment. Setup.exe from that folder can be run without admin rights and it will deploy the application using ClickOnce and then launch the client app which in turn can call a method from the COM component.

Please note that if you want to recompile the sample, in particular the unmanaged Client project, you may need first to temporarily set the “Register for COM Interop” setting in AssemblyWithComComponents project settings. Just make sure to unregister the assembly if you want to test the registration-free activation.

The minimum requirement to leverage this approach is Windows XP SP2 or Windows Vista.

I tested it on Windows Vista SP1, Windows Server 2003 SP2 and Windows XP SP2.

When working on solution architecture with global ISVs we often help them by connecting the dots between various technologies, often by drawing boxes and lines. Sometimes we get our hands dirty and we connect the dots by writing samples that demonstrate end to end scenarios leveraging existing technologies, as in this case.

Hope you will find this sample useful,

Grzegorz Gogolowicz

Senior Solutions Architect

GISV Architecture Team