WIX won't copy DLL into system32 folder - wix

I need to copy a DLL into the system32 folder, that's my WIX script but it doesn't work, the copy command just fails:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="*" Name="LMBrick Service" Language="1033" Version="1.3.0.0"
Manufacturer="MyCompany" UpgradeCode="3de1a175-3701-435f-90bc-e97cb66b5524">
<Package InstallerVersion="200" Compressed="yes" InstallPrivileges="elevated" AdminImage="yes" InstallScope="perMachine" Platform="x64" />
<Property Id="MSIUSEREALADMINDETECTION" Value="1" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="cab1.cab" EmbedCab="yes" />
<Feature Id="ProductFeature" Title="LMBrickServiceInstallation" Level="1">
<ComponentGroupRef Id="LMBrickComponents" />
</Feature>
<CustomAction Id="InstallLMBrickDll" Directory="LMBRICKINSTALLFOLDER" Execute="deferred" Impersonate="no"
ExeCommand="copy LMBrick.dll [System64Folder]LMBrick.dll"
Return="check" />
<InstallExecuteSequence>
<Custom Action="InstallLMBrickDll" After="InstallFiles">NOT Installed</Custom>
</InstallExecuteSequence>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="Company" Name="MyCompany">
<Directory Id="App" Name="MyProduct">
<Directory Id="LMBRICKINSTALLFOLDER" Name="LMBrickService">
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
</Fragment>
</Wix>

Custom Actions that run Exes have to actually run an exe. However copy is not an exe; it's built into the command shell. So you have two immediate choices (and two better choices later):
Find an actual exe, such as xcopy.exe, and run that instead, or
Execute a shell such as cmd.exe with arguments that invoke its copy builtin.
You can confirm this by opening up a command prompt and executing the commands where copy and where xcopy respectively. Note that launching cmd.exe or any console program as an Exe will result in a console window flashing by during installation. This typically looks rather unprofessional, and you should use one of two alternatives:
Wrappers such as WixQuietExec can suppress the console window, or
Built-in Windows Installer functionality, such as exposed through CopyFile, can avoid the need for a custom action at all.
If possible, it's best to avoid custom actions and use Windows Installer functionality. So aim for the last option if you can.

Related

WIX Toolset - uninstalling .exe file

I wrote Wix Setup program, that wraps PyTangoArchiving-7.3.2.win-amd64.exe file into into PyTangoArchivingInstaller.msi package.
The installation procces is correct I think, in control pannel -> Programs I can see two additional programs installed:
PyTangoArchiving-7.3.2.win-amd64.exe - the program I wanted to install and
my wrapper - PyTangoArchivingInstaller.
But when I try to uninstall the application, only wrapper is being uninstalled and whole program (PyTangoArchiving-7.3.2.win-amd64.exe ) is still there, I have to uninstall it manually from Control Panel.
Can sb help me with this?
Here is my code:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="PyTangoArchivingInstaller" Language="1033" Version="1.0.0.0" Manufacturer="test" UpgradeCode="PUT-GUID-HERE">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<WixVariable Id="WixUILicenseRtf" Value="$(var.ProjectDir)\License.rtf"/>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes"/>
<UIRef Id="WixUI_InstallDir"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id='TempFolder'>
<Directory Id="INSTALLLOCATION" Name="MyApp" >
<Component Id='MyComponent' Guid='*'>
<File Id="mysetup_exe" Source="PyTangoArchiving-7.3.2.win-amd64.exe" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="MainApplication" Title="Main Application" Level="1">
<ComponentRef Id="MyComponent" />
</Feature>
<CustomAction Id="run_setup" FileKey="mysetup_exe" ExeCommand="/SP- /SILENT /SUPPRESSMSGBOXES /LANG=English
/NOCANCEL /DIR="[INSTALLLOCATION]""
Execute="deferred" Impersonate="no"
Return="check" />
<InstallExecuteSequence>
<Custom Action="run_setup" Sequence='5401'>NOT Installed</Custom>
</InstallExecuteSequence>
</Product>
</Wix>
As a general comment, you shouldn't usually be running another exe from inside your MSI, especially if it is an install that shows up in add/remove programs. You should instead use a bootstrapper to chain together multiple installs and this is the preferred way to do what you are trying to do.
Since you run your setup_exe from a custom action, you also need a corresponding custom action to uninstall it.
It would basically be the same format as the one you use to install except with the uninstall command line arguments, whatever they may be.
You will need to schedule your uninstall custom action before the "RemoveFiles" standard action so that the setup exe still exists when you try to run the custom action. You should also condition this custom action with REMOVE~="ALL" AND NOT UPGRADINGPRODUCTCODE.
This approach will run into problems when you try to support upgrades with/without upgrades to the packaged exe install. It is highly suggested you use either the wix burn bootstrapper (bit of a learning curve) or one of the other available bootstrappers for multiple install installations. These would more robustly and correctly support two installs along with upgrades and uninstalls.

