WiX: conditionally register application to start when Windows launches - wix

I want to register my application to start as windows launches based on a check box in the exit dialog.
I followed this but it seem that the writing to the registry is done before the end dialog (and the relevant check box) even appear.
My code is:
in product.wxs:
<Property Id="APP_AUTOMATIC_START_UP">1</Property>
....
<Component Id="AppAutoStartUp" Guid="{MyGuid}">
<RegistryValue Id="App.rst" Root="HKCU" Action="write" Key="Software\Microsoft\Windows\CurrentVersion\Run" Name="App" Value="[#MyApp.exe]" Type="string" />
<Condition><![CDATA[Installed OR APP_AUTOMATIC_START_UP]]></Condition>
in MyExitDialog.wxs:
<Control Id="AutomaticStartup" Type="CheckBox" Height="18" Width="295" X="135" Y="190" Text="Run App upon windows startUp" Property="APP_AUTOMATIC_START_UP" CheckBoxValue="1">
<Condition Action="hide" >Installed</Condition>
<Condition Action="show" >NOT Installed</Condition>
EDIT:
I tried adding the key to the registry and in case the user un-check the check box delete it using a custom action. my code:
[CustomAction]
public static ActionResult NotRunOnStartUp(Session session)
{
session.Log("Begin NotRunOnStartUp");
RegistryKey rk = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
rk.DeleteValue("MyApp");
return ActionResult.Success;
}
<Binary Id="NotRunOnStartUpBinary" src="..\CustomActions\NotRunOnStartUp\bin\$(var.Configuration)\NotRunOnStartUp.CA.dll" />
...
<CustomAction Id="NotRunOnStartUpCA"
Return="check"
Execute="immediate"
BinaryKey="NotRunOnStartUpBinary"
DllEntry="NotRunOnStartUp" />
...
<Publish Dialog="MyExitDialog" Control="Finish" Event="DoAction" Value="NotRunOnStartUpCA">APP_AUTOMATIC_START_UP= 0 and NOT Installed</Publish>
The result is, during instalation I write the key to the registry, but when I uncheck the check box and press finish, the key in not removed from the registry.
Any Ideas why?

The other choice is to write a custom action that runs at the end of the install based on the value of the checkbox, and again you'd need to remove that registry entry at uninstall.
As suggested, it is better to make it a configuration of the app and not the install. If the user changes his mind, what's he supposed to do? Fiddle in the registry (if he can figure out where it is)? Uninstall and re-install to change the setting?
By the way, the program does not start "as windows launches". It will start when the user logs on, and that's not the same thing. If you want it to launch when the user logs on I would describe it to your users as "when you logon". If you want it launch when Windows starts it would need to be a service.

Sounds like you have a conditional feature. Remove the check box and instead make a sub-feature.
Another take...
User choices like that are not an installation issue; They are a configuration issue. There is a fine and wavy line between the two. The application's programs should manage its own configuration.
After the installation is complete and your user has made a configuration choice, your installer can launch a configuration program with command-line arguments to add or modify the Run key.
The installer could remove the registry entry upon uninstallation since it would be better to clean up the Run key than to preserve user's choice for when they install your application again.

Related

Custom action of Wix failed to call vb script

