uninstall using Wix on GINA causes login failure - installation

Problem: After uninstalling a replacement GINA I get logged off immediately after logging on if I use the WIX 3.0 installer.
I have a replacement login process (GINA) for windows XP.
It consists of a single file placed in the system directory
C:\windows\system32\NewGina.dll
and a registry entry
(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Winlogon\GinaDLL=NewGina.dll)
and I have no trouble manually installing it, running it, manually uninstalling it and logging in normally.
I can also create an installer using the Microsoft installer package in VS2008 and install, login, uninstall, login still works properly.
The problem I have is when I use the Wix installer, and I install, login, uninstall, and login, I get logged out immediately after login. After immediate logout, I was able to connect a remote regedit and dump the registry. I tried diffing before and after registries and I tried process monitor hoping to discover what the Wix installer was doing but the actions and changes (about 35,000) were a bit extensive to analyze. The registry line (listed above) was gone and windows should revert to the original msgina.dll
Since the rest of the project uses the Wix Installer, I'm hoping to use it.
Any ideas on how to get this to work and avoid the auto logoff?
Thanks
APB
My Wix script looks like
<Package InstallerVersion="200" Compressed="yes" />
<Condition Message="This application is only supported on Windows XP">
<![CDATA[(VersionNT = 501)]]>
</Condition>
<InstallExecuteSequence>
<ScheduleReboot After="InstallFinalize"/>
</InstallExecuteSequence>
<Media Id="1" Cabinet="NewGina.cab" EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="SystemFolder">
<Component Id="NewGina" Guid="cdbdfbe9-8137-4305-98cb-a05618ea0ade" >
<File Source="..\NewGina\Release\NewGina.dll" Checksum="yes" />
</Component>
<Component Id="RegistryEntries" Guid="cdbdfbe9-8137-4305-98cb-a05618ea0adf" >
<RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" Action="createAndRemoveOnUninstall">
<RegistryValue Type="string" Name="GinaDLL" Value="NewGina.dll" />
</RegistryKey>
</Component>
</Directory>
</Directory>
<Feature Id="NewGina" Title="NewGina" Level="1" >
<ComponentRef Id="NewGina" />
<ComponentRef Id="RegistryEntries" />
</Feature>

This line is a little disturbing:
<RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" Action="createAndRemoveOnUninstall">
If my memory serves correctly that says create the Winlogon key during install (probably a noop) then remove the entire Winlogon key during uninstall. In you dump can you see if that registry key exists any longer? If my memory is correct, it might be all gone.
The correct authoring in any case, would be to just remove the RegistryKey/#Action attribute. You just want the RegistryValue installed and uninstalled. No special actions necessary.

Related

WIX setup with user input

