Writing install location to registry from installer - wix

I am using WiX 3.6 to create an installer.
One of the needs is to write the location of the install location to the registry in either HKCU or HKLM depending on the ALLUSERS property.
Now based on the research I have done I think the following should work
<RegistryKey Root="HKMU"
Key="Software\OpenCover"
Action="createAndRemoveOnUninstall">
<RegistryValue Name="Location"
Type="string"
Value="[APPLICATIONFOLDER]"
Action="write"
KeyPath="yes" />
</RegistryKey>
The problem is it only works for when ALLUSERS="" i.e. HKMU is interpreted as HKCU.
If I try a perMachine installation where ALLUSERS=1 then the entry is not written to HKLM as expected, though when I look at the installer log file I see the call to WriteRegistryValues.
MSI (s) (D4:14) [22:46:24:901]: Executing op: ActionStart(Name=WriteRegistryValues,Description=Writing system registry values,Template=Key: [1], Name: [2], Value: [3])
Action 22:46:24: WriteRegistryValues. Writing system registry values
MSI (s) (D4:14) [22:46:24:902]: Executing op: ProgressTotal(Total=2,Type=1,ByteEquivalent=13200)
MSI (s) (D4:14) [22:46:24:903]: Executing op: RegOpenKey(Root=-1,Key=Software\OpenCover,,BinaryType=0,,)
MSI (s) (D4:14) [22:46:24:903]: Executing op: RegAddValue(Name=ConsoleLocation,Value=C:\Program Files (x86)\OpenCover\,)
WriteRegistryValues: Key: \Software\OpenCover, Name: ConsoleLocation, Value: C:\Program Files (x86)\OpenCover\
MSI (s) (D4:14) [22:46:24:906]: Executing op: RegCreateKey()
WriteRegistryValues: Key: \Software\OpenCover, Name: , Value:
Can someone explain how to achieve the task I need to complete

The problem is actually to do with a 32 bit installer on a 64 bit platform.
When ALLUSERS="1" is used in this scenario then the registry entries, marked up with HKMU, are actually being written, but under in this case, HKLM\Software\Wow6432Node\OpenCover. I suspect entries marked as HKLM are also redirected in the same manner.
Unfortunately the documentation on WriteRegistryValues Action does not explain the 32/64 bit of "magic" redirection and the information, details regarding the actual registry entry, doesn't appear in the logs.
To get an insight as to what is happening then the following article demystifies the observed behaviour Registry Keys Affected by WOW64. From this article we can see that the installer "thinks" it is writing to a folder HKLM\Software but this is actually being "redirected" to HKLM\Wow6432Node\Software for a 32 bit process on a 64 bit platform and hence explains why it is not reflected into the log files. The article also explains why when ALLUSERS="" and HKMU is then HKCU why the entries appear where one would expect them to be, because these entries are "shared" between 32 and 64 bit applications.

My guess is that your installer isn't elevating (UAC enabled?) and that the write to HKLM is being redirected to HKCU.
BTW, you could also consider using the Windows Installer API from within your application to query the UpgradeCode, ProductCode, ProductInformation(INSTALLLOCATION) without the need to write a registry key to store this metadata.

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...>

MSI Registry prepend value not updated

We are using wix 3.9.1208.0 to generate MSI. Below code prepend the value to Upperfilters registry key.
<RegistryKey Id="UpperFilters" Root="HKLM" Key="xxxxxxxxx" Action="create">
<RegistryValue Name="UpperFilters" Type="multiString" Action="prepend" Value="xxxxx"/>
</RegistryKey>
After install observed, value not prepend to 'UpperFilters' registry key and not found any errors in MSI log. This issue happened only once.
MSI Log:
MSI (s) (0C:28) [10:38:08:835]: Executing op: ComponentRegister(ComponentId=xxxx,KeyPath=02:xxxxx,State=3,,Disk=1,SharedDllRefCount=0,BinaryType=0)
MSI (s) (0C:28) [10:38:24:455]: Executing op: RegOpenKey(Root=-2147483646,Key=xxxxx,,BinaryType=0,,)
MSI (s) (0C:28) [10:38:24:456]: Executing op: RegAddValue(Name=UpperFilters,Value=xxxxx[~],)
Is MSI returns any failures when unable to update registry?
Will all registry failures are recorded in MSI log?
What's the issue in my scenario?
Thanks in Advance.
It might help to show more from the log. It's hard to tell what's going on from those log fragments. ComponentRegister isn't typically next to RegOpenKey - it's just a register of the keypath in the registry and not related to the actual issue.
There are few things that could be wrong:
Why is the Component id xxxx? Have you hidden the actual guid when you posted the log information or is that what you actually used? It's not a legal id.
It's a 64-bit system and you tried to update the 32-bit registry. Without knowing the system bitness and your MSI's architecture we can't tell if you updated the required key.
Prepending doesn't really do anything if there is nothing in the existing data, so without seeing the data before and the data afterwards it's not clear if it worked correctly (because there was nothing to prepend to) or failed (because it did not actually prepend your data to the existing data).

