Rename Existing Folder using Wix - installation

Our applications installs in a offline network that we generally don't have access to. It is also a high-availability application. We need our old application folder to still be available for use by our user, so we would like to rename the current application folder before installing the new one. That way, if we have some bugs that are no-go, we need them to be able to quickly revert to the old program.
Is this possible with Wix?
Also, we know it's not ideal, but it's what we have, so please just answer the question instead of saying "don't do that".

Just create Custom action that will start before CostFinalize and move your folder.
For example:
<InstallExecuteSequence>
<Custom Action="RenameFolder"
Before="CostFinalize"/>
</InstallExecuteSequence>
<CustomAction Id="RenameFolderCustomAction" BinaryKey="YourCustomActionDll" DllEntry="RenameFolderMethod" Execute="immediate" Impersonate="no" Return="check" />
And Your custom action will look like:
[CustomAction]
public static ActionResult RenameFolderMethod(Session session)
{
session.Log("Begin RenameFolderMethod");
Directory.Move(source, destination);
return ActionResult.Success;
}
Also, you'll need to add custom action that will copy it back in case of error or cancel. For this purpose you can use OnExit custom action.
<InstallExecuteSequence>
<Custom Action="RenameFolder" Before="CostFinalize"/>
<Custom Action="InstallationFailed" OnExit="cancel" />
<Custom Action="InstallationFailed" OnExit="error" />
</InstallExecuteSequence>
<CustomAction Id="InstallationFailed" BinaryKey="YourCustomActionDll" DllEntry="InstallationFailedMethod" Execute="immediate" Impersonate="no" Return="check" />
And action will be the same, just with reversed parameters:
[CustomAction]
public static ActionResult InstallationFailedMethod(Session session)
{
session.Log("Begin InstallationFailedMethod");
Directory.Move(destination, source);//move it back
return ActionResult.Success;
}
Also you can use properties to store source and destination paths. And you can even define them while running your msi if needed.
How to add custom actions in general

Related

Executing a CustomAction in Wix with 'if exist'

Hi I would like to perform the following CustomAction when installing my program:
<!--Include the custom action for overwrite Client.config-->
<CustomAction Id="SetCmdLineParams" Property="QtExecCA" Value='if exist "[CURRENTDIRECTORY]\Client.config" ("xcopy" /Y "[CURRENTDIRECTORY]\Client.config" "[INSTALLFOLDER]")' Execute="immediate" />
<CustomAction Id="QtExecCA" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="no"/>
<!--Include the InstallExecuteSequence for overwrite Client.config-->
<InstallExecuteSequence>
<Custom Action="SetCmdLineParams" After="CostFinalize"/>
<Custom Action="QtExecCA" Before="InstallFinalize" />
</InstallExecuteSequence>
Unfortunately this doesn't work because: CAQuietExec: Command string must begin with quoted application name.
But if I quote "if exist", then the command does not work. What can I do now?
if exist is a feature of cmd.exe. You'd need to say cmd /c first or create a .bat file and call that.
Honestly though, this is really fragile code. For one CURRENTDIR isn't always going to be what you think it is. You should write a C++ or C# custom action that uses the OriginalDatabase property to get where the MSI is running from and copy the config file from there.
Another approach I've used very successfully in the past is to write a utility that can transform a seed MSI by embedding a user provided config file into it. Now the deployment story is simplified.

wix - session.message is not showing at time of installation