I have one VB script in the package itself. I need to call it using CMD, the default way of calling the script taking too much time, so I am trying to call it with CMD and CSCRIPT but the installer raises the error while installation.
I am using the following code which is not working as expected. I searched a lot but didn't find the solution.
<Binary Id="ServiceInstall" SourceFile="..\..\..\AddVirDir.vbs" />
<CustomAction Id="InstallService" BinaryKey ="ServiceInstall"
ExeCommand="CMD /C "[#ServiceInstall]""
Execute="immediate" Return="check" HideTarget="no" Impersonate="no"/>
WiX IIS Elements: If this is all IIS, I would avoid scripting and custom actions whenever possible and use WiX's built-in IIS elements. Here is a Web-installer sample from Rainer Stropek available on github.com.
Look for <iis:WebVirtualDir ... /> et al. Find the WiX Documentation here. I believe you should be able to accomplish what you need without too many custom actions.
DISM.exe: Stropek himself uses custom actions in another sample source to set up IIS using DISM.exe. Not sure I would do it like this (no other suggestions though), but it is a sample of custom actions and IIS.
Need-For-Speed: As to your installation performance issues. Maybe you need to suppress the creation of a restore point and limit file costing? The Windows Installer engine allows this - see link below. I doubt it will be very effective though. I think there must be something else wrong in your installer. Some timeout issue? It could relate to other custom actions, slow network, or some other issue. Can you elaborate on your deployment scenario?
In any case, here is some documentation on speeding up MSI installations in general. Essentially the MSIFASTINSTALL property is the only one I would recommend. DISABLEROLLBACK can cause genuine problems.
Logging: I normally recommend that setup developers enable default verbose MSI logging - as described in the "Globally for all setups on a machine" section, to always have a log file ready when you need one. It is created with a random name for every MSI operation in the TEMP folder and you sort by modify to get the latest one. The log file might give clues as to why the installation is slow - just determine what is really going on. Apologies if this is just obvious trifles and you have this set up already.
Manual log file creation:
msiexec.exe /i C:\Path\Your.msi /L*v C:\Your.log
Interpreting an MSI log: interpreting a log file can be challenging sometimes. Here is an answer with some links to help with this.
Service Installation & Control: You should not install services with scripts. There are built-in mechanisms in MSI that are vastly superior. You simply use the ServiceInstall and ServiceControl WiX XML Elements and "declare" how the service should be registered and when and how the service should be started and stopped:
<Component>
<File Source="$(var.SourceDir)\WindowsService.exe" />
<ServiceInstall Name="MyService" ErrorControl="normal" Start="auto" Type="ownProcess" />
<ServiceControl Id="MyService" Name="MyService" Start="install" Stop="both" Remove="uninstall" Wait="yes" />
</Component>
Look! No custom actions! :-) - Just MSI auto-magic. There is no need to use any custom actions for this. MSI is full-featured and reliable provided your service executable behaves as it is supposed to.
Let me link to a similar sample on github in case the above is not clear. It is more complete and elaborate.
VBScript: I wrote this before I saw you dealt with services. I'll just throw it in: to call a script that doesn't have a function you can try something like this:
<!-- The VBScript file -->
<Binary Id='Sample.vbs' SourceFile='Sample.vbs' />
<!-- The Custom Action -->
<CustomAction Id='Sample.vbs' VBScriptCall='' BinaryKey='Sample.vbs'
Execute='immediate' Return='ignore'/>
<!-- And Insert Into Installation Sequence -->
<InstallExecuteSequence>
<Custom Action='Sample.vbs' After='AppSearch'/>
</InstallExecuteSequence>
That should work for a script like this (Sample.vbs - no funtions, just an implicit main function):
MsgBox(Session.Property("ProductName"))
There is an answer on the topic of VBScript custom actions here: WIX installer execute vbscript from CustomAction.

WiX Service Install with user credentials or LocalSystem depending on UI input

Below is a section of my .wxs installer file which installed my service. I have a WiX UI dialog where the user can either choose to install the service to run under the LocalSystem account or input the credentials of the account they want. The UI has two text boxes (one bound to the ACCOUNT property and one to the PASSWORD property) and a checkbox that is bound to a property called USELOCALSYSTEMACCOUNT.
Individually, these service installers work fine, you can see both ServiceInstall sections below. However I want the installer to install the service with the user input credentials if USELOCALSYSTEMACCOUNT is not set to 1, or to use the LocalSystem account if USELOCALSYSTEMACCOUNT is set to 1, but I am unsure how to do this. the Condition tag doesn't work within a ServiceInstall tag so I'm a bit lost on how to achieve this.
WiX component section below:
<Component Id='MainExe' Guid='*'>
<File Id='MainService'
Name='MyService.exe'
Source='$(var.ServiceRoot2)\SA.MyService.exe'/>
<ServiceInstall Id='MyService'
Type='ownProcess'
Vital='yes' Name='MyService'
Name='$(var.HumanProductName)'
Description='$(var.ProductDescription)'
Start='demand'
Account='[ACCOUNT]'
Password='[PASSWORD]'
ErrorControl='ignore'
Interactive='no'/>
<ServiceInstall Id='MyService'
Type='ownProcess'
Vital='yes'
Name='$(var.HumanProductName)'
Description='$(var.ProductDescription)'
Start='demand'
Account='LocalSystem'
ErrorControl='ignore'
Interactive='no'/>
<ServiceControl Id='MyServiceServiceControl'
Stop='both'
Remove='both'
Name='$(var.HumanProductName)'
Wait='yes'/>
</Component>
You should be able to put the condition around the entire component and just have the LocalSystem version and the User specified version. Wix is smart enough to not package the Myservice.exe twice in the installer. Just make sure your condition has "OR Installed" appended to it because I've had issues in the past with conditional components/features not uninstalling because the property they depended on was not set during uninstall. If it is a state of the machine (VersionNT/VersionVT64 which remain constant) then omitting "OR Installed" should be fine.

