Search for registry change during wix installation - wix

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

Related

Wix Installer Registry Search Fails

I am attemping to do a registry search with in a wix installer so that I know where to install my plug in. I am trying to look up where Tekla Structures 2018i is installed at. However, every time I try running the installer my condition fails. Any help would be greatly appreciated.
Product tag:
<Property Id="TSMAINDIR">
<RegistrySearch Id="TS2018iSetupMain"
Root="HKLM"
Key="Software\Tekla\Structures\2018i\setup"
Name="MainDir"
Type="raw"
Win64="yes"/>
</Property>
<Condition Message="This application requires Tekla Structures 2018i. Please install Tekla Structures 2018i then run this installer again.">
<![CDATA[Installed or TSMAINDIR]]>
</Condition>
RegEdit:
UPDATE:
I have created a log file. The file is rather lengthly so I will not post it. However, When I do a search for TSMAINDIR I find the following:
AppSearch: Property: TSMAINDIR, Signature: TS2018iSetupMain
MSI (c) (00:34) [14:25:26:994]: Note: 1: 2262 2: Signature 3: -2147287038
MSI (c) (00:34) [14:25:26:994]: PROPERTY CHANGE: Adding TSMAINDIR property. Its value is 'C:\Program Files\Tekla Structures\'.
MSI (s) (E4:2C) [14:25:27:694]: Ignoring disallowed property TSMAINDIR
Looks OK to me. You have the right bitness flag so you search the x64 section of the registry. Have you looked in the log file? How to create a log file.
I don't really think it should matter since you are not in deferred mode, but try setting the property to be secure:
<Property Id="TSMAINDIR" Secure="yes">
<...etc...>

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.

WiX: conditionally register application to start when Windows launches

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.

Running a program on uninstall

I want to run a program when my software is being un-installed, it is a simple form that should gather some feedback on why people are un-installing my software.
I found some WiX examples that works to some degree.
It works pretty fine with a standard windows program (notepad), but when I try to run my own program, it does not work. I think the problems is that the program is removed, before it has been run.
I have tried to print the logs, but they did not give me any clues of what to do.
My code so far:
<CustomAction Id="LaunchFeedBackForm"
ExeCommand="notepad.exe" Directory="INSTALLDIR"
Return="asyncWait" >REMOVE="ALL"</CustomAction>
<InstallExecuteSequence>
<Custom Action="LaunchFeedBackForm" After="InstallValidate"/>
</InstallExecuteSequence>
So I need in some way the un-install process to halt or what ever, until the user has closed the feedback form. After the form has been closed, it should continue and remove all software including the feedback form program.
The way you'd like to get user's feedback seems not that natural to me. If I understand you correctly, you'd like to show this feedback form and wait while a user fills it in, and later on continue with uninstallation, right?
To my own experience, when a user decides to uninstall software, he/she would like it to get uninstalled as quickly and clear as possible. Bringing a "must fill" form in front of them would only negatively affect the user experience. Moreover, as you can see, it is more difficult from the technical point of view. I suppose you've also thought about passing this feedback on to your side, right? Is it emailing the info entered by user? How do you ensure the email gets sent?
Alternatively, you can have this form online on a certain web page of your site and start it when the uninstall is done (NOT in progress). In this way, you don't annoy the user blocking the uninstall process.
So, I would do the following:
have a custom action that starts a browser with a URL you need
the installation program SHOULD NOT WAIT for this to complete
BTW, do not expect lots of feedback - people rarely bother spending some time to give feedback :)
If your EXE is in the MSI, try using the FileKey attribute: http://wix.sourceforge.net/manual-wix2/wix_xsd_customaction.htm
For example, if your EXE is defined like this:
<File Id="FeedbackExe" Name="FeedbackExe.exe"/>
you can use:
<CustomAction Id="LaunchFeedBackForm"
FileKey="FeedbackExe" Execute="deferred"
Return="asyncWait">REMOVE="ALL"</CustomAction>
You can also try creating an uninstall log to see what happens with the custom action:
msiexec.exe /x <ProductCode> /L*V "C:\uninstall.log"
where you use your actual ProductCode.
So I need in some way the un-install process to halt or what ever,
until the user has closed the feedback form. After the form has been
closed, it should continue and remove all software including the
feedback form program.
To do this one would set After="InstallValidate"
<InstallExecuteSequence>
<Custom Action="InstallCustomLogic" After="InstallFinalize" />
<Custom Action="UninstallCustomLogic"
After="InstallValidate" >
NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
</InstallExecuteSequence>
Set Return attribute to check so that the installer will halt until the specified executable returns.
<CustomAction Id="UninstallCustomLogic"
Directory="INSTALLFOLDER"
ExeCommand="[INSTALLFOLDER]\RetailConnectCustomLogic.exe uninstall"
Return="check"
/>
This is useful in the event where you need to run something located in the program directory before uninstalling the program. One could also set the attribute to ignore if it doesn't return 0

WiX - trying to figure out install sequences

