Wix CopyFile only on target machine - wix

I need to be able to copy a file that exists on the target machines hard-drive based on a registry setting that holds the folder path.
I have been trying to get this going for a day or two and am having difficulty, can anyone help?
Thanks,
B

Try something along these lines:
<Component Id="MyComponent" Guid="E5FF53DE-1739-42c4-BE37-60F810C9CD69">
<Condition>MYTESTDIR</Condition>
<CopyFile Id="fileToCopy.datCopy" SourceName="[MYTESTDIR]fileToCopy.dat" DestinationProperty="WEBSERVICEBINFOLDER" />
</Component>
You can populate MYTESTDIR with a value from the registry using a RegistrySearch.

You can first search your registry for the file as follows:
<Property Id="PROPERTYNAME" Secure="yes">
<RegistrySearch Id="SomeID"
Root="HKLM"
Type="raw"
Key="SOFTWARE\SomeFolder\SomeSubFolder"
Win64="yes"
Name="InstallPath">
<DirectorySearch Id="REQUIREDDIRECTORY" AssignToProperty="yes" Depth="1" Path="THEEXPECTEDPATH">
</DirectorySearch>
</RegistrySearch>
</Property>
Then use a Custom Action to set the file name
<CustomAction Id="SETFILE"
Property="FILE"
Value="[PROPERTYNAME]file.extension" />
and then copy file as described by the previous answer...
<CopyFile Id="fileToCopy.datCopy" SourceName="[FILE]" DestinationProperty="[YOURDESTINATION]" />

Related

Check file version from file full path

I need to check service executable version before proceed my installation.
I have read full path for registered service, from registry:
<Property Id="SOME_SERVICE_PATH">
<RegistrySearch Id="FindServicePath" Type="raw" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\TARGET_SERVICE" Name="ImagePath" />
</Property>
After that I tried to perform file search like below:
<Property Id="TARGET_SERVICE_UNSUPPORTED">
<DirectorySearch Id="ServiceParticularVersionSearch" Path="[SOME_SERVICE_PATH]">
<FileSearch Name="Service.exe" MaxVersion="2.5.0.1" />
</DirectorySearch>
</Property>
And this not ganed me results.
I suppose the problem is in the value I passed to DirectorySearch Path property.
According to the Wix documentaion Path should be initialized with
"Path on the user's system. Either absolute, or relative to containing directories"
Unfortunately, there is no place in the registry I can read service installation directory. This is 3d party component.
Are there any solutions here? important moment - Its forbidden to use custom actions in our project
As it turned out, the answer was in Type parameter of RegistrySearch element. If I assign "file" to it, I will be able to apply FileSearch on path I read and check executable version.
Another solution here is to use remark from RegistrySearch Element documentation
file
The registry value contains the path to a file. To return the full file path you must add a FileSearch element as a child of this element; otherwise, the parent directory of the file path is returned.
I mean "otherwise, the parent directory of the file path is returned"
Solution 1
<Property Id="TARGET_SERVICE_UNSUPPORTED">
<RegistrySearch Id="FindServicePath" Type="file" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\TARGET_SERVICE" Name="ImagePath" />
<FileSearch Name="Service.exe" MaxVersion="2.5.0.1" />
</DirectorySearch>
</Property>
Solution 2
<Property Id="SOME_SERVICE_PATH">
<RegistrySearch Id="FindServicePath" Type="file" Root="HKLM" Key="SYSTEM\CurrentControlSet\Services\TARGET_SERVICE" Name="ImagePath" />
</Property>
<Property Id="TARGET_SERVICE_UNSUPPORTED">
<DirectorySearch Id="ServiceParticularVersionSearch" Path="[SOME_SERVICE_PATH]">
<FileSearch Name="Service.exe" MaxVersion="2.5.0.1" />
</DirectorySearch>
</Property>

Windows Installer not deleting all files on uninstall