I've struggled with WIX for some time now. I want my program to be installed at the location the user has defined, install a service and start a program after installation.
First my msi package doesn't ask for install path.
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="Test" />
</Directory>
</Directory>
</Fragment>
May someone tell me how to prompt a screen with change install path?
Second when my service will be installed there is an error which says I miss some permissions:
<File Id="FILE_Service" Source="$(var.Service.TargetPath)" />
<ServiceInstall Id="INSTALL_Service"
Name="Servcie"
Description=""
Start="auto"
ErrorControl="normal"
Type="ownProcess"/>
<ServiceControl Id="CONTROL_Service"
Name="Servcie"
Start="install"
Stop="both"
Remove="uninstall"
Wait="yes" />
May someone tell me how to start my service with admin access?
Third the installed package contains only one EXE file, no referenced assembly. May someone tell me how to tell WIX to search for references and install them?
WiX Tutorial: Quite a bit here. You should try a WiX tutorial: https://www.firegiant.com/wix/tutorial/
Links: Here is my WiX quick start tip answer - various resources and hints to deal with WiX and deployment in general.
Please note that there are alternative deployment and package creation tools that might help you make setups quicker and more reliably if you have little experience with MSI and setups.
Learning Advanced Installer - Resources
Direct link Advanced Installer Video Tutorials
Concrete Answer: Here are some attempted answers for your concrete questions:
Configurable installation directory (a bit down the page). You essentially set the ConfigurableDirectory attribute for a feature element to allow the user to select a custom installation directory (you get to the dialog where you can change the installation path by selecting "Custom" installation):
<Feature Id="FeatureDirectory" Title="FeatureDirectory" ConfigurableDirectory="MYCUSTOMDIR">
<!-- your stuff here -->
</Feature>
Major Upgrade Installation Directory: You need to read back the custom directory for major upgrades. Here is how: The WiX toolset's "Remember Property" pattern. Or it will revert to default during the major upgrade. This is because a major upgrade is an uninstall of the old version and a (re)-install of the new version.
Files: To install all required files you need to figure out by dependency scanning what files need to be deployed for your application to work, and then add them to your packages manually (or use heat.exe to auto-generate the files list to include). See the above quick start links for help, or see this hello wix style article: https://www.codeproject.com/Tips/105638/A-quick-introduction-Create-an-MSI-installer-with
Service Permissions: Services should be installed with admin rights if you install the setup after a UAC elevation prompt. Most likely it does not start because there are missing files and hence broken dependencies. What credentials does the service use to run? LocalSystem?
Mock-Up: Here is a quick mock-up of something along the lines of what you need. You need to add all files and dependencies and insert the Service constructs among other things:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="WiXSample" Language="1033" Version="1.0.0.0"
Manufacturer="Someone" UpgradeCode="cb24bedf-e361-4f25-9a06-ac84ce5d6f5c">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<!--Default GUI - add reference to WixUIExtension.dll -->
<UIRef Id="WixUI_Mondo" />
<Feature Id="Core" Title="Core" Level="1" ConfigurableDirectory="INSTALLFOLDER" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WiXSample">
<Component Feature="Core">
<File Source="D:\MyBinary.exe" />
</Component>
</Directory>
</Directory>
</Directory>
</Product>
</Wix>

Problem with Wix uninstall using CustomAction

I've created a very simple MSI which copies some files to the ProgramFiles directory and while installing calling to custom actions found in a binary written in C#.
While installing, I can easily call any custom action I want. For example I've created an installation step where the user should enter a license, and after confirming the license it is checked against a server using logic written inside C# custom action.
But, when uninstalling, every time I add a custom action (even if it does nothing but returning Success), I get error that the installation failed.
This is how I use the uninstalling step:
<InstallExecuteSequence>
<Custom Action='TestUninstallation' After='MsiUnpublishAssemblies'>REMOVE="ALL"</Custom>
</InstallExecuteSequence>
where TestUninstallation is defined as following:
<CustomAction Id="TestUninstallation" Return="check" Execute="deferred" Impersonate="no" BinaryKey="TestCustomAction" DllEntry="Uninstall" />
The property DllEntry equals Uninstall which is a C# method which only returns Success.
After installation is completed, I'm trying to uninstall and I'm getting the UserExit dialog defined inside the AdminUISequence with the property OnExit.
Any idea what am I missing?
Debugging: Managed code is relatively easy to debug (native code is actually even easier). Here are some pointers:
Debug C# Custom Actions (Advanced Installer)
Different debugging methods / aspects
Suggestions: I think you just have a broken reference to the dll export function - in other words an erroneous dll function name / reference:
<CustomAction Id="TestUninstallation" Return="check" Execute="deferred" Impersonate="no"
BinaryKey="CustomActions" DllEntry="__ERRONEOUS FUNCTION REFERENCE__" />
Just check what the dll actually exports and match like this:
<CustomAction Id="CustomAction1" BinaryKey="CustomActions" DllEntry="CustomAction1"/>
As always the real McCoy is the check of the dll itself to see if you have the right function name (the below screen shot from this prior answer, recommended read).
This is a native code C++ dll:
This is a DTF-packaged managed code dll:
Notice that this is a native dll with the managed code stuff embedded. It yields a very different functions list, but you still have to find the function name in there that you refer to.
This is a straight-up managed code dll (no native wrapping):
And finally: this is the straight-up managed code DLL without being wrapped in a native dll shell.
Un-Uninstallable Setup: When a custom action crashes or fails during uninstallation, you will have problems getting rid of the installation (it just rolls-back and you are stuck with it installed). There are several fixes or workarounds.
The overall fix - in my view - is to not fail custom actions on uninstall, or at least condition them so you can force an uninstall by setting a property via the command line:
Set in MSI property table: SUPPRESSERROR = 0. Then - when needed - on the command line set:
msiexec.exe /x {PRODUCT-GUID} SUPPRESSERROR="1"
Inside the MSI you condition the uninstall custom action with:
REMOVE="ALL" AND SUPPRESSERROR="0"
Now the custom action will not run if SUPPRESSERROR is anything but 0.
There is an older answer with several further options: I screwed up, how can I uninstall my program? (courtesy of Wim Coenen, with me messing up his answer with more suggestions).
Boilerplate: For quick use, let me just dump a boilerplate ad-hoc custom action test project here. This assumes a C# managed code custom action project called "CustomAction1" in the same Visual Studio solution and a reference added to it in your WiX source - like you already have obviously (this is for later when we have all forgotten what the problem was and need to test again):
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="WiXCustomActionsTesting" Language="1033" Version="1.0.0.0"
Manufacturer="test" UpgradeCode="PUT-GUID-HERE">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<UIRef Id="WixUI_Mondo" />
<Property Id="SUPPRESSERROR" Value="0" Secure="yes" />
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes" />
<Feature Id="ProductFeature" Title="WiXCustomActionsTesting" Level="1">
<ComponentGroupRef Id="ProductComponents" />
</Feature>
<!--BEGIN CUSTOM ACTION SECTION-->
<Binary Id="CustomActions" SourceFile="$(var.CustomAction1.TargetDir)\$(var.CustomAction1.TargetName).CA.dll" />
<CustomAction Id="TestUninstallation" Return="check" Execute="deferred" Impersonate="no" BinaryKey="CustomActions" DllEntry="CustomAction1" />
<InstallUISequence></InstallUISequence>
<InstallExecuteSequence>
<Custom Action='TestUninstallation' After='InstallInitialize'></Custom>
</InstallExecuteSequence>
<!--END CUSTOM ACTION SECTION-->
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="WiXCustomActionsTesting" />
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
<Component>
<File Source="C:\Projects\MySetup\MyApp.exe">
</File>
</Component>
</ComponentGroup>
</Fragment>
</Wix>
Create WiX project
Copy paste the code, set a new Upgrade GUID
Create CustomAction project, default name
Add reference to custom action project from wix project
Add reference to WiXUIExtension.dll
Adjust path to file in component
Compile

