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.
Related
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...>
When I'm building my MSI file, and I use a basic condition, the expected happens. For example, let's say that I have this in Setup File:
<Property Id="myProperty" Value="0"/>
<Condition Message="Value of myProperty is [myProperty], and it should be 1.">
<![CDATA[Installed OR myProperty = "1"]]>
</Condition>
If I build this and run the MSI file, it works -- that is, it displays the error message and quits.
Working condition when running MSI
However, if I put the MSI into a Bundle, it doesn't work. That is, when I put just this into my Bootstrapper ("Properties" below is the name of my Setup project -- bad name, I realize):
<Chain>
<MsiPackage SourceFile="$(var.Properties.TargetPath)"/>
</Chain>
And then I run the setup file, I get an error. When the installation starts, it checks the condition, gives me the expected message box (same as above), and then I get this error message:
Setup Failed
Looking at the Log, I get three error messages:
Error 0x80070643: Failed to install MSI package.
Error 0x80070643: Failed to execute MSI package.
Error 0x80070643: Failed to configure per-machine MSI package.
With the exit code:
Exit code: 0x643, restarting: No
I'm such a noob at WiX that I'm not even sure how to go about researching what the problem is -- I can't even ask an intelligent question. Hence, I'm reaching out to you kind folks!
(I'm using WiX 3.10 and Visual Studio 2015)
EDIT:
Thanks for getting back to me! I tried your suggestions:
In the installer file, I made the property public and I made it secure. I left the condition the same, and, since I don't think that I should get the value here as opposed to in the bootstrapper, I left the value of the property out. Here is the code that I made for the property/condition:
<Property Id="MY_PROPERTY" Secure="yes"/>
<Condition Message="MY_PROPERTY is [MY_PROPERTY]. Should be 1">
<![CDATA[Installed OR MY_PROPERTY = "1"]]>
</Condition>
Then, in the boostrapper file, I added a child element of and gave it a value:
<MsiPackage SourceFile="$(var.LCondErrorInstaller.TargetPath)">
<MsiProperty Name="MY_PROPERTY" Value="0"/>
</MsiPackage>
When I ran it, I got almost the same behaviour as I did before, except for one difference -- when I get the error message. This time, I get the pop-up screen with the Message condition and the same error message as I did before (see "Setup Failed" above), except this time I get it happens little later in the installation, making me think that the condition is, in fact, getting triggered in the bootstrapper.
As far as the log files, they look the same (I'm not sure how to get log files of the MSI when running the Burn file, what I do now is just run the Burn file with the flag "/l", like so: > file.exe /l logFile.log).
For clarity, here are the parts of the log file that appear to be important:
Error 0x80070643: Failed to install MSI package.
Error 0x80070643: Failed to execute MSI package.
Error 0x80070643: Failed to configure per-machine MSI package.
...
Exit code: 0x643, restarting: No
I should have been more specific when I initially asked the question about what kind of behaviour I'm looking for...
I will have more than just that one MSI file in the Burn file. What I want to do is this: when the Burn file installs, if there is a condition in one of the MSI files that is not met, I want that MSI file to simply not be installed, and the rest of the MSIs to be installed. I don't care about the UI.
If there's another way to do this, I'm all ears.
If you have launch conditions in the MSI you can replicate or move those launch conditions into the bootstrapper bundle itself to stop this type of behaviour.
Launch condition failure returns Fatal Error 1603 (0x643 in hex) which is what I would expect to see when the MSI launched by the bootstrapper fails due to launch condition not met.
You should see something like this in the msi's logs
Action ended 17:33:38: LaunchConditions. Return value 3.
MSI (c) (08:4C) [17:33:38:610]: Doing action: FatalError
Action 17:33:38: FatalError.
Action start 17:33:38: FatalError.
...
MSI (c) (08:4C) [17:33:41:188]: MainEngineThread is returning 1603
To elaborate, you would have to change your msi package definition to the following to get it to run properly through the bootstrapper
<Chain>
<MsiPackage SourceFile="$(var.Properties.TargetPath)">
<MsiProperty Name="MYPROPERTY" Value="1"/>
</MsiPackage>
</Chain>
Additionally if you want to pass in a property from your bootstrapper to your MSI the property must be a public property which is a property whose name is ALL CAPS.
If you want to use this property somewhere in the Install phase of your msi you must also mark this property as secure.
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).
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.
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.