Install a MSI based on whether a windows service is disabled or not

I have a Bundle setup such that it installs a combination about 4 msis, like, MSI_1 -> MSI_2 -> MSI_3 -> MSI_4.
I want the MSI_4 to be installed only if a particular windows service is NOT disabled, i.e. Don't install if the windows service (say ABC) is disabled. I can probably use a CustomAction and run the command
"Get-WMIObject win32_service -filter "name='ABC'" -computer "." | select -expand state"
to check for the state. But how do I use that(can I use that?) to determine whether to execute the installer or not. Mind you, all the 4 MSIs have their own project and they are combined under the umbrella of one VS solution. I don't have to go the CustomAction route, so if you have anything else in mind I am open to try that as well.
Thanks for your time and help in advance. Let me know if something is not clear.
Will answer my own question here, since I found the solution. What I didn't know was the services listing was also available in the registry setting and one can use Util:RegistrySearch element in the wxs where we are doing the Chain element. One can modify the state of the service from Running to Disabled to observe the change in the value and can set the InstallCondition accordingly.
<util:RegistrySearch Root="HKLM"
Key="System\CurrentControlSet\Services\ABC"
Win64="yes"
Value="Start"
Variable="State" />
And the Chain element will be like:
<MsiPackage Id="package"
Cache="no" Vital="yes"
DisplayInternalUI="no"
ForcePerMachine="yes"
SourceFile="package.msi"
InstallCondition="(State = <condition>)" />
Hope this helps.

Search for registry change during wix installation

I have a radio button to choose options, which select type installation. If they choose option 1 the installer can not continue is mozilla firefox is not installed...
The problem is: imagine that user get message that he needs mozilla firefox... so he decide to install it, but do not close my installation... so after what he installs firefox click on next button in my installation and again get message that he needs to install firefox...
Next button check and show message:
<Publish Dialog="AdditionalInfo" Control="Next" Event="SpawnDialog" Value="MozillaCheck" Order="5">INSTALLATION_TYPE = "PORTAL" AND NOT FIREFOXVERSION</Publish>
firefox check:
<Property Id="FIREFOXVERSION">
<RegistrySearch Id='FirefoxVersion_registrySearch' Type='raw'
Root='HKLM' Key='SOFTWARE\Mozilla\Mozilla Firefox' Name='CurrentVersion' Win64='no'/>
</Property>
I was looking for some custom action which I can trigger at DoAction event, but it seems that there is no registrySearch custom action...
Any ideas?
Thanks
Still not sure if it is possible by default, so I decided to create custom action in C#, where I can detect it easily by looking into registry

'wix execute batch before uninstall with administrator

My WiX XML file installs app that contains windows-service named OLOLO_SERVICE (for example). I want to stop this service when installing/reinstalling my app.
I use CustomAction with ExeCommand='sc stop OLOLO_SERVICE'.
<CustomAction Id='EnsureThatServiceIsStopped' Directory='INSTALLLOCATION'
Impersonate="no" Execute="immediate" ExeCommand="sc
stop OLOLO_SERVICE" Return="ignore" />
Inside <InstallExecuteSequence> tag is action
<Custom Action='EnsureThatServiceIsStopped' Before='InstallValidate' />
But this doesn't works, uninstaller shows this window "For uninstallation continue you should stop following executables" (maybe not 100% correct, because in my russian Windows 7 it is written in russian).
I think that possible reasons for this are
script runs before admin rights taken (and stopping service fails because it needs admin privilegies)
script runs after validation (and validation fails when checking installed executables)
Plesae help me, I want to stop service using batch 'sc stop OLOLO_SERVICE'
PS. I decided to simplify a question: I want my WiX to execute 'sc stop OLOLO_SERVICE' with administrator privilegies and before checking for running applications
You don't need to do this in a batch file, you can use the ServiceControl element:
<ServiceControl Id="ServiceControl_OloService"
Name="OLOLO_SERVICE"
Stop="both"
Remove="uninstall"
Wait="yes" />