I'm finding that when I update the manifest for my bootstrapper to support Windows 10 compatability, the InstallUISequence of the MSI will correctly set VersionNT=1000, but the InstallExecuteSequence will set VersionNT=603.
How do I make the InstallExecuteSequence also set VersionNT=1000?
Here's my two cents....
I don't find the VersionNT property terribly useful. VersionNT64 is: VersionNT64 .... Not VersionNT64 to determine bitness.
This is a bit of a hack (they do this, we do that...) but desperate times call for desperate measures....
In all of the compatibility games MSFT is playing they only seem to be masking the Major and Minor but Build and revision. I've also worked out that on Win8 they mask it as 6.2 and on Win 10 they mask it as 6.3. So therefore I feel comfortable doing this:
<Property Id="WIN10FOUND">
<DirectorySearch Id="searchSystem" Path="[SystemFolder]" Depth="0">
<FileSearch Id="searchFile" Name="advapi32.dll" MinVersion="6.3.10000.0"/>
</DirectorySearch>
</Property>
What I tend to do ask myself is "WHY" do I need Windows (FOO)? I then look for some registry entry or DLL that indicates that particular feature, component, API is present and use that for my test.
Microsoft has adopted an evergreen approach of "you don't need to know what version it is, you'll always have the latest and it'll always be called Windows 10" and to me this reinforces the approach I prefer to take. I know that a day will come that they are wrong and I do need to know otherwise I'll install and my application will fail and my users will complain and not know what version they have. (Sigh...)
Microsoft official answer:
When you install an .msi installation package on Windows 10 or Windows Server 2016, the VersionNT value is 603.
Source
Since msiexec.exe does not have Windows 10 compatibility in its manifest, and VersionNT is a private property, there is no clean way I'm aware of to make the execute sequence see VersionNT=1000. I would recommend one of these approaches:
copy VersionNT to another property during the UI sequence (some public property like REALVERSIONNT; be sure to list it in SecureCustomProperties like any other property you want to pass to the execute sequence),
pass in the real value from your bootstrapper (ditto), or
possibly set a registry key in your bootstrapper if you need the same information during maintenance or uninstallation, then pull its value into the installation with a system search.
(I'm torn about the registry key option, as it can go stale if the OS is upgraded in the future. Note as well that all of these options are likely to be only as correct as the manifest on your bootstrap in a theoretical future version of Windows.)
I found that a very easy and robust way of detecting Windows 10 is by calling the built-in WMIC command and parsing the output from it:
wmic os get Name,Version,BuildNumber /VALUE
it'll return exactly the info you need to determine which OS you're on:
BuildNumber=14393
Version=10.0.14393
http://helpnet.flexerasoftware.com/installshield22helplib/helplibrary/whats_newIS2015.htm
On systems with Windows 10, the Windows Installer properties VersionNT
and VersionNT64 indicate 603, which was originally introduced as the
version number of Windows 8.1. Therefore, it is not possible to create
conditions in an .msi package that specifically target Windows 10.
Since Windows Installer 5.0 and Windows 7, DLL custom actions in .msi
packages are shimmed to block obtaining the operating system version;
the APIs GetVersion, GetVersionEx, and RtlGetVersion return a Windows
version of 6.0.6000, which was originally the version number of
Windows Vista. Therefore, it is also not possible to obtain the actual
version number of Windows from a DLL custom action or from an
InstallScript custom action (which is implemented as a DLL).
Because of the aforementioned behavior in Windows Installer, it is not
easily possible to detect what version of Windows on which an .msi
package is running
For installers that do not have a bootstrapper, I've found that creating an immediate custom action that calls GetVersionEx() and sets a property for the rest of the installer to use is also a good alternative.
I've sequenced my custom action to occur after AppSearch, and it was enough to condition components with it.
Related
I have authored a COM component that is distributed through a WIX-generated MSI.
The COM component has rather complicated and non-static registration logic which means that embedding the registration information directly in the Windows Installer WXS file is not a feasible option - registration must be done using regsvr32 - and it's a 32-bit COM component, so it must use the 32-bit version of regsvr32.exe - that is %SystemRoot%\SysWow64\regsvr32.exe on 64-bit Windows or %SystemRoot%\System32\regsvr32.exe on x86 Windows.
I noticed two problems with WIX with this WXS XML:
<InstallExecuteSequence>
<Custom Action="COMRegister" After="InstallFinalize">NOT Installed</Custom>
<Custom Action="COMUnregister" After="InstallInitialize">Installed</Custom>
</InstallExecuteSequence>
<CustomAction Id="COMRegister" Directory="APPLICATIONROOTDIRECTORY" ExeCommand='regsvr32.exe /s "[APPLICATIONROOTDIRECTORY]Component.dll"' />
<CustomAction Id="COMUnregister" Directory="APPLICATIONROOTDIRECTORY" ExeCommand='regsvr32.exe /s /u "[APPLICATIONROOTDIRECTORY]Component.dll"' />
The wrong regsvr32.exe was being invoked. I noticed that the x64 version of resgvr32.exe was being run on 64-bit systems instead of the 32-bit version.
regsvr32.exe was being run without elevated permissions, so COM registration failed with E_ACCESSDENIED.
For 1. it works if I hardcoded the path to the regsvr32.exe executable using [WindowsFolder]\SysWOW64\regsvr32.exe, but this wouldn't work on a real 32-bit machine where SysWow64 doesn't exist.
For 2. I read online that changing After="InstallFinalize" toAfter="RemoveExistingProducts"would cause it to run with elevated permissions, however instead this just gives me errors aboutRemoveExistingProducts` being an unresolved symbol name.
How can I resolve these two issues?
Update
(After struggling with this problem for the past 2 hours, I'm convinced the authors of WIX are close relations of H.P. Lovecraft)
I've worked-around the first issue by writing my own intermediate-step program which is a 32-bit executable, so it will always run under a WOW context, so it will reliably invoke the 32-bit regsvr32.exe program.
I found out the issue with the second issue was these things: For a CustomAction to run with elevated permissions (well, in the same security context as the main installer job) these conditions must be true:
<Custom/>" must haveBefore="InstallFinalize", and **not**After=""any other values forBefore=""` won't work reliably as WIX or Windows Installer might rearrange the actions (wut).
<CustomAction /> have have these attributes explicitly set:
Execute="deferred"
Impersonate="off"
Even-so, I would like to not have to use my helper program to correctly resolve the 32-bit regsvr32.exe. What options are there?
I wouldn't advise using self registration at all it is not the really the right way to do it with Windows Installer, if you really must set File/#SelfRegCost to 1.
A much better way is to extract the registry values and write them with WiX - you can also use heat to generate the values.
This sounds like something that will cause you lots of problems later. Though it sounds like you are determined to use this self-registration, please read this whole post: Self-Registration considered harmful.
Software that is doing "odd things" during self-registration are really frowned upon when found in application packaging in larger companies. Sometimes it is reason enough to throw out the entire software.
If you have stuff you need done with admin rights before your application can run, you should do it as part of the installer, but not via self-registration (see a plethora of reasons in the linked post above). It is better almost any other way, including having your main application.exe run with a command line from a custom action to trigger the custom registration steps, and then provide a good log of what has actually been done. And you should revert to normal COM registration and extraction for the COM servers.
It would be interesting to hear what is unique about your COM servers? Is it the usual licensing issue?
I have an InstallShield Basic MSI project which builds both 32-bit and 64-bit installers using Release Flags mechanism to build the different packages with the correct Template Summary, etc. One of my Components is an explorer.exe shell extension, so in order for this to work it needs to be registered in the 64-bit node in the registry when installed on windows 64-bit, NOT in the Wow6432Node. However, because this is a 32-bit Component to Windows Installer it will get registered as such and go down the Wow6432Node. I am told by InstallShield that this is native Windows Installer behavior and there is really no way around this other than Custom Actions (which I have already resorted to).
Do I have to resort to running regasm? This is what I currently do however I would rather not use Custom Actions for something like this. Also, it appears that other products have the same pattern: a 64-bit shell extension, however installed down program files (x86). I see TFS Power Tools and WinZip doing this for example. For these products, I do NOT see regasm.exe running so I assume they have some other mechanism for this.
Any ideas?
Did you try to set msidbComponentAttributesDisableRegistryReflection (Component table) attribute for that component?
I created a WiX-based installer back in the WiX 3.5 days. The documentation then was even worse than it is now. To make matters worse, it was my first installer—so I didn't do everything right.
Some background: the installer installed two applications and a driver (each of these were a separate feature consisting of one or more components). One of the applications in question is a vendor-proprietary device configuration application written in VB6. Since it's a VB6 application, it uses the libraries comctl32.ocx and tabctl32.ocx.
The crux of the problem is that I didn't see these two libraries in the %windir%\System32 folder on Windows Vista (and/or Windows XP? I don't remember, it's been years since I first wrote this installer). So I thought I needed to install these two libraries along with all of their requisite COM registry entries. (I ended up installing the COM libraries in my application's folder—as you would for a private assembly, but registered them globally in HKLM.) As much as I read about things when creating the first installer, I never once came across the fact that, as of Windows XP, COM components could be installed side-by-side. (And even so, why didn't I use the MSI tables Clsid, ProgId, etc.—which granted, today, is frowned upon, but it would at least have been more correct than what I did? But I digress; what's done is done in MSI land.) Anyway, when creating the original installer, I used the following WiX markup for creating the COM registry values:
<RegistryValue ... Action="write" />
I also should mention that at the time, I had not come across any sort of 'Component Rules 101' kind of documentation as I have this time around. So, this MSI does not follow the component rules. The MSI contained one component for each COM library and its associated registry values with the COM library being the KeyPath of its component.
The question is, if the registry keys/values existed prior to my original MSI running and installing the first version of my product, will uninstallation cause these keys/values to be removed from the system? (I assume these keys/values were created during Windows setup—so are they already reference counted?) I don't want to possibly break other applications on a users' system that relies on those libraries.
If the answer to the above is yes, then my current plan to rectify the situation is:
Author a new MSI as a <MajorUpgrade />—afterall, I am performing an upgrade.
Provide the COM registry entries that were in the original installer for the comctl32.ocx and tabctl32.ocx COM libraries—I'm guessing that I would need to do this with a CA (or multiple CA's) so that they don't get removed again on the next upgrade. I see one of two ways of accomplishing this:
Directly create the registry entries taking care to ensure the values match those of a fresh windows installation (appropriate to the version of OS on which the installer is executing)
Dynamically add the registry entries to be created to the MSI Registry table (which if I understand correctly, isn't tracked by windows installer in terms of uninstallation?)
If previously existing registry keys overwritten by MSI are removed on uninstallation, then:
Is my proposed solution acceptable?
Which of the two options for replacing the removed registry entries is best?
If neither of those two options are acceptable, does anyone have any other suggestions on how I might rectify the situation so as not to break other applications that (may) rely on the libraries in question?
It was a long read but I think this is what you are looking for:
ICE09
To quote the beer commercials.... I don't always install files in the SystemFolder but when I do, I make them permanent.
First, thanks to Christopher Painter above for responding to my question; though, it's not really an answer in the sense that I'm looking for—fixing an existing installer that's "out in the wild". Though, in his last comment about a minor upgrade, that might work for some people.
Next, thanks to Aaron Stebner who responded to my e-mail requesting guidance on this same issue. His advice is to author a MSI component which has no ID. By authoring such a component into a MSI, the component is not tracked by MSI; essentially, it becomes a permanent, uninstallable component. This might work in this situation, if it were completely necessary.
However, after doing some research, I believe that there isn't much risk to damaging a user's system by removing the registry entries I outlined above.
I loaded a fresh copy of Windows XP SP3 and Windows Vista SP1 into a virtual machine. Out of the box, neither of these versions of Windows have the COM components in question registered in anyway in the Windows registry. This makes sense, since from Windows XP onward, there has been registry-free COM registration. This also continues to be the case for Windows 8.1—again, this was expected.
The worst that could happen if these registry keys are uninstalled is that some other older piece of software on a machine that relied on such registry entries could end up broken (e.g. this software is from the late-90's to early 2000's era and used a non-MSI installer and/or installed the COM libraries globally—which they shouldn't have done in the first place—just like I shouldn't have done in the first place ;) ). At that point, the user can either re-register the COM libraries using regsvr32.exe or repair/reinstall the application in question. The likelihood of such applications existing are slim to none in this day and age.
I want to install some files to a folder located at "C:\Users\Public\MyApp". Is there a pre-defined variable in WiX that resolves to "C:\Users\Public" in Windows 7 and equivalent location in other versions of Windows?
No. WiX defines only these variables in Setup projects:
sys.CURRENTDIR
sys.SOURCEFILEPATH
sys.SOURCEFILEDIR
sys.PLATFORM
And WiX variables are only used when the setup package is built.
You probably mean Windows Installer properties. They depend on the Windows Installer version are listed here. Note: when reading the required version of Windows Installer, the docs do you the disservice of listing the minimum version that could actually be installed on a particular operating system version. The minimum version to support a property would be the lowest of those.
The answer is still "no." In fact, there isn't even a CSIDL API to locate that folder. As of Windows Vista, there is a FOLDERID API, though Windows Installer doesn't use it.
The point is, that's not where installed files go! Please consider [CommonAppDataFolder].
This problem is solved as below:
<Directory Id="UserPublicMyAppFolder" Name="MineSched">
</Directory>
<SetDirectory Id="UserPublicMyAppFolder" Value="C:\Users\Public\MyApp" />
I'm trying to find a solution for the following issue:
I have numerous programs (lets call them slaves) that all rely on a single program (master). I need to distribute an installer for each slave. This installer needs to install the master.
I want to be able to version both pieces, so multiple msi's appear to be the right solution, chained with a bootstrapper.
My problem is if a slave installer installs the same version of the master that is already installed, the .msi will run in repair/remove mode.
This is unacceptable from a user standpoint and will just cause confusion.
Is there any way to check for a version of the currently installed fiels before trying to run the msi?
I am currently using WIX's setupbld.exe as a bootstrapper.
Any other solutions greatly appreciated (I have also tried merge modules with no success, since the versioning is useless)
Instead of using setupbld.exe (which I don't really know as I can't find any documentation) you can use msbuild's generatebootstrapper task. The wix documentation already covers how to use this task to generate a bootstrapper that installs the .NET framework. See How To: Install the .NET Framework Using a Bootstrapper. This makes use of the pre-defined bootstrapper packages.
However, in this case you will also have to author your own bootstrapper packages. One way to do this is to study the existing bootstrapper packages in C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\ (or the ones in the Windows SDK) and read the documentation of the Bootstrapper Manifest XML format. The bootstrapper generator tool might also be helpful.
To determine whether the package needs to be installed, you can use one of the InstallChecks to set a property, and then check the property value in a InstallCondition under the Commands element.
If you're thinking that this is all harder than it should be — I agree, but it's what I've used so far. There are some alternatives which I have not tried yet:
the poorly named dotNetInstaller
which is actually a general purpose
bootstrapper generator.
the wix 3.5 burn bootstrapper which is not yet released. I'm not sure if it is in a usable state yet.