I'm installing a large app, and part of it is a custom written tool called "DbUpdateManager" to mass execute SQL scripts against our target database.
Right now, the WiX 2.x install works - but it has one flaw: during install, I also install a couple of Windows services, which can be optionally started right away. Those however will fail, if the DbUpdateManager hasn't been run yet.
So what I'm trying to accomplish is this:
Install DbUpdateManager and my services from my MSI
Run DbUpdateManager BEFORE any of the services start up
My current WiX source looks something like this:
<Directory Id='INSTALLDIR' Name='DbUpdMgr' LongName='DbUpdateManager' >
<!-- DbUpdateManager component with the necessary files -->
<Component Id='DbUpdateManagerComponent' Guid='...' DiskId='1'>
<File Id='DbUpdateManagerFile' LongName='DbUpdateManager.Wizard.exe'
Name='DbUmWz.exe' src='DbUpdateManager.Wizard.exe' KeyPath='no' />
</Component>
<!-- Component to install one of my Windows services -->
<Component Id='InstallServiceComponent' Guid='...' DiskId='1'>
<File Id='InstallServiceFile' LongName='MyService.exe'
Name='MyServic.exe' src='MyService.exe' KeyPath='yes'/>
<ServiceInstall Id='InstallMyService' Name='MyService'
Description='My Service' ErrorControl='normal'
Start='auto' Type='ownProcess' Vital='yes' />
<ServiceControl Id='UninstallMyService' Name='MyService'
Remove='uninstall' Wait='yes' />
</Component>
<!-- Feature for the DbUpdateManager referencing the above component -->
<Feature Id='DbUpdateManager' ConfigurableDirectory='INSTALLDIR'
AllowAdvertise='no' Description='DbUpdateManager' Level='1'
Title='Database Update Manager'>
<ComponentRef Id='DbUpdateManagerComponent'/>
</Feature>
<!-- Custom action for running DbUpdateManager -->
<CustomAction Id='RunDbUpdateManagerAction' FileKey='DbUpdateManagerFile'
ExeCommand='' Return='asyncWait' />
<!-- Calling the custom action in the install sequence -->
<InstallExecuteSequence>
<RemoveExistingProducts After='InstallInitialize' />
<Custom Action='RunDbUpdateManagerAction'
After='InstallFinalize'>&DbUpdateManager=3</Custom>
I inherited this WIX, and it works - but as I said - the DbUpdateManager gets called too late in the process (only "After=InstallFinalize") and thus the services will fail to start up properly at first (the run fine the second time around when you restart them manually after DbUpdateManager has run).
I poked around the MSI documentation a bit and found a nice step called "StartServices", so my hunch was to just change my calling the custom action to this:
<InstallExecuteSequence>
<Custom Action='RunDbUpdateManagerAction'
Before='StartServices'>&DbUpdateManager=3</Custom>
Unfortunately, in this case, nothing at all happens - DbUpdateManager NEVER gets called....
Any ideas why? Debugging the MSI/WiX stuff is really really tricky, and I can't seem to see the forest for the trees anymore....
Thanks!
Marc
EDIT: The "RunDbUpdateManagerAction" is placed in the right position in the InstallExecuteSequence table in my MSI - right AFTER InstallServices and just BEFORE StartServices - and yet it doesn't work.... DbUpdateManager (a Winforms utility) does not show up during installation :-(
EDIT 2: now my action appears to be executed and at the right time - unfortunately, I'm just not seeing my wizard :-( What I'm seeing is an error code "return value 1631" which means something like "MSI Service could not be started" - wtf ???
MSI (s) (2C:D8) [20:53:36:383]: Doing action: RunDbUpdateManagerAction
Action 20:53:36: RunDbUpdateManagerAction.
Action started at 20:53:36: RunDbUpdateManagerAction.
MSI (s) (2C:D8) [20:53:36:383]: Doing action: StartServices
Action 20:53:36: StartServices. Services are being started
Action started at 20:53:36: StartServices.
Action finished at 20:53:36: RunDbUpdateManagerAction. Return value 1631.
Well, I finally got it working - with a bit of help from everyone who responded, and by consulting some of the WiX tutorials and help pages out there on the web. MSI installer stuff isn't easy to figure out and learn......
Basically, I changed execution of my custom action to "deferred" (as suggested by Rob) and I moved the point in the sequence where it gets executed to "After=InstallFiles". I also changed the condition in the <Custom> tag to "NOT Installed" which seems to work just fine in my scenario.
Contrary to Rob's fear, the Db Update Manager and its UI come up quite nicely this way, and the process of updating our database is now completed before any of our services (that depend on the database) get started.
Looking forward to a full RTM release of WiX 3.0 (and its future) !
Thanks to everyone - unfortunately, I could only accept one answer - all would have deserved it.
Marc
It appears that your CustomAction depends on the 'DbUpdateManagerFile' being installed. That means that your CustomAction needs to be scheduled after InstallFiles executes. Remember there are two passes to the InstallExecuteSequence. First, the "immediate" (or "scheduled" or "script generation") actions are executed to build the transaction log (aka: "install script"). Second, the "deferred" actions in the transaction log are executed.
Right now your CustomAction is "immediate" (the default) so it is trying to run before the files are actually copied to the machine. The InstallFiles action is in the script before your CustomAction but it hasn't been executed yet.
So, you need to mark your CustomAction "deferred" to get it to run after your files are installed.
Note: you are not probably not able to show UI from a deferred CA. I wasn't sure if this tool of yours was expected to show UI.
PS: sorry if I didn't explain that well, it's been a long day.
Try getting a log file of the Installation, and look for the sequence order in there and the value of the condition to perform the Custom Action
Use this in the command line:
msiexec /i [msiname] /l*v [filename]
EDIT: After reading your comment have a look at this page here you could try to add NOT INSTALLED in the condition
EDIT2: I found this page Search for your error Number 1631
You can open the .msi in Orca and look at the InstallExecuteSequence table to see what order things are actually happening in. This may give you a good idea of what's actually happening when.