I've seen some similar questions asked on here, but none of the solutions given were very clear or worked for me.
I have an installer (created with WiX) which installs certain files and folders. However, when running the installed application, this creates some folders and copies some files into it. These files and folders are not removed on uninstall.
Edited to Show Code so Far:
This INSTALLDIR property:
<Property Id="INSTALLDIR">
<RegistrySearch Id='Registry' Type='raw' Root='HKLM' Key='Software\$(var.Manufacturer)\$(var.ProductName)' Name='Location' />
</Property>
This Component which should set the install location in the registry:
<Component Id="Registry" Guid="*">
<RegistryKey Root="HKMU" Key="Software\$(var.Manufacturer)\$(var.ProductName)">
<RegistryValue Name="Location"
Type="string"
Value="[INSTALLDIR]"
Action="write"
KeyPath="yes" />
</RegistryKey>
<util:RemoveFolderEx On="uninstall" Property="INSTALLDIR" />
</Component>
This does create a record in the registry with the install location, but I'm not sure how to adapt this code to making note of the 'public' directory and removing it - I don't know where the util:RemoveFolderEx should go either (inside which component)
The clearest tutorial I've seen is this one (except that it does have an apparent error).
Replace this block:
<!--
RemoveFolderEx requires that we "remember" the path for uninstall.
Read the path value and set the APPLICATIONFOLDER property with the value.
-->
<Property Id="APPLICATIONFOLDER">
<RegistrySearch Key="SOFTWARE\$(var.Manufacturer)\$(var.SkuName)" Root="HKLM" Type="raw" Id="APPLICATIONFOLDER_REGSEARCH" Name="Path" />
</Property>
with this one:
<!--
RemoveFolderEx requires that we "remember" the path for uninstall.
Read the path value and set the FOLDERTOREMOVE property with the value.
-->
<Property Id="FOLDERTOREMOVE">
<RegistrySearch Key="SOFTWARE\$(var.Manufacturer)\$(var.SkuName)" Root="HKLM" Type="raw" Id="APPLICATIONFOLDER_REGSEARCH" Name="Path" />
</Property>
and this block:
<util:RemoveFolderEx On="uninstall" Property="APPLICATIONFOLDER" />
with this one:
<util:RemoveFolderEx On="uninstall" Property="FOLDERTOREMOVE" />
and you should have a working test.
The reason for using two different properties is given here and here (among with other places).
If you can derive the path from other values you may have set during installation that Windows Installer will preserve for you, such as ARPINSTALLLOCATION, then you can adjust the above implementation to get what you need without having to create your own registry keys.
Builds on B. Murri's answer:
Example: your application installs new files or folders in 'installdir/public'. These files aren't being deleted as they weren't added by the installer.
First, you need to create a registry value which will store where your public directory is installed. This is in case the user changes the install directory.
<!-- Note that the RegistryValue Value is being set to the 'public' directory ID -->
<DirectoryRef Id='INSTALLDIR'>
<Component Id="RemovePublicDir" Guid="your-guid-here">
<RegistryKey Root="HKCU" Key="Software\$(var.Manufacturer)\$(var.ProductName)">
<RegistryValue Name="Location"
Type="string"
Value="[PUBLIC]"
Action="write"
KeyPath="yes" />
</RegistryKey>
<CreateFolder Directory="PUBLIC"/>
<util:RemoveFolderEx Property="FINDPUBLICDIR" On="uninstall"/>
<RemoveFolder Id="PUBLIC" On="uninstall"/>
</Component>
</DirectoryRef>
You now need to add a property which will search for this registry value later on. Make sure your Root value above matches the one below:
<Property Id="FINDPUBLICDIR">
<RegistrySearch Id='Registry' Type='raw' Root='HKCU' Key='Software\$(var.Manufacturer)\$(var.ProductName)' Name='Location' />
</Property>
Add your manufacturer name and product name to variables, like this:
<?define Manufacturer = "My Company"?>
<?define ProductName = "Test Application"?>
Now make sure you call this Component in your Feature tag:
<Feature Id="FeatureId">
<ComponentRef Id="RemovePublicDir" />
</Feature>

Conditional property in wix script

