Make Wix to not uninstall common dll - wix

I have Wix project in which I need a common used dll library to be installed if it's absent.
If this dll exists I should not overwrite it.
So, when I set DefaultVersion="0.0.0.0" this dll is not overwritten if it exists, its ok. But when I delete app, the dll is beeing removed. How do I prevent removing dll in the case when it existed before installation?
I don't want to make it permanent because it should be removed if it didn't exist before installation.
<Component Id="myLib.dll" Permanent="no" Directory="Shared_Dir">
<File Name="myLib.dll" KeyPath="yes"
Source="mySource\myLib.dll"
DefaultVersion="0.0.0.0"
/>

Add reference to WixUtilExtension and xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" attribute to Wix element in your code.
Define <Property Id="Dll_Installed" Value="false"/> in Product element.
Add child <Condition>NOT Dll_Installed</Condition> to component myLib.dll.
Add that somewhere in your code:
<Fragment>
<util:FileSearch
Id="Dll_Installed"
Variable="Dll_Installed"
Path="[Shared_Dir]myLib.dll"
Result="exists"/>
</Fragment>
DefaultVersion attribute is not necessary.

The feature you are describing is reference counting. The Windows Installer reference counts with Components. Components are identified by their GUID.
So the normal way to address this requirement is to put the File in a Component and make sure the GUID of the Component is stable. The WiX Toolset should do exactly that automatically if if you do not specify the Component/#Guid attribute.
So the default behavior should just work for you.
The only other piece of the puzzle is the Windows Installer will install the latest version of a file. If the file version is the same or less the file will not be installed but will be reference counted.
Based on the details in the question it seems like you should be just fine with:
<Component Directory="Shared_Dir">
<File Source="mySource\myLib.dll" />
</Component>
One might ask why the Windows Installer use Components to reference count files. We'll, it allows you to group other resources, like registry keys, together and control their install as a unit. Much more important if you are installing COM servers than plain old files.

Related

How do I stop removal of files during uninstallation using Wix

When uninstalling my application, I'd like to configure the Wix setup to NOT to remove few files that were added as part of the installation. It seems like the uninstaller removes all the files that were originally installed from the MSI file. How do I do that?
Here are my files which I wish to keep it forever
<Binary Id="RootCABinary" SourceFile="Assets\Certificates\RootCA.cer" />
<Binary Id="SubCABinary" SourceFile="Assets\Certificates\SubCA.cer" />
I have used WixIIsExtension.dll to install these certificates to the windows store.
Overwrite: Is it important that the file never gets overwritten? If so, add
"Never Overwrite" to your component. WiX attribute: NeverOverwrite="yes". Remember to test upgrade scenarios!
Permanent Component: As stated by Pavel, you can set a component permanent:
<Component Permanent="yes">
<File Source="License.rtf" />
</Component>
Blank GUID: Another way to do it is to set a blank component GUID. It essentially means "install and then leave alone". No repair or uninstall should be done (remember to add NeverOverwrite="yes" if the file should never be overwritten):
<Component Guid="" Feature="MainApplication">
<File Source="SubCA.cer" KeyPath="yes" />
</Component>
Read-Only Copy: I sometimes install files to a per-machine path (for example somewhere under program files) and then copy them to a per-user location (somewhere in the user-profile) on application launch, and then do operations on them that entail that the files should not be deleted. This is good in cases where you want to do something that change the files in question (they need to be writable). Then it is good to "untangle" them from deployment concerns (files will not be meddled with by installer operations at all - the installer has no knowledge of them). The original read-only copy installed to program files can be uninstalled though (no longer needed?).
Other approaches: You can also create such files using custom actions during installation (usually text files only), you can download the file in question from your web site on application launch (makes the file easy to manage and update / replace? Vulnerable to connection problems - firewalls, etc...) and the application can create the file using "internal defaults" in the main executable on launch. And there are no doubt further approaches that I can't recall.
Put your binaries in a separate WiX component and make it permanent. Have a look at this thread as well