How does the MSI Installer InstallValidate determine files in use?

I'm trying to work out how to prevent the Restart Manager from detecting that a restart is required when I uninstall my application.
My application has a Windows Service which uses a native DLL (Tanuki Wrapper) and creates another process (Java) which writes to some log files. I'm using WiX Toolset but I'm more interested in the MSI Installer itself. I've been trying some changes manually using Orca. For reference the relevant WiX configuration is (there are some other components for JARs etc that I have omitted):
<DirectoryRef Id="logs3327407xx">
<Component Guid="344ec345-bdd7-4c1d-801f-55ddf9e07735" Id="logs_wrapper_log88580873x">
<File DiskId="1" Id="fl_logs_wrapper_log88580873x" Name="wrapper.log" Source="logs\wrapper.log"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="bin97543xxxx">
<Component Guid="67c93dd8-36ad-427f-9d79-64a07c719eea" Id="bin_wrapper_windows_x86_64_exe189026768">
<File DiskId="1" Id="fl_bin_wrapper_windows_x86_64_exe189026768" KeyPath="yes" Name="wrapper-windows-x86-64.exe" Source="bin\wrapper-windows-x86-64.exe"/>
<ServiceInstall Account="LocalSystem" Arguments="-s "..\conf\wrapper.conf" wrapper.console.flush=true" Description="My Example Service." DisplayName="My Service" ErrorControl="ignore" Id="srvc_i_bin_wrapper_windows_x86_64_exe189026768" Interactive="no" Name="MyService" Start="auto" Type="ownProcess" Vital="yes"/>
<ServiceControl Id="srvc_c_bin_wrapper_windows_x86_64_exe189026768" Name="MyService" Remove="uninstall" Start="install" Stop="both" Wait="yes"/>
</Component>
</DirectoryRef>
<DirectoryRef Id="bin_wrapper_native490235675">
<Component Guid="d7e4295a-1ce5-4dd2-aa92-230caac34247" Id="bin_wrapper_native_wrapper_windows_x86_64_dll156404367">
<File DiskId="1" Id="fl_bin_wrapper_native_wrapper_windows_x86_64_dll156404367" Name="wrapper-windows-x86-64.dll" Source="bin\wrapper\native\wrapper-windows-x86-64.dll"/>
</Component>
</DirectoryRef>
I understand that there is logic in the InstallValidate action that determines whether files are in use. It will either use the Restart Manager or the FilesInUse based on the MSIRESTARTMANAGERCONTROL property.
If I use the Restart Manager then it opens the dialog saying a restart is required. The logs say:
MSI (s) (1C:7C) [12:27:14:679]: Doing action: InstallValidate
Action ended 12:27:14: MigrateFeatureStates. Return value 0.
MSI (s) (1C:7C) [12:27:14:679]: PROPERTY CHANGE: Deleting MsiRestartManagerSessionKey property. Its current value is 'f2947dee632d694f8b4f1795ff254092'.
...
MSI (s) (1C:7C) [12:27:14:679]: Component: bin_wrapper_windows_x86_64_exe189026768; Installed: Local; Request: Absent; Action: Absent; Client State: Local
MSI (s) (1C:7C) [12:27:14:679]: Component: bin_wrapper_native_wrapper_windows_x86_64_dll156404367; Installed: Local; Request: Absent; Action: Absent; Client State: Local
MSI (s) (1C:7C) [12:27:14:679]: Component: logs_wrapper_log88580873x; Installed: Local; Request: Absent; Action: Absent; Client State: Local
...
MSI (s) (1C:7C) [12:27:14:741]: RESTART MANAGER: Detected that application with id 11368, friendly name 'java.exe', of type RmCritical and status 1 holds file[s] in use.
MSI (s) (1C:7C) [12:27:14:741]: RESTART MANAGER: Did detect that a critical application holds file[s] in use, so a reboot will be necessary.
MSI (s) (1C:7C) [12:27:14:741]: Note: 1: 1610
It doesn't actually say the files but if I disable the Restart Manager and use the FilesInUse instead then no dialog appears. This time the logs say:
Info 1603. The file C:\...\wrapper-windows-x86-64.exe is being held in use by the following process: Name: wrapper-windows-x86-64, Id: 11004, Window Title: '(not determined yet)'. Close that application and retry.
MSI (s) (1C:8C) [12:33:23:458]: 2 application(s) had been reported to have files in use.
Info 1603. The file C:\...\wrapper-windows-x86-64.dll is being held in use by the following process: Name: java, Id: 8284, Window Title: '(not determined yet)'. Close that application and retry.
MSI (s) (1C:8C) [12:33:23:458]: Note: 1: 2727 2:
MSI (c) (AC:28) [12:33:23:458]: File In Use: -wrapper-windows-x86-64- Window could not be found. Process ID: 11004
MSI (c) (AC:28) [12:33:23:458]: File In Use: -java- Window could not be found. Process ID: 8284
MSI (c) (AC:28) [12:33:23:458]: No window with title could be found for FilesInUse
Can someone please explain how the InstallValidate determines which files are in use?
Additionally how can I prevent the Restart Manager from saying that files are in use which will be released once the service is stopped?
As a side question, why is the Restart Manager not showing the MsiRMFilesInUse dialog? I have checked all the requirements on MsiRMFilesInUse Dialog and as far as I can tell they are all true.
I remember reading somewhere that using a ServiceControl rather than a custom action helps the Restart Manager know that those Files within that Component are used by the service. I have tried adding the files to that Component but it doesn't seem to make any difference.
The behavior of InstallValidate and in-use files related to ServiceControl isn't complicated. If there are files in use by a service and that service is in the ServiceControl table and marked to be stopped on uninstall then it will ignore those files as far as in-use behavior. Putting files in the same component makes no difference, and obviously Windows can't know that the service code is going to shut down processes that are causing files-in-use situations. To my knowledge there is no way of telling InstallValidate that some files really won't be in-use when they are due to be uninstalled.
You won't get an old-style FilesInUse dialog when Restart Manager isn't used because it requires an active window that the user can be prompted to close to shut down the app. This is the reason tray apps without an active window don't cause a FilesInUse dialog. I can't be sure, but it appears to me that the first log extract referring to Restart Manager actually IS RMFilesInUse, and I think that's the dialog you're seeing.
If the only files-in-use issues you're seeing are related to the java process that the service will shut down then a possible solution is:
Suppress all files-in-use dialogs during uninstall.
Use ServiceControl to shut down your service.
Ensure that your ServiceControl was Wait=1 and that it does not respond to the "stop service" request until the java process has been terminated, assuming you can explicitly shut it down.
Windows isn't so dumb that it will force a reboot just because files were in use at InstallValidate time but that isn't true at actual removal time. So the reboot won't be necessary if you can make sure that the files are no longer in use at the actual time they need removing/replacing/whatever. It's not unusual to see the dialog and then find that a reboot is not in fact necessary. So if you suppress the dialog and get everything shut down you won't see a reboot request.

