Awesome. Thanks so much. I think that got it.
↧
New Post: ExeFileShortcut set working directory to %TEMP%
↧
New Post: Bug in installation to Program Files directory
Hi, Oleg!
I have an installer with managedUI.
During the installation I selected installation folder in standard InstallDir dialog:
C:\Program Files\My Company\My Product
Product is installed to C:\Program Files (x86)\My Company\My Product
In Load event handler
InstallDir=C:\Program Files\My Company\My Product
In BeforeInstall event handler
InstallDir=C:\Program Files (x86)\My Company\My Product
What happened?
I have an installer with managedUI.
During the installation I selected installation folder in standard InstallDir dialog:
C:\Program Files\My Company\My Product
Product is installed to C:\Program Files (x86)\My Company\My Product
In Load event handler
InstallDir=C:\Program Files\My Company\My Product
In BeforeInstall event handler
InstallDir=C:\Program Files (x86)\My Company\My Product
What happened?
↧
↧
New Post: Bug in installation to Program Files directory
No it is not a bug. It is an unfortunate non-intuitive behavior of MSI. I guess MSI handles special folder ProgramFiles in a tricky way and always maps path
In my experiment I tried to eliminate Wix# from the experiment and used the following WiX code:
And it behaves the same way as in your experiment.
After changing the install dir to
If you are trying to install to x64 then you need to use
C:\Program Files
to the actual folder specific to your MSI platform, which is in your case C:\Program Files (x86)
. In my experiment I tried to eliminate Wix# from the experiment and used the following WiX code:
<?xmlversion="1.0"encoding="Windows-1252"?><Wixxmlns="http://schemas.microsoft.com/wix/2006/wi"><ProductId="e2e75b4b-666c-4ae3-8957-4d29c85dc0d9"Name="CustomActionTest"Language="1033"Codepage="Windows-1252"Version="1.0.0.0"UpgradeCode="e2e75b4b-666c-4ae3-8957-4d29b85dc0d8"Manufacturer="OlegShilo"><PackageInstallerVersion="200"Compressed="yes"SummaryCodepage="Windows-1252"Languages="1033"/><MediaId="1"Cabinet="CustomActionTest.cab"EmbedCab="yes"/><DirectoryId="TARGETDIR"Name="SourceDir"><DirectoryId="ProgramFilesFolder"Name="ProgramFilesFolder"><DirectoryId="INSTALLDIR"Name="Test"><ComponentId="Component.readme.txt"Guid="e2e75b4b-666c-4ae3-8957-4d295c7e7230"><FileId="readme.txt"Source="readme.txt"/></Component></Directory></Directory></Directory><UIRefId="WixUI_InstallDir"/><PropertyId="WIXUI_INSTALLDIR"Value="INSTALLDIR"/><FeatureId="Complete"Title="Complete"Absent="allow"Level="1"><ComponentRefId="Component.readme.txt"/></Feature></Product></Wix>
//Corresponding Wix# codevar project = new Project("CustomActionTest", new Dir(@"%ProgramFiles%\Test", new File("readme.txt")); project.UI = WUI.WixUI_InstallDir; project.BuildMsi();
After changing the install dir to
C:\Program Files
the product is still installed to C:\Program Files(86)
.If you are trying to install to x64 then you need to use
project.Platform = Platform.x64
. ↧
New Post: How to guarantee custom actions aren't executed on upgrades
Hello,
I have the following situation:
Setup installs a single .exe and a configuration file
Three custom actions:
Furthermore, the project is using a ManagedProject and ManagedUI. I have a custom dialog that obtains the user input that is necessary and places it into session.CustomActionData, so the custom action in 3 can compose the configuration file. This dialog should ideally be completely skipped if we are in the context of an upgrade.
Given all of this information, how can I make the setup behave correctly when it is in the context of an upgrade? Right now, I have been attempting to use e.UpgradingProductCode / session.Property("UPGRADINGPRODUCTCODE"), but it never seems to work correctly. My versions are all X.Y.ZZZ form, with only ZZZ being incremented in testing so far.
Thanks in advance,
José Maia.
I have the following situation:
Setup installs a single .exe and a configuration file
Three custom actions:
- Installs the exe as a service (calls the console application with a given parameter)
- Uninstalls the exe as a service (calls the console application with a given parameter)
-
Given user input, composes the configuration file
Furthermore, the project is using a ManagedProject and ManagedUI. I have a custom dialog that obtains the user input that is necessary and places it into session.CustomActionData, so the custom action in 3 can compose the configuration file. This dialog should ideally be completely skipped if we are in the context of an upgrade.
Given all of this information, how can I make the setup behave correctly when it is in the context of an upgrade? Right now, I have been attempting to use e.UpgradingProductCode / session.Property("UPGRADINGPRODUCTCODE"), but it never seems to work correctly. My versions are all X.Y.ZZZ form, with only ZZZ being incremented in testing so far.
Thanks in advance,
José Maia.
↧
New Post: How to guarantee custom actions aren't executed on upgrades
Hi José,
One obvious thing that can help is to fix the deployment to follow/respect "separation of concerns" principle.
Your config file does not belong to the deployment as is a part of the configuration. Remove the config file from your setup and update your application in such a way that it creates the config file with the defaults if it doesn't exist. This way you kill a few birds:
As for "UPGRADINGPRODUCTCODE" you are right MSI solution for that is messy. I can only suggest that you can play with upgrades and evaluate the properties as it is done in "Setup Events" sample. This way you may find some magic combination. Though if you follow my first suggestion you don't need to deal with detecting upgrades.
One obvious thing that can help is to fix the deployment to follow/respect "separation of concerns" principle.
Your config file does not belong to the deployment as is a part of the configuration. Remove the config file from your setup and update your application in such a way that it creates the config file with the defaults if it doesn't exist. This way you kill a few birds:
- You can easy reset the config file to defaults by simply deleting it.
- The config file can be auto-resurrected if it got deleted for whatever reason (e.g. by accident).
- Your config file will never be overwritten by setup as setup is not aware about it at all.
- The config file can be created in any location more appropriate than ProgramFiles (e.g. user profile).
- Your product can automatically handle advertised setup scenarios.
-
Resetting/recreation of the config file doesn't longer require running setup in repair mode.
As for "UPGRADINGPRODUCTCODE" you are right MSI solution for that is messy. I can only suggest that you can play with upgrades and evaluate the properties as it is done in "Setup Events" sample. This way you may find some magic combination. Though if you follow my first suggestion you don't need to deal with detecting upgrades.
↧
↧
New Post: How to guarantee custom actions aren't executed on upgrades
Hello,
Thank you for the quick reply. I will evaluate with the team if we have an alternative, but I believe the decision to make configuration and setup a single step is irreversible. I will look into the sample you mention and attempt to figure out a solution. Will report back.
Thank you for the quick reply. I will evaluate with the team if we have an alternative, but I believe the decision to make configuration and setup a single step is irreversible. I will look into the sample you mention and attempt to figure out a solution. Will report back.
↧
New Post: How to guarantee custom actions aren't executed on upgrades
You may also find useful this info.
It's a fragment from the WixSharp.MsiRuntime code doco:
It only confirms how flaky the UPGRADINGPRODUCTCODE handling is.
It's a fragment from the WixSharp.MsiRuntime code doco:
/* http://www.codeproject.com/Articles/132918/Creating-Custom-Action-for-WIX-Written-in-Managed
* Expected to be like this:
* Property Name Install Uninstall Repair Modify Upgrade
* --------------------------------------------------------------------------------------
* Installed False True False True True
* REINSTALL True False True False False
* UPGRADINGPRODUCTCODE True False True True True
*
* Though in the reality it is like this:
* Property Name Install Uninstall Repair Modify Upgrade
* ---------------------------------------------------------------------------------------------------
* Installed <null> 00:00:00 00:00:00 00:00:00 <not tested yet>
* REINSTALL <null> <null> All <null> <not tested yet>
* UPGRADINGPRODUCTCODE <null> <null> <null> <null> <not tested yet>
*
* */
↧
New Post: Bug in setting background image
Hi, Oleg!
I have a managed project with standart UI. I detedted a bug in setting BackgroundImage.
When I set up BackgroundImage with dimensions 493312(standart size) BuildWxs return null.
When I set up BackgroundImage with dimensions 493493 or 164*312, it's OK. But BackgroundImage is resized all over the form.
var project = new ManagedProject("My product",
project.BackgroundImage = @"images\dialog_bmp.png"; project.BannerImage = @"images\dialog_banner.png"; return project.BuildWxs();
I have a managed project with standart UI. I detedted a bug in setting BackgroundImage.
When I set up BackgroundImage with dimensions 493312(standart size) BuildWxs return null.
When I set up BackgroundImage with dimensions 493493 or 164*312, it's OK. But BackgroundImage is resized all over the form.
var project = new ManagedProject("My product",
new Dir(@"%ProgramFiles%\My product\",
new Files(@"Product\*.*"))));
project.UI = WUI.WixUI_InstallDir;project.BackgroundImage = @"images\dialog_bmp.png"; project.BannerImage = @"images\dialog_banner.png"; return project.BuildWxs();
↧
New Post: Saving product settings in registry
Hi, Oleg!
I have a managed project with standart UI. Unfortunatelly, I can't use ManagedUI, because burn doesn't show UI.
After installation I want to save product settings, that user input in UI, in registry. But in SaveSettings function in session there is nothing but "INSTALLDIR".
How can I save user settings?
var project = new ManagedProject("My product",
.......
public class CustomActions
{
in SaveSettings session["ProductName"] throw exception
I have a managed project with standart UI. Unfortunatelly, I can't use ManagedUI, because burn doesn't show UI.
After installation I want to save product settings, that user input in UI, in registry. But in SaveSettings function in session there is nothing but "INSTALLDIR".
How can I save user settings?
var project = new ManagedProject("My product",
new Dir(@"%ProgramFiles%\My product\",
new Files(@"Product\*.*"))),
new ManagedAction(CustomActions.ReadInstallDir, Return.ignore, When.Before, new Step("AppSearch"), Condition.NOT_Installed, Sequence.InstallExecuteSequence | Sequence.InstallUISequence) { Execute = Execute.firstSequence },
new ElevatedManagedAction(CustomActions.SaveSettings, Return.check, When.After, Step.InstallFiles, Condition.NOT_Installed)));
project.UI = WUI.WixUI_InstallDir;.......
public class CustomActions
{
[CustomAction]
public static ActionResult SaveSettings(Session session)
{
try
{
Registry.LocalMachine.CreateSubKey(@"Software\" + session["ProductName"])
.SetValue("InstallationDirectory", session.Property("INSTALLDIR"));
}
catch { }
return ActionResult.Success;
}
[CustomAction]
public static ActionResult ReadInstallDir(Session session)
{
try
{
session["INSTALLDIR"] = Registry.LocalMachine.OpenSubKey(@"Software\" + session["ProductName"]) .GetValue("InstallationDirectory") .ToString();
}
catch { }
return ActionResult.Success;
}
}in SaveSettings session["ProductName"] throw exception
↧
↧
New Post: Bug in setting background image
Wix# does not participate in images handling of the standard UI. The images you specified are simply passed to the WiX as is:
I guess that WiX/MSI dialogs don't do resizing and jus fill the area. Thus most likely you will need to play with the actual sizes of the images.
<WixVariableId="WixUIBannerBmp"Value="images\dialog_banner.png"/><WixVariableId="WixUIDialogBmp"Value="images\dialog_bmp.png"/>
↧
New Post: Saving product settings in registry
> Unfortunatelly, I can't use ManagedUI, because burn doesn't show UI.
Yeah, this is unfortunate. WiX guys scheduled the fix for the next WiX version so let's hope...
> But in SaveSettings function in session there is nothing but "INSTALLDIR".
Yes this is because
Wix# pushes
Read more here: https://wixsharp.codeplex.com/wikipage?title=Deployment%20scenarios#_deferred_actions
> in SaveSettings session["ProductName"] throw exception
You should use
BTW you are probably better off using
Though you still need to nominate (with
Yeah, this is unfortunate. WiX guys scheduled the fix for the next WiX version so let's hope...
> But in SaveSettings function in session there is nothing but "INSTALLDIR".
Yes this is because
SaveSettings
is a deferred custom action and MSI always initializes new completely clean disconnected session object for all deferred actions. It is one of the ugliest MSI architecture flaw. There is a hack/trick that MS offers to address the flaw. You can nominate which session properties you want to carry on from the normal session to the deferred one. It is convoluted but Wix# allows you to do it in a simple way://from project project.DefaultDeferredProperties += ",<your property name>"; //from action new ElevatedManagedAction("OnInstall") { UsesProperties = "INSTALLDIR,<your property name>" }
INSTALLDIR
to the deferred actions by default. Read more here: https://wixsharp.codeplex.com/wikipage?title=Deployment%20scenarios#_deferred_actions
> in SaveSettings session["ProductName"] throw exception
You should use
session.Property("ProductName")
instead. MSI doesn't even allow to access the session object from deferred actions so you need to pull your properties from a complete different session member. And session.Property
always does accessing the property transparently.BTW you are probably better off using
project.AfterInstall
event. It is nothing else but an already prepared for you 'after Install' ElevatedManagedAction:staticvoid project_AfterInstall(SetupEventArgs e) { if (e.IsInstalling) try { Registry.LocalMachine.CreateSubKey(@"Software\" + session.Property("ProductName")) .SetValue("InstallationDirectory", session.Property("INSTALLDIR")); } catch{} }
project.DefaultDeferredProperties
) all properties that your deferred action (event handler) is going to use.↧
New Post: Can't understand that the program is uninstalling
Hi, Oleg!
There is the same problem in managed project with standart UI.
I click Remove button in MaintenanceTypeDialog. In BeforeInstall and AfterInstall event handlers e.IsUninstalling is false.
There is the same problem in managed project with standart UI.
I click Remove button in MaintenanceTypeDialog. In BeforeInstall and AfterInstall event handlers e.IsUninstalling is false.
↧
New Post: Can't understand that the program is uninstalling
I need to clarify. When you execute your msi and facing MaintenanceTypeDialog (managed or standard) you are always is in maintenance mode. That is it. As far as MSI runtime concerned you are modifying but not uninstalling the product. The fact that you clicked 'Remove' button doesn't change anything. You didn't start your msi with '/uninstall' switch then you are not uninstalling but modifying.
In ManagedUI I have an opportunity to intercept remove button click and set
Effectively it means that the properties of
Where does it leave you? You can dig WiX/MSI documentation find out what combination of properties signifies pressing Remove button during Modifying. If you find one please share it with me and I will update the IsUninstalling implementation.
You can try to find this combination by yourself. I couldn't but I captured the screenshots of SetupEvents sample so it can be a good start point for you: https://wixsharp.codeplex.com/wikipage?title=ModifyType%20detection%20
But arguably the most practical solution is something like this:
In ManagedUI I have an opportunity to intercept remove button click and set
MsiRuntime.Session["REMOVE"] = "ALL";
so effectively I start uninstalling and e.IsUninstalling
returns true. But native UI doesn't set REMOVE property so it is not installing but modifying (by removing all components).Effectively it means that the properties of
SetupEventArgs
for native UI can only reliably report you how your setup was started but not to trace your input in the native setup UI.Where does it leave you? You can dig WiX/MSI documentation find out what combination of properties signifies pressing Remove button during Modifying. If you find one please share it with me and I will update the IsUninstalling implementation.
You can try to find this combination by yourself. I couldn't but I captured the screenshots of SetupEvents sample so it can be a good start point for you: https://wixsharp.codeplex.com/wikipage?title=ModifyType%20detection%20
But arguably the most practical solution is something like this:
if (e.IsUninstalling) { //do your uninstalling stuff } elseif (e.IsModifying) { if (<your product files are present>) { //do your uninstalling stuff } }
↧
↧
New Post: Can't understand that the program is uninstalling
And of course you can also avoid all these troubles if you stop allowing user to modify (only repair and uninstall) your setup. Thus way unninstalling can be determined reliably
↧
New Post: Saving product settings in registry
I tried to use UsesProperties and DefaultDeferredProperties. I change property's value in in BeforeInstall event handler, but it isn't changes
e.Session["IP"] = "test";
in CustomActions.SaveSettings I want to get "test", but session.Property("IP") is 85
e.Session["IP"] = "test";
in AfterInstall event handler session.Property("IP") is 85
What's wrong?
-
I set up UsesProperties in ElevatedManagedAction:
new Property("IP","85"),
new ElevatedManagedAction(CustomActions.SaveSettings, Return.check, When.After, Step.InstallFiles, Condition.NOT_Installed)
{
UsesProperties = "IP",
Execute = WixSharp.Execute.deferred
}
e.Session["IP"] = "test";
in CustomActions.SaveSettings I want to get "test", but session.Property("IP") is 85
-
I tried to use DefaultDeferredProperties:
project.DefaultDeferredProperties += ",IP";
e.Session["IP"] = "test";
in AfterInstall event handler session.Property("IP") is 85
What's wrong?
↧
New Post: InjectClrDialog throw exception
Hi, Oleg!
I tried to Inject 2 dialogs.
var project = new Project("CustomDialogTest",
project.RemoveDialogsBetween(NativeDialogs.WelcomeDlg, NativeDialogs.InstallDirDlg);
project.InjectClrDialog("ShowEmptyDialog", NativeDialogs.WelcomeDlg, NativeDialogs.InstallDirDlg);
Second InjectClrDialog function throw exception:
An unhandled exception of type 'System.ApplicationException' occurred in WixSharp.dll
Additional information: Project.CustomUI is already initialized. Ensure InjectClrDialog is invoked before any adjustments made to CustomUI.
I tried to Inject 2 dialogs.
var project = new Project("CustomDialogTest",
new Dir(@"%ProgramFiles%\My Company\My Product",
new File("setup.exe")));
project.InjectClrDialog("ShowCustomDialog", NativeDialogs.InstallDirDlg, NativeDialogs.VerifyReadyDlg);project.RemoveDialogsBetween(NativeDialogs.WelcomeDlg, NativeDialogs.InstallDirDlg);
project.InjectClrDialog("ShowEmptyDialog", NativeDialogs.WelcomeDlg, NativeDialogs.InstallDirDlg);
Second InjectClrDialog function throw exception:
An unhandled exception of type 'System.ApplicationException' occurred in WixSharp.dll
Additional information: Project.CustomUI is already initialized. Ensure InjectClrDialog is invoked before any adjustments made to CustomUI.
↧
New Post: Uninstall previous version of MSI befor installing a later one
Hi Oleg,
Thanks for your reply. I have managed to uninstall the previous version of MSI before installing the newer version by following the below steps.
Thanks for your reply. I have managed to uninstall the previous version of MSI before installing the newer version by following the below steps.
- Removing the Website from IIS
- Stopping Window Service
- Uninstalling Window Service
-
Removing the entry of MSI name from registry in order to remove it from the Control Panel
↧
↧
New Post: Uninstall previous version of MSI befor installing a later one
It is pure MSI problem. MSI may decide that reboot needed even without your consent.
Wix# Reboot sample shows the (commented) techniques of controlling implicit MSI rebooting policies. Most likely you will be able to address the issue with:
Wix# Reboot sample shows the (commented) techniques of controlling implicit MSI rebooting policies. Most likely you will be able to address the issue with:
project.RebootSupressing = RebootSupressing.ReallySuppress;
↧
New Post: InjectClrDialog throw exception
The CLR Dialog injection technique is designed for a single dialog only. Injection is a valid but an intrusive technique. Thus I only planed it for a single 'gentle' insertion and if it's used any different way the compile and runtime behavior will become unpredictable.
If you need to inject more than a single dialog then insert a panel which can host full size sub-panels that are visible only one at the time. This will create the effect of proceeding to the next step of the installation on 'Next' button click.
Judging from all your questions I feel that you are going through all this pain because you are doing too much configuration in your setup. I don't know if you have that luxury but I encourage you to reconsider your deployment strategy.
Deployment responsibility is only to deploy the files. The only user input the deployment should take is the one that controls how files need to be deployed (e.g. which files to install, install location). The configuration (e.g. IP addresses, serial numbers) is a responsibility of your application. Thus your deployment should always start some sort of a config utility at the end of the installation. Or application itself in a pure config mode. If you follow this approach then you don't need to deal with complicated UI scenarios, challenging product detection techniques and so on.
Read more about the matter here: https://wixsharp.codeplex.com/wikipage?title=Deployment%20Strategy%20Considerations
If you need to inject more than a single dialog then insert a panel which can host full size sub-panels that are visible only one at the time. This will create the effect of proceeding to the next step of the installation on 'Next' button click.
Judging from all your questions I feel that you are going through all this pain because you are doing too much configuration in your setup. I don't know if you have that luxury but I encourage you to reconsider your deployment strategy.
Deployment responsibility is only to deploy the files. The only user input the deployment should take is the one that controls how files need to be deployed (e.g. which files to install, install location). The configuration (e.g. IP addresses, serial numbers) is a responsibility of your application. Thus your deployment should always start some sort of a config utility at the end of the installation. Or application itself in a pure config mode. If you follow this approach then you don't need to deal with complicated UI scenarios, challenging product detection techniques and so on.
Read more about the matter here: https://wixsharp.codeplex.com/wikipage?title=Deployment%20Strategy%20Considerations
↧
New Post: Saving product settings in registry
MSI CustomActions scheduling can be quite tricky. Indeed BeforeInstall doesn't change the the actual property value as it is somehow became "immutable". Though Load event works OK and the changed IP value is carried to the AfterInstall correctly. If Load is not suitable for you and you need more precise CA scheduling then indeed you may have too do everything in custom actions not events.
This is the full code sample that works for your scenario:
On unrelated note. May I ask you to use code formatting in your posts. Reading non formatted code is quite difficult. I hope you understand. Thank you.
The markdown formatting rules are here: http://codeplex.codeplex.com/wikipage?title=Markdown&referringTitle=Documentation
This is the full code sample that works for your scenario:
staticvoid Main() { var project = new ManagedProject("ManagedSetup", new Property("IP", "85")); project.DefaultDeferredProperties += ",IP"; project.UI = WUI.WixUI_ProgressOnly; project.Load += msi_Load; project.AfterInstall += msi_AfterInstall; project.BuildMsi(); } staticvoid msi_Load(SetupEventArgs e) { e.Session["IP"] = "test"; } staticvoid msi_AfterInstall(SetupEventArgs e) { MessageBox.Show(e.Session.Property("IP"), "msi_AfterInstall"); }
On unrelated note. May I ask you to use code formatting in your posts. Reading non formatted code is quite difficult. I hope you understand. Thank you.
The markdown formatting rules are here: http://codeplex.codeplex.com/wikipage?title=Markdown&referringTitle=Documentation
↧