I'm new to WiX installer but I need to solve a situation. After searching for some time I haven't found any solution.
I need to read a value from SQL Server while running the WiX installer and keep it, but I'm not sure if it is possible. All I've found are 'updates' or 'insert' query examples, but no 'select'.
Has someone done something like this?
When you need to read something from somewhere during the installation process, you have several options:
if it has a trace in the registry, then RegistrySearch is the proper choice
if it has a file installed to the well-known location, then DirectorySearch/FileSearch approach fits best
otherwise, you always have the last resort - a custom action
Obviously, if you need to read something from SQL Server, custom action is the only choice for you. So, to tell it short, you should create an immediate custom action which will read the data you need and place it to the property (or a number of properties). You should use this property later in your installation.
Try to avoid custom actions as much as you can, but if you have no other choice, still try to find the tested ones. For this particular case, take a look at the Community MSI extensions.
Although you might solve this particular problem fast, I would still encourage you to dive deeper into the topic and understand how Windows Installer (the underlying technology behind WiX Toolset) works. Start from MSDN.
You could use the registry extended stored procedures to insert the value you need into the registry and then do a Registry search to pull the values into your installer.
As the blog post says the sp's are undocumented and thus unsupported but if it works for you it will save writing a custom action.
Related
We have a unique requirement to create an msi using wix,the catch is that the msi must support multiple instance installation. User should be able to use the msi to install the product more than once on a particular system, so in order to achieve this we should disable repair mode and upgrades in msi, so literally each invocation of msi should be treated as fresh install.
Is the above requirement technically feasible with Wix? I am aware that having unique product code and package code for every invocation of msi will treat the installation as fresh install. Can this be achieved using a wrapper around the msi?
You could do this with a wrapper around the MSI. In general your wrapper program would start with the base MSI, alter the ProductCode and PackageCode using the Windows Installer APIs, copy this MSI to a location on the system then install it from there.
I say "copy and install" because it's futile trying to disable repair - it's too baked into the architecture of Windows Installer. If you have each separate MSI product cached somewhere then repair will work using that unique MSI, and it also means that you could modify as well. Repair is too unpredictable to completely prevent. Any shared files can trigger repair from other installed products that share them. What do clients do if they accidentally delete files or registry entries? And there's this about keeping the source MSI available, although the list of reasons doesn't come with a lot of explanation, Rule 31:
https://blogs.msdn.microsoft.com/windows_installer_team/2006/05/24/tao-of-the-windows-installer-part-3/
There are a lot of other issue that aren't mentioned, so it's not clear if you care about patches and maintenance in general, about multiple entries in Programs/Features (that you could suppress, but how do you uninstall?) and so on. It's also not clear that each of these separate installs don't conflict with each other in any way, such as common files/registry entries, service names, files being installed in the same location with the same name.
Before sending you to the MSI SDK I should add that I dislike this instance transform concept myself, and have not used it in practice. It might be that I have become a grumpy old man! :-).
MSINEWINSTANCE: Please investigate the MSINEWINSTANCE property and read up on the MSI SDK topic: "Installing Multiple Instances of Products and Patches". And here is perhaps a better example - more practically oriented.
Also some context on why I am not too keen on this feature. Carolyn Napier was on the original MSI team - this is straight from the horse's mouth as they say.
I know some people claim success with these instance transforms (Chris Painter might be able to illuminate my claims here), but I'd rather virtualize in scenarios such as these. Please see this age-old post from serverfault.com: I want to install an MSI twice (please skim all the other answers in that "thread" too).
APP-V: I have almost zero App-V experience, but my guess is that this is what you should try to convince your manager to spend some time on investigating. Maybe call in some favors and talk to guys who are operative in current deployment. They always have the current prevailing prejudice to report - with the tricks that make things work in the real world.
Great if you can let us know how you end up solving the problem.
Disable Repair & Modify: And for the record: disabling repair and modify (buttons only) can be done by setting the ARPNOMODIFY and ARPNOREPAIR properties. But this is not what you are looking for to allow multiple instance installations. MSI is not easily fooled and knows what you have installed and when - no reason to waste time testing these "options". All these two properties do is to hide or disable the modify and repair buttons - yields nothing you need apart from that.
I have a big program in WiX that uses a bunch of MSIs, C# custom action programs, UIs, bootstrapper, you name it, it's there.
I'm having this problem: when I run a major upgrade, the previous version isn't being erased. That is, if I upgrade from version 1.0.0.x to 1.1.0.x, Programs & Features shows that both versions are installed on the machine.
This is a common problem, with many solutions here on SO. None of them are working for me -- if there's a post of SO about this, I've tried it.
I've been told that there's a one-to-one relationship between components in a major upgrade. That is, for every component that is removed, another component has to be added. When it's NOT a one-to-one relationship is when the old version doesn't get removed -- because there are still old components hanging.
Is there a way to determine what components are hanging? Like, in the log files or something? If I could determine what MSI is having the problem I could be far more proactive in solving the issue.
EDIT:
Although I haven't solved the problem, thanks to Mr. Urman's suggestions I may be on the right track.
I created that registry key, but... it didn't seem to do anything. However, I did search my uninstall logs for the word "Disallow", and I found this phrase 9 times:
Disallowing uninstallation of component: {GUID-HERE} since another client exists.
Also, this phrase appears before each grouping of the "Disallow" phrase:
PROPERTY CHANGE: Adding INSTALLLEVEL property. It's value is '1'.
This gives me something to go on. However, I can't seem to find the GUIDs that are mentioned! They're not in my solution nor are they searchable in the registry. Besides searching the registry, is there a way (Windows 7 32 bit) to find out what component a specific GUID corresponds to?
I've been told that there's a one-to-one relationship between components in a major upgrade. That is, for every component that is removed, another component has to be added. When it's NOT a one-to-one relationship is when the old version doesn't get removed -- because there are still old components hanging.
This is not strictly true. It's quite true of minor upgrades, and in certain configurations (those involving a late RemoveExistingProducts) major upgrades are just as picky. But your typical major upgrade functions more like the user had chosen to uninstall the old version, then to install the new version. Start by verifying your assumptions: make sure you have a proper major upgrade (you changed your ProductVersion and Product Code, and have the right entries in your Upgrade table, right?). Then diagnose.
How best to identify what's going on? In my experience, log files are your best bet. Since the older version is being uninstalled indirectly, you cannot use command lines to log it. So instead set the Logging policy by creating or setting the following registry value. (Remove it later when you want to revert the setting.)
HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer
Value (Reg_SZ): Logging
Data: voicewarmup
Then run your major upgrade, find the appropriate log file that was generated in %temp%. (Consider cleaning out %temp% ahead of time to make finding it easier. Or sort by date.) Look especially at the uninstallation (which you can identify by ProductVersion, or the presence of UPGRADINGPRODUCTCODE). I'd look especially for lines like Disallowing uninstallation of component ... that contain a component GUID.
Once you have that GUID, you have to figure out what component it is, and how it got into its current state. You can manually examine your built .msi files (with a tool like Orca) to find the component, but few tools will tell you all the clients. My employer's product comes with a helper tool called InstallShield Msi Sleuth that can list all the installed products referencing a component code, or you can build your own from MsiEnumProducts or Installer.ComponentClients. You cannot just search the registry directly, because Windows Installer stores GUIDs in a compressed or packed form.
Then identifying the "why" could be the hard part. Or it could be as simple as an incorrect Shared DLL reference count, especially if you've only encountered this on a test machine that has seen non-released versions of your product.
As a related alternative, but only relevant to a minor upgrade or small update, you could set the EnforceUpgradeComponentRules Policy. This helps reveal problems as you hit them, rather than allowing Windows Installer to do its best to continue anyway.
I have a small question.
Which action removes installed product info (which was advertised with PublishProduct action) during uninstallation?
Thank's in advance.
Short answer: InstallFinalize.
Long answer: it comes down to the InstallExecuteSequence being the thing that always runs removal. I have a deeper investigation on my blog.
Frankly I never use advertising, but if I were to guess I would say that the advertisement sequence is defining a subset of the InstallExecuteSequence that is run during advertisement, and that the actual uninstall of the advertised product is actually running the full InstallExecuteSequence in uninstall mode to run standard actions such as UnPublishComponents, UnPublishFeatures, etc... I think this is logical since certain features could already have been installed by installation on demand, and a full uninstall is then necessary to clean up.
One way to test this is to insert message boxes in the InstallExecuteSequence to determine what sequence is run. I don't have the tools required to test this here and now. Again, until I have tested this with debugging scripts inserted into the sequences I can't be sure of anything.
The MSI SDK and Installshield's help file may provide some clues. In concluding I would like to ask you why you need to know what action uninstalls the product info? Perhaps we can provide a different way to achive what you want to do. Much of the point of MSI is to leave most of the work to standardized actions, and it is not good to interfere with these processes. Custom
actions should be used only for stuff that can never be achived with standard actions.
I'm currently trying to write a program in VB.NET which fluidly changes the DWM window colorization colors in Windows 7.
I first tried to edit Registry values directly, but I had to restart the UXSMS service. This solution was unsatisfying, because of the toggle of the taskbar.
I'm now searching for a function in a DLL such as user32.dll or themecpl.dll which can reproduce the behaviour of control panel when setting the window color.
I'm now on IDA, searching for the adquate function (CColorCplPage::SetDwmColorizationColor seems good!). If anyone has one, please share it!
(If anyone need screens or code, please ask. Sorry for my poor English.)
Your first attempt failed because manually editing the Registry is never the correct way to change system settings. As you found out, lots of Windows components (and other applications!) read those configuration values once and cache them, preventing your changes from being propagated. Another problem (and you'd be surprised how often I see this) is applications that attempt to muck around in the Registry generally end up corrupting things.
Instead, you should call the documented API to change the settings. There's almost always a documented way of doing this, and if there isn't, well then you shouldn't be doing it.
This appears to be one of those cases. There's a documented DwmGetColorizationColor function, but there's no corresponding DwmSetColorizationColor function, as one might expect.
The reason is that the user is supposed to be the only one who can change their colorization settings, not other applications. You might promise not to abuse this, and to only make such changes at the user's explicit request, but not all applications can be trusted to do this. Lots of people would use it maliciously, so these functions have not been documented and exposed.
But as usual, if you press on, you can usually find an undocumented way of doing things. The problem with using undocumented functions is that there's no guarantee they'll work or continue to work. They've been intentionally left undocumented because they're liable to change on new versions of Windows. You should only use them at your own risk.
In this case, if you use a program like DumpBin to obtain a list of all the exported functions from the DWM DLL (dwmapi.dll), you'll see a number of undocumented exported functions.
The ones you're interested in are DwmGetColorizationParameters and DwmSetColorizationParameters. Both of these functions take a COLORIZATIONPARAMS structure as an argument that contains the values they need.
So, you need to reverse engineer these functions and obtain the appropriate definitions. Then, you can call the DwmGetColorizationParameters function, passing in a COLORIZATIONPARAMS structure to obtain the current configuration settings; modify the member of the structure that contains the current colorization color; and then pass that modified version of the structure to the DwmSetColorizationParameters function.
Did I mention that I don't recommend doing this?
Following the advice of wcoenen, I've decided to try using registration-free COM. This works perfectly, excepting on pre-XP machines, of course. One idea which I thought would be kind of neat would be to add to some files, SelfRegCost='[var]'. It is quite likely that this is not The Right Thing™ but I still want to know how to do it, if only to satisfy my own curiosity. I'm assuming, perhaps incorrectly, that SelfRegCost='[var]' will not cause self-registration if var is an empty string. But this could be wrong.
This is similar to "WIX: How can the registry key be changed based on the OS on which the installer is running ?", but in my case I realize I can (and probably should) use a different component and just don't care.
It is quite likely I'll probably end up using a different component anyhow, but please satisfy my curiousity.
I haven't had to do COM installation with WiX (thank god). But from the docs and this thread, it sounds like SelfRegCost is just there to give MSI an idea how much space it needs to verify is available. I'm guessing blank will either be an error, or be treated as a zero and still install the DLL.
I would definately go with the multiple components.
You need to use conditional components to install in different ways to different OS's.
What you are suggesting is to have part of the installation fail, but hopefully silently.
Using a custom action, you can do just that!
<CustomAction Id="YourId" Directory="INSTALLDIR" ExeCommand='regsvr32.exe /s "[INSTALLDIR]YourCOM.dll"' Return="ignore" />
This is of course not recommended for the slew of reasons Rob Mensching provides.