Wix MSI fails when setting permissions on network path (util:PermissionEx)

I have an MSI that works perfectly when installing locally. If the data path is set to a network location, it fails.
Relevant LOG:
MSI (s) (BC:4C) [17:01:57:322]: Executing op: ActionStart(Name=ExecSecureObjects_64,,)
MSI (s) (BC:4C) [17:01:57:322]: Executing op: CustomActionSchedule(Action=ExecSecureObjects_64,ActionType=3073,Source=BinaryData,Target=ExecSecureObjects,CustomActionData=\\ravel\TeamData\lrieger\Tim2015Pre_Data\CreateFolderEveryone-1073741824C:\ProgramData\Nemetschek Engineering\TIM 2015.0.0.477590057-pre\CreateFolderEveryone-1073741824)
MSI (s) (BC:78) [17:01:57:324]: Invoking remote custom action. DLL: C:\Windows\Installer\MSIAEDE.tmp, Entrypoint: ExecSecureObjects
MSI (s) (BC:A8) [17:01:57:324]: Generating random cookie.
MSI (s) (BC:A8) [17:01:57:325]: Created Custom Action Server with PID 4488 (0x1188).
MSI (s) (BC:60) [17:01:57:335]: Running as a service.
MSI (s) (BC:60) [17:01:57:337]: Hello, I'm your 64bit Elevated custom action server.
ExecSecureObjects: Error 0x80070005: failed to get security info for object: \\ravel\TeamData\lrieger\Tim2015Pre_Data\
CustomAction ExecSecureObjects_64 returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
MSI (s) (BC:4C) [17:01:57:393]: Note: 1: 2265 2: 3: -2147287035
MSI (s) (BC:4C) [17:01:57:393]: User policy value 'DisableRollback' is 0
MSI (s) (BC:4C) [17:01:57:393]: Machine policy value 'DisableRollback' is 0
Action ended 17:01:57: InstallExecute. Return value 3.
WIX Code:
<Component Directory="DATA_DIRECTORY">
<RegistryValue Root="HKLM" Key="$(var.RegRoot)\Setup" Name="TIM_DATA_DIRECTORY" Value="0xff" Type="string" />
<CreateFolder>
<util:PermissionEx User="Everyone" GenericRead="yes" GenericWrite="yes" Domain="[LOGONDOMAIN]" />
</CreateFolder>
</Component>
Without the util:PermissionEx it works on the network share, but setting these permissions is a requirement, at least if the target directory is local.
Q: Is it possible to set permissions on a network location with wix/msi?
If Not, how can I detect that it is a network directory?
Or is there, in MSI, any way to mark a component as allowed to fail?
If it is not possible to do any of the above, I will probably need to write a custom action that tries to set the permissions but suppresses any failures...
Briefly, I don't think it's possible. The issue is that elevated custom actions run with the system account, and that account doesn't have any network privileges. That WiX utils code is already a custom action that's supplied as a helper for a common task, so writing your own custom action isn't going to help. If you run the CA not impersonated it won't run elevated (unless you elevate the entire MSI install at launch time) so that's not likely to help either. You need an elevated user app to do this for the network share, maybe run at first use of the app itself. This might help:
http://wixtoolset.org/documentation/manual/v3/howtos/ui_and_localization/run_program_after_install.html
I would assume it's a network share if it starts with \. A drive letter won't work with the CA anyway because drive letters are a user profile mapping (not a system mapping), so the system account won't know of them. In .Net, FileSystem.GetDriveInfo would help.

