fourpastmidnight
fourpastmidnight

Reputation: 4234

WiX: Component rules for installing an application with an application manifest

I'm writing an installer using WiX 3.7. The installer will install an old VB6 program (it's a vendor-proprietary program for which I do not have the source code). As such, this program makes use of some old COM libraries that are not installed with the most recent versions of Windows (e.g. Windows 7 and beyond—not sure about Vista or XP).

Since I recently learned that COM libraries can now be installed privately without global system registration using registry-free COM registration, this is precisely what I intend to do for those COM libraries that are no longer distributed with the Windows OS.

To that end, I've created the required manifest files that will be used to lookup all the COM registration information when the library is loaded and used by the application. I've created MSI components for these libraries. Here's the relevant WiX markup for these two libraries (I've removed my GUIDs for the components so no one copies them for their own installer):

<Component Id="C__MsComm32.ocx" Guid="PUT-YOUR-GUID-HERE" DiskId="1">
  <File Id="F__MsComm32.ocx" Vital="yes" KeyPath="yes"
        Assembly="win32"
        AssemblyApplication="F__MyApp.exe"
        AssemblyManifest="F__MsComm32.sxs.manifest"
        Name="mscomm32.ocx" Source="[to be filled in]" />
  <File Id="F__MsComm32.sxs.manifest" Vital="yes" KeyPath="no"
        Name="mscomm32.sxs.manifest" Source="[to be filled in]" />
</Component>
<Component Id="C__threed32.ocx" Guid="PUT-YOUR-GUID-HERE" DiskId="1">
  <File Id="F__threed32.ocx" Vital="yes" KeyPath="yes"
        Assembly="win32"
        AssemblyApplication="F__MyApp.exe"
        AssemblyManifest="F__threed32.sxs.manifest"
        Name="threed32.ocx" Source="[to be filled in]"  />
  <File Id="F__threed32.sxs.manifest" Vital="yes" KeyPath="no"
        Name="threed32.sxs.manifest" Source="[to be filled in]" />
</Component>

In order for all of this to work, I also need to provide a manifest file for the application exectuable, called MyApp.exe.manifest that tells the OS which assemblies this application depends on. So I also created the requisite manifest file. Now I need to create the component (or components) for deploying the application and its manifest.

According to the VS intellisense for File/@Assembly:

Specifies if this File is a Win32 Assembly or .NET Assembly that needs to be installed into the Global Assembly Cache (GAC). If the value is '.net' or 'win32', this file must also be the key path of the Component.

And then, for File/@AssemblyManifest:

Specifies the File identifier of the manifest file that describes the assembly. The manifest should be in the same Component as the assembly it describes. This attribute may only be specified if the Assembly attribute is set to '.net' or 'win32'.

That's all well and good, and I understand all of that completely. So for my application's File element in WiX, I have this so far:

<File Id="F__MyApp.exe" Vital="yes" KeyPath="yes"
      Assembly="win32"
      AssemblyManifest="F__MyApp.exe.manifest" />

Now, what I don't understand is the intellisense for the File/@AssemblyApplication attribute:

Specifies the identifier for the application file. This assembly will be isolated to the same directory as the application file. If this attribute is absent, the assembly will be installed to the Global Assembly Cache (GAC).

Obviously, I don't want my application installed into the GAC (and, I think it shouldn't be since I set File/@Assembly to win32). The question is, can the File/@AssemblyApplication attribute value point to its parent element's @Id attribute? For example:

<Component Id="C__MyApp.exe" Guid="PUT-YOUR-GUID-HERE" DiskId="1">
    <File Id="F__MyApp.exe" Vital="yes" KeyPath="yes"
          Assembly="win32"
          AssemblyManifest="F__MyApp.exe.manifest"
          AssemblyApplication="F__MyApp.exe" />
    <!-- @AssemblyApplication references it's parent element's @Id attribute. -->
    <File Id="F__MyApp.exe.manifest" Vital="yes" KeyPath="no"
          Name="MyApp.exe.manifest" Source="[to be filled in]" />
</Component>

Is this the correct way to author the Component element for my application which contains an application manifest? Or should I forget about setting the various Assembly* attributes and create two Components, one for the application executable and another for its manifest?

Upvotes: 2

Views: 2256

Answers (1)

Stein &#197;smul
Stein &#197;smul

Reputation: 42276

Isolated COM: What you need is an isolated COM component, this is a different concept than Win32 assemblies (WinSxS) and .NET assemblies (GAC).

Quick Advice:

My 2 Cents: Run this legacy application on a virtual machine instead! Problem solved? (problem removed maybe).


Warning: the below was written in a rush. I will check it again later.

The real expert on this (of old) is Wim Coenen - not sure he lurks this tag anymore:


Side-By-Side: These two types of assembles are win32 files installed side-by-side (WinSxS) or .NET assemblies installed side-by-side (GAC) respectively. So that means old Win32 files (native code) and modern .NET assemblies (managed code - .NET runtime required). Side-by-side obviously means that different versions of the same file (referred to as assembly) can co-exist and you can load the one you require by means of a manifest.

Isolated COM: Isolated COM is something completely different. It is the installation and invocation of COM servers without any registry entanglements - all happening from within the same installation folder. I often refer to this as "registrationless COM" - an odd term perhaps.

What it means is that you can load incompatible COM server versions from the local installation folder for whatever binary consumes them. All you need to do is to dump the COM server and its manifest in the local installation folder. No need for Win32 or .NET assembly installation. See below for reality check...

  • This "solves" a huge problem with COM, namely the per-machine or global registration nature of COM servers. In other words there is usually only one version of the COM server installed (though it is technically possible to install different flavors of COM servers it was usually not done - a nightmare of GUIDs and IDs to change).
  • It also helps to isolate your application from dirty packages, installers, scripts and applications that trigger COM registration conflict in the registry. A very problematic issue ever since COM arrived.

WiX Markup: Just install the COM server and the manifest file in the same folder:

<Component>
  <File Source="mscomm32.ocx" />
  <File Source="mscomm32.sxs.manifest" />
</Component>
<Component>
  <File Source="threed32.ocx"  />
  <File Source="threed32.sxs.manifest" />
</Component>

Reality Check: My experience is that it is very hard to get isolated COM to work when you don't have access to the source code in question. The reason is that COM is a binary standard / binary reuse. As I understand it you need the exact same version of the files involved for this isolated COM to work properly. All files in correct version. That is not to say that people have not succeeded using the approach, but I have generally suggested that people go virtual instead: rely on virtual machines to run these legacy applications.

I have this old answer with more context: What do I do when launching an application triggers repeating, endless Windows Installer self-repair? (see registration-less COM section).

Upvotes: 1

Related Questions