How to include inherited permissions when specifying permissions for a file installed by Wix / Windows Installer?

The Wix source code that I feed to the Wix compiler to build an MSI package for my application, contains the following PermissionEx directive, part of a file component which Windows Installer should install with additional (to those that should be inherited by default) permissions:
<PermissionEx Sddl="D:AR(A;;FW;;;BU)" />
As you can surmise, I intend to install the file with inherited permissions ("AR") included in its ACL and on top of that allow members of the Built-in Users group ("BU") to be allowed ("A") to write to the file ("FW").
The code above does not have the desired effect -- the file is installed, but only that single explicit ACE is listed, none of the ACEs that are supposed to be inherited from parent folder.
In contrast, if I subsequently remove all permissions from the file and run cacls file /S:D:AR(A;;FW;;;BU), i.e. specify exactly the same SDDL string, it does work as intended -- the permissions from parent are inherited and form part of the ACL, together with the explicit non-inherited ACE.
I am using Wix 3.11.1.2318 and the Windows Installer version is 5.0.16299.611, all running on Windows 10 Enterprise 64-bit. Orca tells me the MsiLockPermissionsEx table embedded in my built MSI file is populated with the intended SDDL record. So why is the file created without inheriting permissions from its containing folder?
I tried to use "AI" in place of "AR", and both strings together, but none of it had any effect either.
Is this some known limitation or a quirk with Windows Installer? I know that people were talking a while back how the old LockPermissions table (the one specified for Windows Installer versions earlier than 5) was inadequate in this specific regard -- inherited permissions, namely -- but they also said Microsoft was out to address this very issue with the new table feature.
Otherwise what am I doing wrong?
Given your knowledge in this field, you probably have already tried this. It would also be much better to eliminate the need for permissioning, but two snippets for you - notice the Append attribute:
Create a WiX project in Visual Studio. Add the Util namespace to the WiX element:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
In Visual Studio project, right click References and add reference to "%ProgramFiles(x86)%\WiX Toolset v3.11\bin\WixUtilExtension.dll".
Permission Folder:
<Component Feature="ProductFeature" Id="Test.exe" Guid="PUT-GUID-HERE">
<File Source="C:\Test.exe" />
<CreateFolder>
<util:PermissionEx User="Power Users" GenericWrite="yes" />
</CreateFolder>
</Component>
Permission File:
<Component>
<File Source="C:\Test2.exe">
<util:PermissionEx Append="yes" User="Users" GenericWrite="yes" />
</File>
</Component>
Take a look at WiX's custom PermissionEx in the Util extension.
http://wixtoolset.org/documentation/manual/v3/xsd/util/permissionex.html

vsdrfCOMSelfReg equivalent for WixSharp

I am trying to recreate the functionality of a legacy installer using WixSharp. In the legacy Setup Project, some of the third party DLL's were marked "vsdrfCOMSelfReg". I have seen in various places that you can add to the File tag SelfRegCost="0" but it is highly frowned upon.
How can I properly register a COM DLL using WixSharp? Is there a way to just add SelfRegCost field to the File tag for the DLL from WixSharp?
It's true that you can say something like SelfRegCost=1 in the File element, but every install guy will tell you it's evil, as you discovered. The non-evil way is to use heat.exe on the Dll to extract the registration data into a wxs file. If necessary add interface entries for type library data by running heat.exe on a tlb file. Heat is just a WiX tool, I don't see how WiXSharp is involved.
The point is that registration data is static and can be stored in the MSI via WiX and simply written to the system at install time without requiring the Dll to be loaded and called.
After some further source browsing and experimentation, I figured out how to force the evil approach through WixSharp. I also later discovered that this was somewhat covered by the WixSharp Sample "CustomAttributes".
"Evil Way"
File LibToReg = new File("..\Path\To\LibToReg.dll");
LibToReg.AttributesDefinition += "SelfRegCost=1";
Alternatively (based on the CustomAttributes sample):
File LibToReg = new File("..\Path\To\LibToReg.dll")
{
Attributes = new Attributes() { { "SelfRegCost", "1" } }
};
This will generate the following wxs underneath:
<Component Id="Component.LibToReg.dll" Guid="EABD7A49-26DD-4720-AE5A-AA9EEFD8C91A">
<File Id="File.LibToReg.dll" Source="..\Path\To\LibToReg.dll" SelfRegCost="1" />
</Component>
The rest of the generated code looks the same as any other DLL that is installed.
For reference, here is the original wxs source that was generated from the original Setup Project using "VDProj to WiX Converter" from Add-In Express. I believe the SelfRegCost="0" was added by the converter, but a co-worker may have manually added it in afterwards.
<Component Id='com_FB7105EC_5352_4561_AE01_405562F0EA1E' Guid='6718170E-0335-4FD6-A1E8-D9E926DDE3EC' Permanent='no' SharedDllRefCount='no' Transitive='no'>
<File Id='_FB7105EC_5352_4561_AE01_405562F0EA1E' DiskId='1' Hidden='no' ReadOnly='no' SelfRegCost='0' System='no' Vital='yes' Compressed='yes' Name='LibToReg.dll' Source='..\Path\To\LibToReg.dll' KeyPath='yes' />
</Component>