Wix v3.7 - Error Writing Registry Values

I'm creating an installer using wix and I'm having problems writing to the registry. Here is my RegistryValue element:
<Component Id="CMP_odbcreg" Guid="{115B002E-F4C9-48CD-8E1C-E8803B16AE69}">
<RegistryValue Id="rg_psql"
Root="HKLM"
Key="SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers"
Name="PostgreSQL"
Value="Installed"
Type="string"
KeyPath="yes"
Action="write"/>
</Component>
Nothing is being written to the registry. This component is in my main install feature, so it should always write to the registry. I looked at my log file and found this:
MSI (s) (60:1C) [00:00:07:080]: Doing action: WriteRegistryValues
MSI (s) (60:1C) [00:00:07:080]: Note: 1: 2205 2: 3: ActionText
Action 0:00:07: WriteRegistryValues. Writing system registry values
Action start 0:00:07: WriteRegistryValues.
WriteRegistryValues: Key: Writing system registry values, Name: , Value:
Action ended 0:00:07: WriteRegistryValues. Return value 1.
I don't know if I'm interpreting that right, but it seems like nothing is being written to the registry at all. I have several other components generated using heat that contain RegistryValue elements which should have been executed in addition to CMP_odbcreg. I checked my Windows Registry and confirmed that no values are being written.
I have a wix manual which contains an example of writing to the registry. I tried copying and pasting it into my installer and adding it to the main install feature. That didn't work either
Please Help!
So it turns out I was looking at the wrong registry. Windows 7 machines have a 32 bit AND a 64 bit registry, so I should have been looking at the regedit.exe found in Windows\SysWOW64.
Since nowadays 64 bit systems are widely spread I recommend a small lecture on Registry Redirection, I am sure you will find the info useful for the future. This applies to any application accessing the registry, not just to an installer.
In your case, if you need to disable the redirection for the installer, you can have a look at this SO thread.