WiX setup creating a Registry key doesn't work when also using CustomActions

I have issues understanding the order of operation of the WiX setup.
When trying to create a Registry key to add a menu entry to Windows Explorer context menu and simultaniously
using CustomActions the Registry key will not be added.
If I however only try to register the key, it works (any CustomAction code is commented out).
In my Product.wxs I have set elevated priviliges with
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated"/>.
In my <Feature> I have
<ComponentRef Id="RegistryEntries"/> referenced.
This is the code for creating the registry key
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="RegistryEntries" Guid="*">
<RegistryKey Root="HKCR"
Key="Excel.CSV\shell\Use MyConverter\command"
ForceCreateOnInstall="yes"
ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Value="[INSTALLLOCATION]$(var.SolutionName).exe %1"
KeyPath="yes"/>
</RegistryKey>
</Component>
<Directory Id="ProgramFilesFolder">
<Directory Id="HSZLG" Name="MyConverter">
<Directory Id="INSTALLLOCATION" Name="$(var.SolutionName)" />
</Directory>
</Directory>
<!--<Directory Id="ProgramMenuFolder">
<Directory Id="Shortcuts" Name="MyConverter" />
</Directory>-->
</Directory>
</Fragment>
Now Im also using the following Custom Actions:
<CustomAction Id="UnregisterImportFormat" BinaryKey="WixCustomAction" DllEntry="UnregisterImportDefinition" Execute="deferred" Impersonate="no" Return="check" />
<CustomAction Id="PropertiesForUnregisterImportFormat" Property="UnregisterImportFormat" Return="check"
Value="app=AB;key=10000P1000" />
And call them in the <InstallSequence> like this:
<InstallExecuteSequence>
<Custom Action="PropertiesForRegisterImportFormat" Before="RegisterImportFormat" />
<Custom Action="RegisterImportFormat" Before="InstallFinalize">(NOT Installed) OR REINSTALL</Custom>
<Custom Action="PropertiesForUnregisterImportFormat" Before="UnregisterImportFormat" />
<Custom Action="UnregisterImportFormat" Before="InstallFinalize">REMOVE</Custom>
</InstallExecuteSequence>
It'd be gladly appreciated if someone can point out what I am doing wrong here.
There are difficulties with (deferred) custom actions running without impersonation as well as the HKCR key because HKCR isn't an actual registry location - it's a merge of the interactive user and HKEY_LOCAL_MACHINE\Software\Classes. This goes into detail:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx
and the custom action code is running with the system account (deferred, no impersonation) which is adding more confusion about which registry key you're creating. As that MSDN note says:
"To change the settings for the interactive user, store the changes under HKEY_CURRENT_USER\Software\Classes rather than HKEY_CLASSES_ROOT"
and I assume your code is attempting to use HKCR. Windows Installer is preferred for writing these registry entries because "it just works". Code running with the system account writing to HKCR is unreliable, so if you really must use code (and you shouldn't) then try HKEY_LOCAL_MACHINE\Software\Classes.

WIX 3 : Using HEAT for Visual Basic 6 COM Dlls

I am using WIX 3. I have used heat to create a wxs file for a VB6 dll. The msi creates without any errors, and the installation is successful as well.
All seems to be fine, and I can invoke the component successfully from a VB client.
However, if I invoke the component from an ASP page, I get 0x800401f3.
If instead of the installer, I use self registration (regsvr32), both work fine.
I did a registry difference to figure out what was the difference between self registration (regsvr32) and the installer, and I see the following
All entries in HKCR match - all well here
regsvr32 adds entries in HKLM, while the installer does not touch HKLM
I am wondering if this is the issue, or am I completely on a wrong track.
MSDN (http://msdn.microsoft.com/en-us/library/ms694355(VS.85).aspx) mentions that registry entries are required in HKLM, wondering what am I missing here.
Following is the file created by heat.
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Directory Id="dirAD70B10292EAB7CAC7171859FBB23AA9" Name="vbdll" />
</DirectoryRef>
</Fragment>
<Fragment>
<DirectoryRef Id="dirAD70B10292EAB7CAC7171859FBB23AA9">
<Component Id="cmp9D818C62A6239E8B51E971A0048D0C05" Guid="PUT-GUID-HERE">
<File Id="filDD6F51EC5018EF4A9A312FFA6AC4257D" KeyPath="yes" Source="SourceDir\vbdll\act.dll">
<TypeLib Id="{80D8DA04-72C9-4D36-B269-57D989187ACF}" Description="act" HelpDirectory="dirAD70B10292EAB7CAC7171859FBB23AA9" Language="0" MajorVersion="1" MinorVersion="0">
<Class Id="{31BD65B6-9479-40EB-83C0-E717CD4793DD}" Context="InprocServer32" Description="act.def" ThreadingModel="apartment" Version="1.0" Programmable="yes">
<ProgId Id="act.def" Description="act.def" />
</Class>
<Interface Id="{C6D46026-CD7E-4AB0-B3B6-810FBF435BEF}" Name="def" ProxyStubClassId="{00020424-0000-0000-C000-000000000046}" ProxyStubClassId32="{00020424-0000-0000-C000-000000000046}" />
</TypeLib>
</File>
<RegistryValue Root="HKCR" Key="CLSID\{31BD65B6-9479-40EB-83C0-E717CD4793DD}\Implemented Categories\{40FC6ED5-2438-11CF-A3DB-080036F12502}" Value="" Type="string" Action="write" />
</Component>
</DirectoryRef>
</Fragment>
</Wix>
Update : Using the "SelfReg" option for the File makes the ASP client work as well. I read from other posts that this is not to be used. Can someone tell me what's to be done?
To get the installer to put entries under HKLM, the installation has to be marked as perMachine, the default seems to be perUser, as done below.
<Package InstallScope="perMachine" InstallerVersion="200" Languages="1033" Compressed="yes" SummaryCodepage="1252" />
Once this is done, the entries come in HKCR and also HKLM.
I hope somebody finds this useful, took me a good 6 hours..

Launch after install, with no UI?

How do I launch my application after install with no UI (or in quiet mode)? Thanks!
I had a installer with UI which has an option to run after install. Now I want my application to updates itself by downloading and running the new version of installer in quiet mode, but after updating done, it won't launch again.
From the msdn topic on sequencing custom actions:
As in the case of standard actions,
custom actions that are scheduled in
the InstallUISequence or
AdminUISequence run only if the
internal user interface is set to the
full level.
So I guess your custom action is scheduled in a UI sequence, not in InstallExecuteSequence. Try scheduling your custom action in the InstallExecuteSequence like this:
<InstallExecuteSequence>
<Custom Action='LaunchApplication' After='InstallFiles'/>
</InstallExecuteSequence>
where "LaunchApplication" should be replaced by the Id of your CustomAction element.
edit: I looked at the instructions that you followed, and I don't see the custom action for launching the application being scheduled in any sequence. It is only triggered from a UI action (clicking the Finish button). This explains why it is never executed during a silent install.
edit: full sample (it's a bit sloppy as it also tries to execute the custom action on uninstall, repair etc. but for some reason I couldn't get the "NOT Installed" condition to work)
<?xml version='1.0' encoding='utf-8'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product
Name='ProductName'
Id='*'
Language='1033'
Version='0.0.1'
Manufacturer='ManufacturerName' >
<Package
Keywords='Installer'
Description='Launch application demo'
Manufacturer='ManufactererName'
InstallerVersion='100'
Languages='1033'
Compressed='yes'
SummaryCodepage='1252'/>
<Media Id='1' Cabinet='test.cab' EmbedCab='yes'/>
<Directory Id='TARGETDIR' Name="SourceDir">
<Directory Id='ProgramFilesFolder'>
<Directory Id='TestFolder' Name='Test' >
<Component Id="ExeComponent" Guid="*">
<File Id="ExeFile" Source="c:\windows\notepad.exe" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id='Complete'
Display='expand'
Level='1'
Title='Test'
Description='Test'>
<ComponentRef Id="ExeComponent" />
</Feature>
<InstallExecuteSequence>
<Custom Action='LaunchInstalledExe' After='InstallFinalize'/>
</InstallExecuteSequence>
<CustomAction Id="LaunchInstalledExe"
FileKey="ExeFile"
ExeCommand=""
Execute="immediate"
Impersonate="yes"
Return="asyncNoWait" />
</Product>
</Wix>
In my final solution I used two properties, one for UI (LAUNCH_APP_ON_EXIT), one for command line arguments (UPDATING_AUTOMATICALLY).
I have to do this because if I run the CustomAction after InstallFinalize in full UI mode, the application would start before you click the "Finish" button.
Now I can call setup.exe /qn UPDATING_AUTOMATICALLY=1 in my program to update.
Here is it all:
<Property Id="LAUNCH_APP_ON_EXIT" Value="1" />
<Property Id="UPDATING_AUTOMATICALLY" Value ="0" />
<CustomAction Id="LaunchApplication" FileKey="mainExecutableFile" ExeCommand="" Execute="immediate" Impersonate="yes" Return="asyncNoWait" />
<UI>
<!-- explainations: http://www.dizzymonkeydesign.com/blog/misc/adding-and-customizing-dlgs-in-wix-3/ -->
<UIRef Id="MyWixUI_InstallDir" />
<UIRef Id="WixUI_ErrorProgressText"/>
<Publish Dialog="MyExitDialog" Control="Finish" Order="1" Event="DoAction" Value="LaunchApplication">LAUNCH_APP_ON_EXIT</Publish>
</UI>
<InstallExecuteSequence>
<Custom Action='LaunchApplication' After='InstallFinalize'>UPDATING_AUTOMATICALLY = 1</Custom>
</InstallExecuteSequence>
I would assume that you are launching your app from a custom action, which is triggered through a property bound to the checkbox. If that is the case, you can try specifying that property as a command line argument to setup.exe. Say, if your custom action is bound to the MSI property LAUNCH_NEW_VERSION, you can call setup.exe like this:
setup.exe /q LAUNCH_NEW_VERSION=1
The standard setup bootstrapper should pass that property/value to the MSI engine. If it doesn't, you might consider invoking the .msi directly instead of calling the bootstrapper exe to run your installer.
This is the approach I took.
<Property Id="WixShellExecTarget" Value="[#(the id of your exe here)]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
This will execute which ever file id you enter in the Value. The [# ] is needed. I used this and ran it via the UI but you should be able to call this custom action anywhere and it work.

Resources