What elements does Wix use to auto generate a ComponentId guid when the keypath is a RegistryKey/Value

I have a Wix (3.8) project that is relatively generic in that we are attempting to produce multiple Demo installers using a variety of tools such as the preprocessor to change the name, include different files and options. I also modify the ProductId/ProductCode/UpgradeCode for each so that they appear as 2 different products and install side by side. Installing and uninstalling one alone works fine. When I install 2 side-by-side and uninstall one there are several abandoned resources one of which is the shortcuts.
Here is the code I am using for the shortcuts:
<DirectoryRef Id="DesktopFolder">
<Component Id="DesktopShortcuts"
Guid="*">
<Shortcut Id="ApplicationDesktopShortcut"
Name="!(bind.property.ProductName)"
Description="Demo Application"
Target="[INSTALLDIR]Demo.exe"
WorkingDirectory="INSTALLDIR"
Advertise="no"/>
<RegistryKey Root="HKMU"
Key="SOFTWARE\$(var.Manufacturer)\!(bind.property.ProductCode)\DesktopShortcuts">
<RegistryValue Name="Installed"
Type="integer"
Value="1"
KeyPath="yes" />
</RegistryKey>
</Component>
</DirectoryRef>
After reviewing the installer logs I note that the ComponentId for the shortcuts is always the same which explains the abandoned resources (shortcuts).
I was under the impression that because the Path to my registry value was different for each installer (note that I bind the product code into the key) I would get a different Guid for each installer as a result of the Guid="*" attribute. However, the wix documenation is unclear WRT Registry keys as are other discussions I located. Apparently this isn't an issue with files that are in separate directories.
Such as this and the Wix docs.
So I figured out what is going on. It's all got to do with some subtle issues on this line:
Key="SOFTWARE\$(var.Manufacturer)\!(bind.property.ProductCode)\DesktopShortcuts">
As noted in the question the documentation and references suggest that the Path for files and registry entries are used to dynamically generate the Guid. Note the path includes the file/Value Name. This is in fact happening but how was I getting the same Guid for the ComponentId for 2 different installers using 2 different ProductCodes? You would think that the inclusion of the ProductCode into the path would make each unique. Well, turns out it's because I was using !(bind.property.ProductCode) in the path. Binder variables don't get substituted until the Linking phase with light. The Guid="*" element is generated in the Compiling phase with Candle which is obviously before the linker. So while the substitution was occurring and the proper keys were being generated in the registry, the Guid was being generated from a non unique path:
SOFTWARE\MyCompany, Inc\!(bind.property.ProductCode)\DesktopShortcuts\Installed
So don't use binder variables in any KeyPath element when using the auto generated Guid functionality.

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?
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:
Generate manifest files for registration-free COM
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).