Wix CustomAction [C#] session.Message(Messagebox) is not displayed during installation.
I have a Session.Message added in my custom action,
public static ActionResult DisplayConfirmationMessage(Session session) {
Record record = new Record();
record.FormatString = pMessage;
Session.Message(InstallMessage.Error
| (InstallMessage)System.Windows.Forms.MessageBoxIcon.Warning
| (InstallMessage)System.Windows.Forms.MessageBoxButtons.OK, record);
}
And in wxs file custom action
<CustomAction Id="RestartAction" BinaryKey="CustomActions" DllEntry="DisplayMessage" Execute="immediate" Return="check" />
and in install execute (only one custom action call):
<InstallExecute>
<Custom Action="RestartAction" After="InstallFinalize"></Custom>
</InstallExecute>
the message box is displayed only at time of uninstall. But during installation it is getting logged to session.Log.
I have checked with 'NOT Installed AND NOT REMOVE' still same results.
I am blocked on this, please help.
Thank you in advance.

Wix : Declare or set property after ResolveSource

I try to search a file in my project. The problem is I use the var "SourceDir" and it's work fine in install with UI but no with silent install.
I found it's because SourceDir is not setted before I try to used it in silent mode.
That's why I want to set my property after the "ResolveSource" action
<Property Id='CUSTOMCONFIGFILEEXISTS'>
<DirectorySearch Id='DirSearch' Path='[SOURCEDIR]' Depth='0'>
<FileSearch Id='FileSearch' Name='EasyFolderApplicationDesktopToolbar.exe.config'/>
</DirectorySearch>
</Property>
...
<Component Id="CustomMainExecutableConfig" Guid="A952C40B-0274-4EA8-8A48-0216395455CF" Directory="INSTALLDIR" NeverOverwrite="yes">
<Condition>CUSTOMCONFIGFILEEXISTS</Condition>
<CopyFile Id="CustomEasyFolderApplicationDesktopToolbarCONFIG" SourceProperty="CUSTOMCONFIGFILEEXISTS" DestinationProperty="INSTALLDIR" />
<!--<CopyFile Id="CustomEasyFolderApplicationDesktopToolbarCONFIG" SourceProperty="CONFIGFILEEXISTS" DestinationProperty="INSTALLDIR" />-->
</Component>
I already try this, with no result :
<Property Id='CUSTOMCONFIGFILEEXISTS'>
<DirectorySearch Id='DirSearch' Path='[Temp]' Depth='0'>
<FileSearch Id='FileSearch' Name='EasyFolderApplicationDesktopToolbar.exe.config'/>
</DirectorySearch>
</Property>
<CustomAction Id='SET_CUSTOMCONFIGFILEEXISTS'
Property='Temp'
Value='[SourceDir]'/>
...
<InstallExecuteSequence>
<ResolveSource After="CostInitialize" ></ResolveSource>
<Custom Action='SET_CUSTOMCONFIGFILEEXISTS' After='ResolveSource'></Custom>
<Custom Action="AlreadyUpdated" After="FindRelatedProducts">SELFFOUND</Custom>
<Custom Action="NoDowngrade" After="FindRelatedProducts">NEWERFOUND</Custom>
<RemoveExistingProducts After="InstallExecute" />
</InstallExecuteSequence>
I already see this How do I use the SourceDir MSI property in WiX?
But I don't know how to do...
Can you help me ?
That search is ultimately an AppSearch, and in a WiX-built MSI that's the first thing that runs, so your 'CUSTOMCONFIGFILEEXISTS' property has already been processed by the search, so it's false by the time that component results in the component not being installed and the copyfile not being done. So the reason for the failure is not ResolveSource - it's because 'CUSTOMCONFIGFILEEXISTS' is being set false and you are conditioning the component and the copyfile on that false condition.
IMO you are over-thinking this. Don't bother with a search. Just pick a component relevant to the file you want to copy (don't invent a transitional component for it with a condition). Add the CopyFile to that component with [SourceDir] as the source. If the file is there it will be copied, if not then it won't be.
Don't add an unconditional ResolveSource action because it will happen every time the an installer action takes place (repair, removing features, patches, uninstall) and that is generally unnecessary. In any case I am certain you do not need a ResolveSource. There is an implicit ResolveSource at first install or it wouldn't even know where the MSI was! Just do the copyfile as I suggested.

Custom Action After InstallInitialize to check the Drive Existence