WiX toolset EXE Wrapper installer with no files

I have a simple working EXE wrapper in WIX but I don't like that I have to add at least one file for it to work and I can't seem to find a way to not add files to it, is it even possible?
<?xml version="1.0" encoding="UTF-8" ?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product>
<Package Compressed="yes" InstallerVersion="301" />
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="MyProgramDir" Name="MyInstaller">
<Single unwanted dummy component here>
</Directory </Directory>
</Directory>
<Binary Id="MYEXE" SourceFile="Installer.exe" />
<CustomAction Id="RunInstaller" BinaryKey="MYEXE" ExeCommand="" Impersonate="no" Execute="deferred" Return="asyncNoWait" />
<InstallExecuteSequence>
<Custom Action="RunInstaller" Before="InstallFinalize">
NOT Installed
</Custom>
</InstallExecuteSequence>
<Feature Id="ProductFeature" Level="1">
<Single unwanted dummy component ref here>
</Feature>
</Product>
</Wix>
You don't have to have atleast one file (although the scenarios where you don't have any files are very, very rare) you do have to have atleast 1 component and that component has to have a key. The key can be a file, registry entry or by default directory.
The old saying is that installers is more then just copying files but generally they always include atleast copying a file or two.

CustomAction in Wix not executing

So I'm creating my first Wix project and I seem to be having a problem executing a custom action. I'm not sure that it's being included in the msi and I'm not quite sure what I'm doing wrong. The following is my Wix file:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="ExactaDynamicManifest" Language="1033" Version="1.0.0.0" Manufacturer="Bastian Software Solutions" UpgradeCode="274ff2d9-e291-4706-a8db-ce80ccd91538">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="ExactaDynamicManifest" Level="1">
<ComponentGroupRef Id="ExactaDynamicManifest"/>
</Feature>
<Icon Id="exacta.ico" SourceFile="icons\exacta.ico"/>
<Property Id="ARPPRODUCTICON" Value="exacta.ico" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="ExactaFolder" Name ="Exacta">
<Directory Id="INSTALLFOLDER" Name="ExactaExactaDynamicManifest" />
</Directory>
</Directory>
</Directory>
</Fragment>
<Fragment>
<CustomAction Id="InstallService" FileKey="ExactaDynamicManifest.exe" ExeCommand="install"/>
<InstallExecuteSequence>
<Custom Action="InstallService" After="InstallFinalize"/>
</InstallExecuteSequence>
</Fragment>
</Wix>
The last fragment contains my custom action which what I hoped would do is the following on the command line after all files have been placed in the directory:
ExactaDynamicManifest.exe install
One thing to note is that exe is actually coming from a ComponentGroupRef defined above. Not sure if this is a problem or not but thought I'd mention it. Any help would be appreciated.
I finally got something that is working. My initial problem of the CustomAction not loading seemed to be due to it being in a different <fragment>. I consolidated all of the code into a single fragment and it seemed to run.
After battling with user permissions etc I finally ended up with this solution:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="ExactaDynamicManifest" Language="1033" Version="1.0.0.0" Manufacturer="Bastian Software Solutions" UpgradeCode="274ff2d9-e291-4706-a8db-ce80ccd91538">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate />
<Feature Id="ProductFeature" Title="ExactaDynamicManifest" Level="1">
<ComponentGroupRef Id="ExactaDynamicManifest"/>
</Feature>
<Icon Id="exacta.ico" SourceFile="icons\exacta.ico"/>
<Property Id="ARPPRODUCTICON" Value="exacta.ico" />
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="ExactaFolder" Name ="Exacta">
<Directory Id="INSTALLFOLDER" Name="ExactaExactaDynamicManifest" />
</Directory>
</Directory>
</Directory>
<CustomAction Id="RunTopShelfServiceInstall" Directory="INSTALLFOLDER" Execute="deferred" Return="ignore" Impersonate="no" ExeCommand="[INSTALLFOLDER]ExactaDynamicManifest.exe install"/>
<CustomAction Id="RunTopShelfServiceUninstall" Directory="INSTALLFOLDER" Execute="deferred" Return="ignore" Impersonate="no" ExeCommand="[INSTALLFOLDER]ExactaDynamicManifest.exe uninstall"/>
<InstallExecuteSequence>
<Custom Action="RunTopShelfServiceInstall" After="InstallFiles">
NOT Installed
</Custom>
<Custom Action="RunTopShelfServiceUninstall" After='InstallInitialize'>
(NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
</InstallExecuteSequence>
</Fragment>
</Wix>
Are you going to register a service using a custom action?
You also have to handle uninstall, repair actions.
It's much simpler to use standard MSI feature to install services:
http://wixtoolset.org/documentation/manual/v3/xsd/wix/serviceinstall.html
If you want to use custom actions for this purpose and UAC is enabled your service won't be installed due to permissions.
You have to use deferred and not impersonated custom action scheduled before InstallFinalize (after InstallFinalize custom actions can't be scheduled).

Changing the TARGETDIR in WiX

I am having problems setting the TARGETDIR path. I used dark.exe to reverse engineer a working MSI file and read any posts I could find on this subject, but I seem to be unable to set the TARGETDIR to point to the path ProgramFiles\Manufacturer\Product. Below is a distilation of my WXS file which results in my application being installed to the root of my D-drive for some reason:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Name="FBL - Some App"
Language="1033"
Version="1.0.0.0"
Manufacturer="Foo & Bar Limited"
UpgradeCode="780286c6-e064-4402-80d8-dd2c68b56c04">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine"
Comments="Performs some operation that is important" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<Media Id="1" Cabinet="App.1.0.0.cab" EmbedCab="yes" />
<CustomAction Id="setTARGETDIR"
Property="TARGETDIR"
Value="[ProgramFilesFolder][Manufacturer]\[ProductName]"
Execute="firstSequence"
Return="check" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="C__App.exe"
Guid="{074586E9-A675-2734-A4CD-1CE520922A41}">
<File Id="F__App.exe"
Name="App.exe"
KeyPath="yes"
Assembly=".net"
AssemblyManifest="F__App.exe"
AssemblyApplication="F__App.exe"
DiskId="1"
Source="D:\SomePath\bin\Debug\App.exe" />
</Component>
</Directory>
<Feature Id="DefaultFeature" ConfigurableDirectory="TARGETDIR" Level="1">
<ComponentRef Id="C__App.exe" Primary="yes" />
</Feature>
<Icon Id="favicon.ico" SourceFile="d:\SomePath\favicon.ico" />
<Property Id="ARPPRODUCTICON" Value="favicon.ico" />
<UI />
<InstallExecuteSequence>
<Custom Action="setTARGETDIR" Before="CostFinalize" />
</InstallExecuteSequence>
</Product>
</Wix>
I'm sure I am missing something simple, but I cannot find any further information on what to do from here.
The following modifications were needed:
<CustomAction Id="SetTARGETDIR"
Directory="TARGETDIR"
Value="[ProgramFilesFolder][Manufacturer]\[ProductName]"
Return="check" />
and
<InstallExecuteSequence>
<Custom Action="SetTARGETDIR" After="InstallValidate" />
</InstallExecuteSequence>
Explanation: Use the Directory attribute instead of a property (it's a type 35 custom action) and schedule this action after InstallValidate in the execute sequence - that's when directories are checked for write access and truly set.
(Thanks to Narina Chandra Sekhar, from the WiX user group for the answer on this.)
This is strange...I had the same issue but your answer didn't work for me. All I needed was this:
<Product>
<SetProperty Id='TARGETDIR' Value='[ProgramFilesFolder][Manufacturer]\[ProductName]\' Before='FindRelatedProducts' />
...
</Product>
But then again I think something else in my installer may have been setting the TARGETDIR directory from the property; I was working with some legacy stuff.
Edit: Actually, that was a bad idea. A lot of times, some of these custom actions that are built in can be called at different parts of the installation process, so its just better to add a custom action to set the property.
Here is what worked for me:
<Product>
<CustomAction Id='SetTARGETDIR' Property='TARGETDIR' Value='[ProgramFilesFolder][Manufacturer]\[ProductName]\'/>
...
</Product>
<InstallUISequence>
<Custom Action='SetTARGETDIR' Sequence='1'/>
...
</InstallUISequence>
<AdminUISequence>
<Custom Action='SetTARGETDIR' Sequence='1'/>
...
</AdminUISequence>
Nothing worked for me so what I did is to run the msi with a command line setting the property of the installation directory. By default my program would be installed to drive C but sometimes I wanted it to be installed to D drive so here is what I did:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONROOTDIRECTORY" Name="XServer">
</Directory>
</Directory>
</Directory>
Here is the command line:
XServer.msi /L*v log.log APPLICATIONROOTDIRECTORY="D:\Program Files (x86)\XServer"
This actually worked for me. The CostFinalize action is where TARGETDIR Directory is defined.
<SetProperty Id="TARGETDIR" Value="[ROOTDRIVE]MyCompany" Sequence="first" Before="CostFinalize">NOT Installed AND NOT TARGETDIR</SetProperty>
I tried changing the installation dir via custom action (cause I needed code to figure out the path with code - long story), and what solved it for me what the timing - I had to schedule the custom action to:
After="CostInitialize"

How to correctly use WixAppFolder for install without UAC?

I have created a minimal installer with "WixAppFolder" set to "WixPerUserFolder". Application installs in
HOME\AppData\Local\Apps\APPNAME as expected, but installer shows same UAC prompt for both per-user and per-machine install (under normal user this prompt has 'enter administrator password'). I'm using Windows 7 Ultimate 64-bit. The installer GUI for "Install just for you" says thet "you do not need local administrator privileges'. But it is not true - local administrator priviliges are required. What i'm doing wrong? Installer source code:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="Test" Language="1033" Version="1.0.0"
Manufacturer="Me"
UpgradeCode="bb39686c-d77a-4bc4-bbd8-f13b1e0ec26c">
<Package InstallerVersion="200" Compressed="yes" />
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<UIRef Id="WixUI_Advanced" />
<Property Id="ApplicationFolderName" Value="test_app" />
<Property Id="WixAppFolder" Value="WixPerUserFolder" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="APPLICATIONFOLDER" Name="test_app">
<Component Id="c_test" Guid='*'>
<File Id='test_txt' Name="test.txt" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id='f_test' Title="Test" Level='1' >
<ComponentRef Id='c_test' />
</Feature>
</Product>
</Wix>
First, set your Package/#InstallScope="perUser". Then you'll not want to default your application folder to ProgramFilesFolder because that is a per-machine location (pick a per-user location like LocalAppDataFolder). After that, it seems like things should work.
After long conversations with Wix team i found following:
Until windows 7 it is not possible for windows installer to have a single installation that can install both per user or per machine.
The UI text is a bug.