Hi there I am having a problem getting my Wix installer to remove elements on Uninstall. The problem folders and files are located on our corporate specified programdata folder 'D:\programdata'. The folders get created OK, however will not remove on Uninstall. The folder structure is as follows
D:\programdata
Company Name
App Name
Logs
QueryOutput
The following is an excerpt from the relevant section of the product.wxs file:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="CommonAppDataFolder" Name="CommonAppData" >
<Directory Id="dirCompanyAppData" Name="Company Name">
<Directory Id="dirAppNameAppData" Name="AppName">
<Component Id="cmpDirCommonAppData" Guid="{F808944A-D898-43F3-BA1D-A35A3FD7DF41}" KeyPath="yes">
<CreateFolder Directory="dirAppNameAppData" />
<RemoveFile Id="PurgeAppName" Name="*.*" On="uninstall" />
<RemoveFolder Id="idDirAppNameAppData" On="uninstall" Directory="dirAppNameAppData" />
</Component>
</Directory>
<Component Id="cmpDirCompanyName" Guid="{A1E7E75A-D582-40C5-BD6B-D36BFB11795E}" KeyPath="yes">
<RemoveFile Id="PurgeCompanyName" Name="*.*" On="uninstall" />
<RemoveFolder Id="idDirCompanName" On="uninstall" Directory="dirCompanyNameAppData" />
</Component>
</Directory>
</Directory>
<Directory Id="ProgramFilesFolder">
... etc
Note company and application identifying elements have been replaced in the code. I have left out the remainder of the wxs file for brevity and because I believe the relevent code is included in this extract. Any assistance much appreciated, this has me stumped.
Kind Regards
Paul J.
From RemoveFolder definition:
Remove an empty folder if the parent component is selected for installation or removal.
In your case the AppData folder probably has user specific configuration in it like it is supposed to.
I think all the component planning is done first, then executed. So, RemoveFile will plan all the files in that folder to be removed and RemoveFolder will decide it shouldn't delete the folder because at the time of planning, the folder still has stuff in it that is not part of the installation included components and therefore not empty.
You will need to use util:RemoveFolderEx. Again there is another caveat to using this.
Because it might dramatically affect Windows Installer's File Costing, the temporary rows must be written before the CostInitialize standard action. Unfortunately, MSI doesn't create properties for the Directory hierarchy in your package until later, in the CostFinalize action.
So you need to manually set a directory based off of a property you probably read from the registry before the WixRemoveFoldersEx action which I think is scheduled just before CostInitialize.
Related
My installer requires that I create some folders that cannot be uninstalled. Is there a way to make directories as permanent just like components?
For an empty folder, I am using below code and worked out successfully :-
<Directory Id="dir04517D319ACA03A67ABEF6DCD0061557" Name="paperworks">
<Component Id="cmpC9B5254FDBE0CC06C0A860BF1CAE69E0" Guid="{A23C24A1-7FE5-4908-9739-AEBE3BCC7109}" KeyPath="yes" Permanent="yes">
<CreateFolder />
</Component>
</Directory>
However, for a directory with files in it, how do I make that folder permanent?
I am struggling against the issue with wix toolset: why after I uninstall an application some folders including the "logs" are not deleted? is it a bug or not?
<Directory Id="logs" Name="logs">
<Component Id="logs" Guid="0A4D0A3F-2E0D-1B1A-1C6D-1A0F8FAAABC6" Win64="$(var.is64)">
<CreateFolder Directory="logs">
<Permission GenericAll="yes" User="Everyone" />
</CreateFolder>
<RemoveFolder Id="logs" On="uninstall"></RemoveFolder>
</Component>
</Directory>
Sometimes if the application you install generates files or folders after the installation, that can prevent WiX from removing the parent folder during uninstall.
If there are log files created after install, you can purge them by adding this to your existing component:
<RemoveFile Id="RemoveLogFiles" Name="*.*" On="uninstall" />
If your application also creates subdirectories and RemoveFile doesn't get rid of them, I would look into using RemoveFolderEx(http://wixtoolset.org/documentation/manual/v3/xsd/util/removefolderex.html). This would require you to to create a Property and write the directory path to a place in the registry so you can set the Property before RemoveFolderEx runs. You can't just use the Directory Id because RemoveFileEx runs before the MSI creates the Directory properties. Read the link I provided if my explanation didn't make sense to you.
Hope this helps!
Just trying to setup an installer for the first time, bit confusing.
This code;
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="FTSM" Name="FTSM">
<Directory Id="INSTALLFOLDER" Name="FCP" FileSource="..\FCP\bin\Debug\">
<Component Id="MainExecutable">
<File Id="FCPEXE" Name="FCP.exe" Source="FCP.exe" KeyPath="yes"/>
<Shortcut Id="startMenuFCP" Directory="ProgramMenuDir" Name="FCP" WorkingDirectory="INSTALLDIR" Icon="FCP.exe" IconIndex="0" Advertise="yes"/>
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
Doesn't give me any success, I always get System cannot find the file 'FCP.exe'
If I take the FileSource variable and put it into the source variable, like so;
<File Id="FCPEXE" Name="FCP.exe" Source="..\FCP\bin\Debug\FCP.exe" KeyPath="yes"/>
Then everything works perfectly. I can build the WiX project without errors and it generates an installer that works as expected.
The file structure is as follows;
Main
-> FCP (Main Project)
--> bin
---> Debug
----> FCP.exe
-> Installer (WiX Project)
--> Product.wxs
Obviously not a big issue for this Project, but when I run into multiple components, it's going to be a lot handier to specify the FileSource once.
From Bob Arnson's blog-entry Choosing your payloads:
When you use the File/#Name attribute and don’t use the File/#Source
attribute, the compiler constructs an implicit path to the file based
on the file’s parent component directory plus the name you supply.
Thus when File/#Source is present WiX will use it regardless of any Directory/#FileSource, if it is not then the source path is constructed by combining Directory/#FileSource and File/#Name.
So, a bit of a lucky find really, but it turns out if you use the references folder from within the WiX project you can then do some neat referencing in the wxs file.
I referenced my project and could then do the following;
<File Id="FCPEXE" Name="FCP.exe" Source="$(var.FCP.TargetDir)\FCP.exe" KeyPath="yes"/>
I'm creating a program which is being installed by Wix, using VS 2010 and I've already got the product.wxs ready.
In my wxs file, I've got directory definitions which looks like this:
<SetDirectory Id="INSTALLFOLDER" Value="[WindowsVolume]Myapp" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLFOLDER" Name="Myapp">
<Directory Id="Myapp_Installer_Dir" Name="Myapp">
<Directory Id="BIN" Name="Bin" />
<Directory Id="ICONS" Name="Icons" />
</Directory>
</Directory>
</Directory>
And then I got these file installation definitions:
<DirectoryRef Id="Myapp_Installer_Dir">
<Component Id="INSTALLER_Myapp" Guid="{94F18477-8562-4004-BC6F-5629CC19E4CB}" >
<File Source="$(var.Myapp.TargetPath)" KeyPath="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="BIN">
<Component Id="INSTALLER_Data" Guid="{545FB5DD-8A52-44D7-898E-7316E70A93F5}" >
<File Source="$(var.Data.TargetPath)" KeyPath="yes"/>
</Component>
...
And it continues in that manner. The files for the "ICONS" directory are defined as well.
I am also using the WixUI_InstallDir dialog set and I got these lines present as well:
<Property Id="WIXUI_INSTALLDIR" Value="Myapp_Installer_Dir" />
<UIRef Id="WixUI_InstallDir" />
The problem is when the user installs the program and changes the value of the installation folder, the files of the "Bin" and "Icons" are installed to their correct path, but the Myapp target is installed to a fix location which was defined at the start as the default installation path.
Why do only the bin and icon files installed to the correct folder the user wanted, but the myapp target does not?
I have finally figured out the problem.
After searching for a while, I came across this document:
WixUI_InstallDir Dialog Set
The relevant part: "The directory ID must be all uppercase characters because it must be passed from the UI to the execute sequence to take effect."
And as you can see in my code: "Myapp_Installer_Dir" does not meet this criteria.
After changing it to "MYAPPINSTALLERDIR", everything worked.
I'm not quite sure, but this is what I think has happened.
When you author a SetDirectory element, you basically add a custom action which sets a directory to the MSI database. As long as you do not specify the sequence it is executed in, it defaults to both, which means execute in both InstallUISequence and InstallExecuteSequence.
Now, when a user changes the installation directory in the wizard, this happens in the UI sequence. Obviously, when the installation enters the execute sequence, the value of INSTALLFOLDER is set to [WindowsVolume]Myapp as it was instructed.
So, you have to rework this somehow. Keep in mind the silent installation as well - there's only execute sequence there.
UPDATE instead of what you have, try something like this:
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="WindowsVolume">
<Directory Id="INSTALLFOLDER" Name="Myapp">
<Directory Id="BIN" Name="Bin" />
<Directory Id="ICONS" Name="Icons" />
</Directory>
</Directory>
</Directory>
And let the user optionally change the INSTALLFOLDER as you do now.
Additionally to the pitfall with capital letters there is also an other one:
You have to mark the ID of the changeable directory as secure. (At least when the setup runs with admin rights.)
Related to Yonatan's answer with the directory ID MYAPPINSTALLERDIR you have to add this:
<Property Id="MYAPPINSTALLERDIR" Secure="yes" />
Related to the example WixUI_InstallDir in the WiX documentation you have to add this:
<Property Id="TESTFILEPRODUCTDIR" Secure="yes" />
Unfortunately this important fact is not mentioned in the WiX example.
We're using WiX to bundle up our ASP.NET code into an MSI installer, and we need to set the [ComputerName]\IIS_WPG group to have modify permissions on a folder (named "CO") under the installation directory. The directory structure looks like this after install
C:\inetpub\wwwroot\MyApp\CO
The CO folder is actually part of the .NET solution file, and when the application is bundled into an MSI, the CO folder is included automatically because there are XML files underneath it which are marked as "Content" (this means that I don't need to explicitly use CreateFolder to create the CO folder underneath MyApp). These XML files are updated by the application, which is why the IIS_WPG needs modify permission.
My question is, how do I set the permission on the CO folder? I thought that I might be able to create the folder in an attempt to overwrite whatever permissions are included by default but it doesn't set the permission - I'm guessing that's because the folder I'm creating is overwritten by the actual folder in the MSI, thereby overwriting the permissions that I've set.
I thought that I might need to create a CustomAction which gets executed at some point before InstallFinalize, but I'm lost because I don't understand how to link the folder creation to the CustomAction. I've tried this
<InstallExecuteSequence>
<Custom Action="SetPermission" Before="InstallFinalize" />
</InstallExecuteSequence>
<CustomAction Id="SetPermission" Directory="CODIRECTORY">
<Directory Id="CODIRECTORY" Name="CO" LongName="CO">
<Component Id="CODIR" Guid="D28C9DA4-D20F-45E6-9C9B-4687177EDF41" DiskId="1">
<CreateFolder>
<Permission GenericAll="yes" User="[ComputerName]\IIS_WPG" />
<Permission GenericAll="yes" User="Administrators" />
<Permission GenericRead="yes" GenericWrite="yes" User="ASPNET" />
</CreateFolder>
</Component>
</Directory>
</CustomAction>
But that gives me this error
error CNDL0049 : The CustomAction element's DllEntry, Error, ExeCommand, JScriptCall, Script, Value, or VBScriptCall attribute was not found; one of these is required.
error CNDL0005 : The CustomAction element contains an unexpected child element 'Directory'
I've also tried to use PermissionEx, but I get this error when using that
error CNDL0005 : The CreateFolder element contains an unexpected child element 'util:PermissionEx'.
even though I added xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" at the top of the file.
How do I get the CustomAction to work and Folder Permissions correct?
Your settings looks quite similar to mine, there are little differences.
We do not set the permissions in a custom action, but with creating the directory.
This one works for us:
<Directory Name="SourceDir" Id="TARGETDIR">
<Directory Id="CommonAppDataFolder">
<Directory Name="$(var.InstallCompany)" Id="CompanyDir">
<Directory Name="$(var.InstallProduct)" Id="ProductDir">
<Directory Name="$(var.InstallFolder)" Id="INSTALLLOCATION">
<Component Id="Permission.InstallFolder" Guid="{7C5234ED-EE92-468A-A765-27E5747705DB}">
<CreateFolder>
<Permission ChangePermission="yes" GenericAll="yes" User="Administrators"/>
<Permission User="Everyone" WriteExtendedAttributes="yes" WriteAttributes="yes" CreateFile="yes" CreateChild="yes" GenericWrite="no" GenericRead="yes" GenericExecute="yes"/>
</CreateFolder>
</Component>
</Directory>
</Directory>
</Directory>
</Directory>
</Directory>
I had to create a CustomAction, similar to what is done in this post
Set Permission Using cacls
I know it's not ideal, but it solves the problem. We could potentially upgrade to Wix 3 and use PermissionEx, but that's a battle I'll have to fight another day.
Not sure it helps, but I did some more investigation and found that we're using Wix 2, so I'm guessing that's why we couldn't use PermissionEx.