I have written a custom action in C# to check for the drive existence like below, I got stuck in between.
[CustomAction]
public static ActionResult MySimpleAction(Session session)
{
if (Directory.Exists("F:\\"))
{
return ActionResult.Success;
}
else
{
return ActionResult.Failure;
}
}
And in wxs file, I am running the custom action as like below.
<Binary Id="myAction" SourceFile="MyCustomAction.CA.dll" />
<CustomAction Id="myActionId"
BinaryKey="myAction"
DllEntry="MySimpleAction"
Execute="immediate"
Return="check" />
<InstallExecuteSequence>
<Custom Action="myActionId" After="InstallInitialize" > </Custom>
</InstallExecuteSequence>
If I run the msi in the target machine where I have F:\ drive then installation succeeds, if the target machine doesn't have F:\ drive then Setup failed, I am getting error as "Setup wizard ended prematurely because of an error. Your system has not been modified."
What I am trying to do here is, if F:\ drive is available in the target computer (My Custom action succeeds), I want to set my root drive as F:\, and I want to install the application in F:\MyApp\Bin
<Property Id="ROOTDRIVE"><![CDATA[F:\]]></Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLFOLDERLOCATION" Name="MyApp">
<Directory Id="INSTALLLOCATION" Name="Bin">
if F:\ drive is not available in the target computer (My Custom action fails), I want to set my root drive as C:\, and I want to install in C:\MyApp\Bin
<Property Id="ROOTDRIVE"><![CDATA[C:\]]></Property>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLFOLDERLOCATION" Name="MyApp">
<Directory Id="INSTALLLOCATION" Name="Bin">
How can I set the root drive property by using this custom action?
Thanks for the help!
When using an immediate Custom Action, you can set property values by using session["PROPERTYNAME"] so in your case you could use session["ROOTDRIVE"] = "F:\\"; in your Custom Action.
The reason it's failing at the moment is that you are returning a Failure message from your custom action, and since you have specified Return="check", the installer checks the return value, and fails the install if the Custom Action has failed.
You are on the right track. Here's what I do differently.
1) I use the DriveInfo class to see if the drive exists and it's of DriveType Fixed. (Not CDROM, USB Drive, Network....)
2) The custom action is scheduled in both the UI and Execute sequence after AppSearch and sets a property called something like InstallDirOverride. The custom action always returns ActionResult.Success.
3) I use a Set Property custom action (wxs element) to assign InstallDirOverride to INSTALLLOCATION (or INSTALLDIR... whatever you have called your main directory ) with the condition that INSTALLLOCATION doesn't yet have a value and InstallDirOverride does have a value and Not Installed. This custom action gets scheduled in both the UI Sequence and ExecuteSequence prior to CostInitialize.
The result of all this is an installer that defaults to C:\Program Files\My Company\My Product but changes it's behavior to default to something else based on the business rules in your C# custom action. This gives you the flexibility to default the way you want for a specific platform environment and yet still be complaint to Windows Standards when your platform is missing that resource.
I thank Christopher Painter and ChrisPatrick for helping me!!! the below code made the trick to work.
[CustomAction]
public static ActionResult MySimpleAction(Session session)
{
session.Log("DriveInfo Starts");
DriveInfo[] drives = DriveInfo.GetDrives();
foreach (DriveInfo d in drives)
{
if (d.Name.Contains("F") & d.IsReady == true & d.DriveType.ToString() == "Fixed")
{
session["TARGETDIR"] = "F:\\";
}
else
{
session["TARGETDIR"] = "C:\\";
session.Log("No F:\\ Drive Found!!!!");
}
}
session.Log("DriveInfo Ends");
return ActionResult.Success;
And in the .wxs file,
<Binary Id="myAction" SourceFile="MyCustomAction.CA.dll" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLFOLDERLOCATION" Name="MyApp">
<Directory Id="INSTALLLOCATION" Name="Bin">
<CustomAction Id="myActionId" BinaryKey="myAction" DllEntry="MySimpleAction" Execute="immediate" Return="check" />
<InstallUISequence>
<Custom Action="myActionId" Before="CostFinalize" > NOT Installed </Custom>
</InstallUISequence>

How do I make a WiX installer force VS to install templates?

I've got a WiX installer that is meant to update VS 2010 templates after installing them. The code I'm using is as follows:
<CustomAction
Id="InstallTemplates"
ExeCommand=""[VISUALSTUDIODIR]devenv.exe" /installvstemplates"
Directory="VISUALSTUDIODIR"
Execute="commit"
Return="check"
HideTarget="no"
Impersonate="no"/>
<InstallExecuteSequence>
<Custom Action="InstallTemplates" Before="InstallFinalize"></Custom>
</InstallExecuteSequence>
In the above, VISUALSTUDIODIR refers to the correct location, and templates are correctly deployed. However, it seems that the command does not get called, so no templates are actually installed. What am I doing wrong?
WiX has built-in functionality to do that. Add a reference to WixVSExtension.dll and add the following authoring:
<CustomActionRef Id="VS2010InstallVSTemplates" />
Make sure that VISUALSTUDIODIR is an actual directory in your MSI package (it's saved in Directory table). This is a requirement for this type of custom action.
Also, try creating an installation log and search for your custom action to see what happens.

Resources