Recently I had to "pre-select" an feature inside an WiX product. If the target machine is an Terminal-Server, the Feature should be selected for install.
To check, if the machine realy is used as Terminal-Server or not isn't required, since the installing user can still deselect the feature later.
One way to check for Terminal-Server (and not just an machine with RDP enabled) is to use GetVersionEx-API to check the wSuiteMask.
How to check that in WiX?
First we had to link WixUtilExtension.dll (Project-References->Add Reference)
Then use INSTALLLEVEL (as per mrnx's advice) to switch between different Features. We default it to "2" (All below 2 will be selected in feature-selection-screen, all above 2 will be de-selected):
<!--Default Features: All with levl 1-->
<Property Id="INSTALLLEVEL" Value="2" />
Use feature-selection-UI-template (Maybe you have to reference WixUiExtension.dll)
<UI>
<UIRef Id="WixUI_FeatureTree" />
</UI>
Now reference the properties, which we want to know:
<!--Terminal-Server?-->
<PropertyRef Id="WIX_SUITE_TERMINAL" />
<!--On Terminal-Server this property will be null, if multiple RDP-sessions are allowed-->
<PropertyRef Id="WIX_SUITE_SINGLEUSERTS" />
And finally in our Feature-list we have to use the properties inside a condition. The Feature should be de-selected per default, so we set it to one Level higher than the default "2" --> "3".
<Feature Id="TerminalServerServiceFeature" Level="3"
Title="(Feature-Title, i.E.)Terminal-Server-Service"
AllowAdvertise='no'
InstallDefault='local'
Absent='allow'
Description="Some description for the user, when he clicks on the feature" Display="expand"
ConfigurableDirectory='APPLICATIONFOLDER'
>
<!--Reference to the component (or componentgroup) we want to install-->
<ComponentRef Id="TerminalServerServiceComponent" />
<!--This sets this feature to installlevel 1, if the condition evals to true-->
<Condition Level="1">(WIX_SUITE_TERMINAL="1") AND NOT (WIX_SUITE_SINGLEUSERTS)</Condition>
</Feature>
Testing:
To check, why the condition fails, you have to check the installer log (msiexec /i YourMsi.msi /l*v "log.log").
Something along the lines
MSI (c) (8C!98) [11:18:27:663]: PROPERTY CHANGE: Adding
WIX_SUITE_SINGLEUSERTS property. Its value is '1'.
for a machine with RDP but without multi-rdp-session-support and
MSI (c) (4C!E0) [11:26:15:422]: PROPERTY CHANGE: Adding
WIX_SUITE_TERMINAL property. Its value is '1'.
for a machine with RDP and multi-rdp-session-support.
Related
I’m creating a WiX installer for a Petrel plugin using WiX 3.11.1. The Product.wxs is essentially the following one with a couple modifications:
https://github.com/davidbcc/DeCompactPlugIn/blob/dev/FaciesDecompactorInstaller/Product.wxs
I added a page in the wizard where the user can specify a license server in an edit box. From this information, I create and/or update an environment variable:
<!-- Get the current environment variable if it exists -->
<SetProperty Id="LICENSE_SERVER_ENV_VAR" Value="[%LIC_HOST]" After="LaunchConditions" Sequence="first"></SetProperty>
<snip>
<!-- Validate that the license server name is not empty before proceeding. -->
<Control Type="PushButton" Id="Next" X="239" Y="243" Width="56" Height="17" Default="yes" Text="Next">
<Publish Event="SpawnDialog" Value="ServerNameErrorDlg"><![CDATA[LICENSE_SERVER_ENV_VAR = ""]]></Publish>
<Publish Event="NewDialog" Value="ngenDialog"><![CDATA[LICENSE_SERVER_ENV_VAR <> ""]]></Publish>
</Control>
<snip>
<!-- Install the plugin and set the environment variable -->
<Fragment>
<ComponentGroup Id="PluginComponents" Directory="INSTALLLOCATION">
<Component Id="PetrelPluginPip" Guid="120AF5B9-E751-43F4-AF4C-7DED33C8BEB4">
<Environment Id="LicenseServerEnVar" Action="set" Name="LIC_HOST" System="yes" Permanent="yes" Value="[LICENSE_SERVER_ENV_VAR]"/>
<File Id="PetrelPluginPippip" Source="../OceanPluginPip/bin/$(var.OceanPluginPip.Platform)/$(var.OceanPluginPip.Configuration)/PetrelPluginPip.pip" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
Everything seems to run fine on initial install and when operating through Add/Remove Programs. If I run repair through there, it runs silently and the environment variable remains.
However, after installation, if I right-click on the installer (the actual .msi file), select “Install”, and then select the “Repair” option in the Maintenance dialog, I go through the wizard again. The page correctly pulls the license server information just like on initial install but after completing the repair, the environment variable is removed from the system.
I have tried:
setting "Sequence” on SetProperty to “both”
putting the “Environment” tag into its own Component
creating a CustomAction for setting the license server that is then used in the InstallExecuteSequence
None of these have worked.
Does anyone know why repair through the MaintenanceDialog is resulting in the removal of the environment variable? Thanks.
EDIT:
After adding verbose logging, the repair output shows the following which seems relevant:
MSI (s) (60:78) [11:42:25:420]: PROPERTY CHANGE: Adding RestrictedUserControl property. Its value is '1'.
MSI (s) (60:78) [11:42:25:420]: PROPERTY CHANGE: Adding PETRELINSTALLLOCATION property. Its value is 'C:\Program Files\Schlumberger\Petrel 2022\'.
MSI (s) (60:78) [11:42:25:420]: Ignoring disallowed property INSTALLLOCATION
MSI (s) (60:78) [11:42:25:420]: Ignoring disallowed property LICENSE_SERVER_ENV_VAR
MSI (s) (60:78) [11:42:25:420]: Ignoring disallowed property TARGETDIR
Action start 11:42:25: LaunchConditions.
Action ended 11:42:25: LaunchConditions. Return value 1.
MSI (s) (60:78) [11:42:25:468]: Doing action: SetLICENSE_SERVER_ENV_VAR
MSI (s) (60:78) [11:42:25:468]: Note: 1: 2205 2: 3: ActionText
Action start 11:42:25: SetLICENSE_SERVER_ENV_VAR.
MSI (s) (60:78) [11:42:25:469]: Skipping action due to msidbCustomActionTypeFirstSequence option.
Action ended 11:42:25: SetLICENSE_SERVER_ENV_VAR. Return value 0.
Why is the property disallowed on repair? I'm not seeing that on initial installation. But I still don't see where the environment variable is getting removed.
After investigating what "Ignoring disallowed property" meant, I came across the following post indicating that likely the property is not propagating to the execute sequence:
https://stackoverflow.com/a/39227065/4460247
By adding a Property definition and marking it as "Secure" before populating it, the property is set and the environment variable no longer gets removed.
<Property Id="LICENSE_SERVER_ENV_VAR" Secure="yes"></Property>
<SetProperty Id="LICENSE_SERVER_ENV_VAR" Value="[%LIC_HOST]" After="LaunchConditions" Sequence="first"></SetProperty>
I have a set of registry values that were set by a previous version of my application. It was set permanently (from c++ code) and will not be removed when the application is uninstalled. Now I am trying to edit the wix installation file to remove those registry keys on new installation of the application but it is not working. Here is my code -
<Component Id="RemoveOldRegKeys" Guid="9xxxxxx" KeyPath="yes">
<RemoveRegistryKey Id="RemoveAppInit64" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs" Action="removeOnInstall"/>
</Component>
I have a feature where this component is referred -
<Feature Id="SmartCardFeature" Level="1">
<ComponentRef Id="RemoveOldRegKeys" />
</Feature>
I checked the install logs and it seems to be executing fine. These are the lines I am getting -
MSI (s) (A8:44) [14:00:43:435]: Executing op: RegOpenKey(Root=-2147483646,Key=SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs,,BinaryType=1,,)
MSI (s) (A8:44) [14:00:43:435]: Executing op: RegRemoveKey()
MSI (s) (A8:44) [14:00:43:436]: Note: 1: 1402 2: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs 3: 2
I am just wondering if what I am doing is possible and if yes, what am I missing or doing wrong?
Thanks in advance for the help.
AppInit_DLLs is a value (under the SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows key), not a key itself. You want RemoveRegistryValue instead.
Using Wix installer (win 8), I have a custom action that runs the application after successful installation, using Wix:
<CustomAction Id='LaunchFile'
Directory='TARGETDIR'
Impersonate="no"
Execute="immediate"
ExeCommand='[SystemFolder]cmd.exe start CMD /c ""[TARGETDIR]ManagerAndControl.exe""'
Return="asyncNoWait" />
This works great, but for some reason, the CMD window remains open, and when the application is closed it is closed too.
I couldn't find anything similar in google, anyone encounterd a similar problem?
Thank you
EDIT:
I'm trying, as #Rolo suggested, the QtExecCmdLine:
<Property Id="QtExecCmdLine" Value='C:\Users\User\Desktop\tests.exe'/>
<CustomAction Id="QtExecExample" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="immediate" Return="check"/>
And also:
<Publish Event='DoAction' Value='QtExecExample'>(NOT Installed) AND (LAUNCHPRODUCT = 1)
</Publish>
But nothing happens, and the log says:
Action start 11:02:49: QtExecExample.
MSI (c) (E0:20) [11:02:49:911]: Invoking remote custom action. DLL: C:\Users\User\AppData\Local\Temp\MSIAD42.tmp, Entrypoint: CAQuietExec
MSI (c) (E0:EC) [11:02:49:913]: Cloaking enabled.
MSI (c) (E0:EC) [11:02:49:913]: Attempting to enable all disabled privileges before calling Install on Server
MSI (c) (E0:EC) [11:02:49:913]: Connected to service for CA interface.
MSI (c) (E0!00) [11:02:49:944]: PROPERTY CHANGE: Deleting QtExecCmdLine property. Its current value is 'C:\Users\User\Desktop\tests.exe'.
Action ended 11:02:49: QtExecExample. Return value 3.
DEBUG: Error 2896: Executing action QtExecExample failed.
The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2896. The arguments are: QtExecExample, ,
Action ended 11:02:49: FinishedForm. Return value 3.
Action ended 11:02:49: INSTALL. Return value 1.
Filling lost here
Use the "Quiet Execution Custom Action" instead.
http://wixtoolset.org/documentation/manual/v3/customactions/qtexec.html
Update:
I'll have to update my answer. You should use the WixShellExec custom action. It works pretty similar to Quiet Execution CA, but it will allow you to launch the app without waiting for it to close.
However it can only be used as an immediate custom action.
There is a full example of the implementation you need here:
http://wixtoolset.org/documentation/manual/v3/howtos/ui_and_localization/run_program_after_install.html
http://wixtoolset.org/documentation/manual/v3/customactions/shellexec.html
Edit your execommand like this
> ExeCommand='[SystemFolder]cmd.exe start CMD /c ""[TARGETDIR]ManagerAndControl.exe"" & exit'
EDIT
> ExeCommand='"[TARGETDIR]ManagerAndControl.exe"'
I've just tried this for me and it's worked after I recreated your original problem. However, where you have [TARGETDIR] I use [INSTALLDIR] - I assumed that this was referencing your install directory. You need to be aware of your use of inverted commas.
Thanks for your help, finally I solved it:
<Property Id="WixShellExecTarget" Value='[TARGETDIR]ManagerAndControl.exe' />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<!-- UI code here -->
<Publish Event='DoAction' Value='LaunchApplication'>(NOT Installed) AND (LAUNCHPRODUCT = 1)</Publish>
I'm working on moving a set of installers from VS2010 to WIX and have encountered an error with our NT Service applications.
After creating and installing the NT Service using the WIX installer, the service is not looking for the app.config named as you would expect (ApplicationName.exe.config). Our application name is akin to XXX.YYYYYYYY and when injecting the debugger into the service during start up, i can see that it is looking for XXX.config instead of XXX.YYYYYYY.exe.config.
I've tried running the application via the console and when I do, it looks for the correct app.config file name. Using the VS2010 installer also has the service looking for the correct app.config file name.
Is there some setting in wxi3.8 that I am missing, or putting the incorrect value into, that would cause this? Here is the segment of the wxs that controls the service:
<Component Id="Service" Guid="DCE18608-D25F-4DC0-9E1B-C2E3575D0BFE">
<File Id="ServiceComponentMain" Name="$(var.XXX.YYYYYYY.TargetName)" Source="$(var.HHG.SpecOrderLoadSync.TargetPath)"
DiskId="1" Vital="yes" KeyPath="yes"/>
<ServiceInstall Id="Service" Name="$(var.XXX.YYYYYYY.TargetName)" Type="ownProcess" DisplayName="$(var.XXX.YYYYYYY.TargetName)"
Description="$(var.XXX.YYYYYYY.TargetName)" Start="auto" Account="NT AUTHORITY\LocalService" ErrorControl="normal">
<util:PermissionEx User="Everyone" ServicePauseContinue="yes" ServiceQueryStatus="yes"
ServiceStart="no" ServiceStop="yes" ServiceUserDefinedControl="yes"/>
</ServiceInstall>
<ServiceControl Id="Service" Stop="both" Remove="both" Name="$(var.XXX.YYYYYYY.TargetName)" Wait="no"/>
Finally figured this out after digging around the registery. It appears that with my current wsx file it isn't registering the full path to the executable including ".exe" at the end. This is what is causing the config file name to be confused. Why in the world this makes a difference is beyond me, but just another thing to annoy me about windows i guess...
To fix, changing the Name on the File element in the segment above to be $(var.XXX.YYYYYYY.TargetName).exe instead of just $(var.XXX.YYYYYYY.TargetName) seems to work.
I'm creating an installer for one of our products. The installer was done with WISE earlier but we wanted to change this to wix with this release. It's important that our users uninstall the old version of the product before installing the new version and thus I need to check for a key in the registry that was created by the old installer (the key is removed when the old version is uninstalled).
I have a conditional check in the wxs like so:
<!-- Check if older version of Product has been installed. Must be removed by user-->
<!-- The key below is set by the old installer. If it exists, the old version is there.-->
<Property Id="OLDKEY">
<RegistrySearch Id="OldRegKey" Root="HKLM" Key="SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Company Product för Product" Name="DisplayName" Type="raw"></RegistrySearch>
</Property>
<Condition Message="You need to uninstall the old version of Product before installing this one.">
OLDKEY
</Condition>
You'll notice a Swedish character in there. I suspect this might be the cause of some problems. This is how I configured since I had to handle Swedish characters:
<Product
Id="*"
Name="$(var.Manufacturer) $(var.ApplicationName)"
Language="1033"
Version="!(bind.FileVersion.Product.exe)"
Manufacturer="$(var.Manufacturer) AB"
UpgradeCode="[GUID]"
Codepage="1252"
>
Notice the 1252 codepage.
When I install and have the old version on the machine, I find the key in the registry and the installer will show me the message. If I remove the old version I can see the registry key disappear but the installer will still show me the message and exit. I have tried rebooting (you never know) to no avail.
I'm running out of ideas... any thoughts?
Turns out the registry search returns 1 if key is not found. So I changed
OLDKEY
To
<![CDATA[OLDKEY <> 1]]>
And it was fixed.