I used the below property so i could avoid the add or remove option in the control panel
<Property Id="ARPSYSTEMCOMPONENT" Value="1" />
But i need to make it dynamic .I want to read the value in the registry. If a value mathes my condition i will include this orelse i wont include this line my partial code is as follows
<Property Id="NETFRAMEWORK20">
<RegistrySearch Id="NetFramework20"
Root="HKLM"
Key="Software\Microsoft\NET Framework Setup\NDP\v2.0.50727"
Name="Install"
Type="raw" />
</Property>
//Some Conditon
<Condition Message="I will create the Add or remove option since the softwar i look for s not present">
<![CDATA[Installed OR NETFRAMEWORK20]]>
</Condition>
<Property Id="ARPSYSTEMCOMPONENT" Value="1" />
//or else
Thank in Advance
Try using SetProperty. Means, instead of:
<Property Id="ARPSYSTEMCOMPONENT" Value="1" />
try:
<SetProperty Id="ARPSYSTEMCOMPONENT" After="InstallInitialize" Value="1">
<![CDATA[~~~CONDITION~~~]]>
</SetProperty>
As a side note, I would recommend first, not to hide staff you install from add/remove, and second, use standard .NET framework extension for checking if .NET framework is installed instead of inventing your own method with registry search.

Is it possible to read from 64 and 32-bit registry entries in the same installation?

In my installation I need to check presence of 64-bit entry at first.
And read its value if it is present in 64-bit part of registry.
If entry is absent then I need to try to read this entry from 32-bit registry part(Wow6432Node).
I need to read it directly from wxs file or from custom action on VBScript.
Is it possible to do?
If you're running a 64bit MSI you can set two AppSearch/RegLocator entries using the style:
<Property Id="MY_32BIT_REG">
<RegistrySearch Id="my32bitreg"
Root="HKLM"
Key="SOFTWARE\My Company"
Name="foo"
Type="raw"
Win64="no" />
</Property>
<Property Id="MY_64BIT_REG">
<RegistrySearch Id="my64bitreg"
Root="HKLM"
Key="SOFTWARE\My Company"
Name="foo"
Type="raw"
Win64="yes" />
</Property>
These entries will check the appropriate "HKLM\SOFTWARE\My Company" and "HKLM\SOFTWARE\Wow6432Node\My Company" registry hives.

Using WiX, how to skip a component when a certain registry key does not exist?

I want to copy some files into a directory in another product's installation tree, but only if that product is installed. So I figured I could set a property based on a registry search to find that product's installation root. Then I could use the property in a condition element on the component element.
Here is my code. For some reason, I am getting an error when the other product is not installed and the registry search comes up empty since the registry key will not be found.
<Property Id="PRODUCTPATH">
<RegistrySearch Id="PRODUCTPATH" Root="HKLM" Key="_MY_KEY_" Name="_MY_NAME_" Type="raw" />
</Property>
<SetProperty Id="PRODUCTBINPATH" Value="[PRODUCTPATH]\BIN" After="AppSearch"/>
<Component Id="CommonDLLs" Guid="_MY_GUID_" Directory="INSTALLLOCATION">
<Condition>PRODUCTPATH</Condition>
<RegistryValue Id="_MY_ID_" Root="HKLM" Key="_MY_KEY_2" Name="Installed" Value="1" Type="integer" KeyPath="yes" />
<CopyFile Id="myfile1.dll" FileId="myfile1.dll" DestinationProperty="PRODUCTPATH" DestinationName="myfile1.dll"/>
<CopyFile Id="myfile2.dll" FileId="myfile2.dll" DestinationProperty="PRODUCTPATH" DestinationName="myfile2.dll"/>
</Component>
Try to use the util:RegistrySearch instead of RegistrySeach
This element comes with Util Extension. Check here if you don't know how to use extensions.
The util:RegistrySearch has an attribute (Result) for only checking if the key exists or not.
It would be like that:
<util:RegistrySearch
Id="PRODUCTPATH"
Variable="PRODUCTPATH"
Root="HKLM"
Key="_MY_KEY_"
Format="raw"
Result="exists">
Actually, all you have to do is add a condition to the SetProperty element like this:
<Property Id="PRODUCTPATH">
<SetProperty Id="PRODUCTBINPATH" Value="[PRODUCTPATH]\BIN" After="AppSearch">PRODUCTPATH</SetProperty>