WiX waits for the launched process to complete installation - process

I am using the below lines to execute a process from an exe that is in the installed directory.
<SetProperty Id="LaunchMosquitto" Value=""[#fil7D28AEF774656849395A2FA20A5C963D]" -c [#filA995207A6EF3FF0B4A1912B4627C6A9E]" Before="LaunchMosquitto" Sequence="execute"/>
<CustomAction Id="LaunchMosquitto"
BinaryKey="WixCA"
DllEntry="WixQuietExec64"
Return="ignore"
Impersonate="no" />
I am using this approach to run the exe silently with arguments after the installation. But the installer is waiting for the spawned process to terminate for the installation to complete. Though the process is spawned, installer hangs there. It completes only when I close the spawned process. This is because of the Return=ignore property I believe. Perhaps async-no-wait would help. But that requires ExecCommand instead of the SetProperty. The problem in using that is it launches the command prompt after installation to spawn the process. Kind of caught in a dead lock here. Any help would be much appreciated.

Related

Remove popups that are caused by custom actions - Wix

Newbie to wix, I am learning it. I had initially set up some custom actions for installing/ uninstalling/ rollback actions. These custom actions cause unintended popups during installation. I am trying to remove the same using SetProperty, DllEntry and BinaryKey. This is my original code:
<CustomAction Id="InstallStorageService"
Directory="ProductAppDataFolder"
ExeCommand='[ProductAppDataFolder]bin\install_service.bat "[InstallationFolder]" "[ProductAppDataFolder]" "$(var.StorageServiceName)"'
Execute="deferred"
Impersonate="no"
Return="check"/>
This is what I have changed it to:
<SetProperty Id="InstallStorageService"
Value="cmd.exe /c [PRODUCTAPPDATAFOLDER]bin\install_service.bat "[InstallationFolder]" "[ProductAppDataFolder]" "$(var.StorageServiceName)""
After="CostFinalize"/>
<CustomAction Id="InstallStorageService"
BinaryKey="WixCA"
Execute="deferred"
Return="check"
DllEntry="CAQuietExec"
Impersonate="yes"/>
I have done similarly for removing and for rollback actions. I do not get any errors or issues while I run the .bat file to create the msi file, but once the msi is created, I am having trouble installing it. I can share the log file if required, but there are fatal errors with not much of verbose about it.
Any help would be greatly appreciated.
You can use the Quiet Execution Custom Action pattern to invoke out of process exe's and scripts. The pattern will capture stderr and stdout to the Windows Installer log.
However it would be better to not use a .BAT as self registration (in all forms) is not a windows installer best practice. See Zataoca: Custom actions are (generally) an admission of failure.

Kill my application during uninstall

I have run into challenging problem trying to accomplish the following:
my application installs a service (watchdog.exe) and an exe file (app.exe).
After the installation is done the service starts and creates process "app.exe".
during uninstall I want to kill the process "app.exe" (which is running under local system account, so I must be running as admin).
problem 1:
The installs says that it requires a reboot since it sees that file "app.exe" is being held (running) during the CostFinalize phase (please correct me if I'm wrong about the phase that checks if a reboot will be required). It would be much better to kill the process when the uninstallation begins. I have verified that if the process is not running during the uninstall then the install does not complain about a reboot required.
problem 2:
using a custom action to kill the process is problematic. the action must run elevated, but on the other hand it must run before the costFinalize (otherwise - it's back to problem 1).
I would appreciate any suggestion. Also, any alternative solutions (is there another way to close the process maybe during install that will not require a reboot?)
The custom action code I have now (not good since it both unnecessarily asks for a reboot and fails to kill the process due to lack of permissions):
<InstallExecuteSequence>
<!--<ScheduleReboot After="InstallFinalize" />-->
<Custom Action="MyProcess.TaskKill" Before="InstallValidate"></Custom>
</InstallExecuteSequence>
<!--<Property Id="Net">Net.exe</Property>-->
<Property Id="QtExecCmdLine" Value='"[%SYSTEMROOT]\System32\taskkill.exe" /F /IM App.exe' />
<CustomAction Id="MyProcess.TaskKill"
BinaryKey="WixCA"
DllEntry="CAQuietExec"
Execute="immediate"
Return="ignore" />
Here is the log for the failure:
CAQuietExec: Error 0x80070001: Command line returned an error.
CAQuietExec: Error 0x80070001: CAQuietExec Failed
CustomAction MyProcess.TaskKill returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
Action ended 18:15:54: MyProcess.TaskKill. Return value 1603.
There are few ideas that I have, namely:
Use EventWaitHandles, which allow processes to communicate between each other, and delegate your wish to app.exe. Your app.exe can then terminate, as needed. This is clean solution and should be prefered.
If for whatever reason you decide to kill the application like you don't care about anything at all in the world, then you can:
I saw today a project that can run MSI completely elevated, in all stages. It was Visual Stdio template, however I can't find it right now, but know that it exists there.
You can also use this, maybe it works: How do I get WiX installer to request administrative privileges?
Basically there are so many hackery tricks you can do, to kill the application. Such as using WiX Burn and requiring administration rights, then doing your thing. I would go with solution#1(create your own mechanisms)
By the way, if you use ServiceControl element in WiX, it will STOP the service before REINSTALLING/UNISTALLING. You can hook to OnStop() method in Service and kill your App.exe there. If you have set Service as App.exe parent, then there should be flag that any child processes die with parent.

PerUser install with Custom Action - UAC disabled

I'm using WiX to generate an MSI that installs a browser plugin on a perUser basis. I have a custom action to install a driver using DPInst (which needs elevated privileges).
The install works fine when UAC is enabled; Windows shows the prompt to elevate. However, if I have UAC disabled and try to install on a regular user account, dpinst.exe will get spawned until the computer freezes. (About a thousand times at last count).
In the <InstallExecuteSequence> I have:
<Custom Action="Install_Drivers" After="InstallFiles">NOT Installed</Custom>
My custom action is:
<CustomAction Id='Install_Drivers' Execute='deferred' Directory='DRIVERS' ExeCommand='"[DRIVERS]DPinst.exe" /SW /SA' Return='ignore' Impersonate='no'/>
I have Return='ignore' because, from what I understand so far, dpinst.exe always returns a non-0 code.
How can I ensure that the custom action fails correctly when UAC is disabled? On a related note, can I show a custom message to the user when the driver installation fails?
Further Information: I'm developing on Windows 7 currently, but targeting WinXP and up.
Edit Taking a look at the log for the installation these seem to be the relevant lines:
Executing op: CacheSizeFlush(,)
Executing op: ActionStart(Name=Install_Drivers,,)
Executing op: CustomActionSchedule(Action=Install_Drivers,ActionType=3170,Source=C:\long_redacted\Drivers\,Target="C:\long_redacted_path\Drivers\DPinst.exe" /SW /SA,)
Disallowing shutdown. Shutdown counter: 0
CustomAction Install_Drivers returned actual error code 1073807364 but will be translated to success due to continue marking
The bit about the shutdown is, I believe, when I logged off stop the installation. (Canceling doesn't seem to have any effect).
Try setting the 'Impersonate=no' attribute on the 'CustomAction' element, like this:
<CustomAction Id='Install_Drivers' Execute='deferred' Directory='DRIVERS' ExeCommand='[DRIVERS]DPinst.exe" /SW /SA' Return='ignore' Impersonate="no" />
Also note: you have a stray double-quote in your ExeCommand
Installing a driver is an inherently per-machine operation. A limited user can't do it. So with UAC disabled, it's not going to work. DPInst apparently doesn't get the hint that it doesn't have permissions and can't get them. Sounds like a bug in DPInst. You should change your installer to be per-machine and add a launch condition on the Privileged property to prevent the installer from starting for limited users without UAC.

'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" />

Set environment variable before running a custom action in WiX

I have to build an MSI-based installer using WiX and I need to set environment MY_HOME before running a command action.
I have a component:
<Component Id="SEMYHOME"
Guid="*my guid*">
<CreateFolder />
<Environment Id="MY_HOME"
Action="set"
Part="all"
Name="MY_HOME"
Permanent="no"
System="yes"
Value="[APPLICATIONPATH]myapp"/>
</Component>
Then I have a custom action:
<CustomAction Id="InstallMyService"
Directory="INSTALLDIR"
ExeCommand='"[INSTALLDIR]myapp\install_service.bat" install'
Execute="immediate"
Return="ignore"/>
<InstallExecuteSequence>
<Custom Action="InstallMyService"
After="InstallFinalize"/>
</InstallExecuteSequence>
NOTE: This action need the MY_HOME variable to be set before running.
When install this MSI, I got a log showing that the MY_HOME variable is set before running the custom action "InstallMyService", but the command to install my service still fails. I found that the cause is when command called, MY_HOME still not set.
After an install is finished, MY_HOME was set as expected, but the custom action fails :(
How can I fix this problem?
Windows Installer and Custom Actions are hosted via the Service Control Manager which has a long history of not respecting broadcast messages that are sent announcing Environment changes. So even if you fix the immeadiate / deferred problem that Yan mentions you'll find that your custom action still doesn't have the environment variable.
Why don't just just pass "[APPLICATIONPATH]myapp" to your .bat file and fetch it in as %2?
BTW I also don't reccomend calling batch files from an installer. It's fragile and embarrassing to see installs that run popping up little black windows.
You CA is immediate. This means that it runs immediately when Windows Installer is processing your MSI package. And this obviously happens before the component containing <Environment/> is installed. Modify it to be deferred (Execute="deferred") and schedule before InstallFinalize.