Welcome to MSDN Blogs Sign in | Join | Help

The Release of Visual Studio 2008 SP1 will Install over SP1 Beta

One of many improvements made to Visual Studio 2008 Service Pack 1 is that VS 2008 SP1 Beta customers will not need to uninstall SP1 Beta before installing the release of SP1. The same is true for Visual Studio 2008 Express products and .NET 3.5 SP1 - both of which are complete upgrades to older products that may already be on the system or that can be installed on a clean system.

So please read the requirements and known issues, give Visual Studio 2008 SP1 Beta a try, and provide feedback about we can improve the release of VS2008 SP1 and future releases.

How to Download all of Visual Studio 2008 SP1

Visual Studio 2008 Service Pack 1 is comprised of multiple packages, including executables, installer packages, and patches. Compare this with Visual Studio 2005 SP1 which was a single patch wrapped in an executable. A lot of updates were made to both the .NET Framework and VS 2008 - along with changes to SQL and other bits from across the company - so a download manager was created to download only what you need.

But if you want to put VS 2008 SP1 on your network or a DVD for later or continued use, you can pass /createlayout to the download bootstrap application. The /createlayout parameter requires an argument to specify the directory to download to.

VS90sp1-KB945140-ENU.exe /createlayout \\server\share

After a brief moment, the following dialog is displayed.

This will download all the packages for a single language of VS2008 SP1 and will put an executable named SPInstaller.exe into that same directory. You'll need about 782MB free for SP1 Beta. Run SPInstaller.exe to install the service pack from that install point. SPInstaller.exe will first use valid packages in the same containing folder before fetching them from the Internet.

There is a known issue that .NET Framework 3.5 SP1 requires an active connection when installing the layout. This is because only the web bootstrap application is downloaded. For VS2008 SP1 Beta, you can work around this by downloading the full redistributable and replacing dotnetfx35setup.exe in the layout folder where you saved the rest of the downloaded files. Note that the package you download will be dotnetfx35.exe, so you'll need to rename it to dotnetfx35setup.exe. Just selecting the existing dotnetfx35.exe file in the Save As dialog will do this automatically.

Changes for Microsoft Visual Studio 2008 Service Pack 1

Microsoft Visual Studio 2008 Service Pack 1 (Beta) has been released to web, along with Microsoft .NET Framework 3.5 Service Pack 1 (Beta). Included as part of .NET 3.5 SP1 are Microsoft .NET Framework 2.0 Service Pack 2 (Beta) and Microsoft .NET Framework 3.0 Service Pack 2 (Beta).

Visual Studio 2008 SP1 includes over 250 new features and improvements to existing features, including SQL Server 2008 support. .NET 3.5 SP1 also includes many new features on which VS 2008 SP1 is dependent. Because of this, VS 2008 SP1 chains .NET 3.5 SP1 and other necessary components as you can see from the partial list in the screenshot below.

Orcas SP1 Welcome Screenshot

This means the complete download for VS 2008 SP1 is large - almost twice as large as VS 2005 SP1. The full beta download is about 761 MB which contains the 229 MB full redistributable for .NET 3.5 SP1. However, because of changes we made for VS 2008 SP1 the patch installs in about half of the average time it took for VS 2005 SP1. In addition, we made some additional changes we're sure you'll like.

Smaller Individual Packages

Visual C++ libraries and headers comprised almost 70% of Visual Studio 2005 SP1 and because it was all in a single patch package, everyone had to download it. However, libraries and headers for x64 and IA64 are not installed by default and some customers may not install VC++ at all if they only focus on managed languages such as VB or C#. To save time space, three separate packages are produced for each of x86, x64, and IA64 which contain the libraries and headers for VC++. If you don't have all the VC++ features installed, only part of the overall patch release is downloaded. This does mean, however, that if you later install VC++ features you will need to reinstall SP1 again in order to download and apply the separate patches.

Also by reducing the size of the patch packages, many more customers will be able to install successfully without seeing another 1718 error message stating that the patch was rejected by digital signature policy.

Single Installation Experience

Even though Visual Studio 2008 SP1 includes multiple packages - and not just for Visual Studio - a single user interface using the typical wizard style provides download and installation progress as you see below.

Orcas SP1 Progress Screenshot

VS2005 SP1 only had a chainer to make sure the patch was correctly applied to each applicable and installed product, but did not implement an external UI handler that provided a consistent and uninterrupted user interface. As a result, some customers canceled dialogs under the assumption that VS2005 SP1 was simply installing again and their machines were not updated fully, sometimes leading to destabilization of Visual Studio 2005.

Friendly Logging

Windows Installer logs are difficult for many to read, so the new external UI chainer generates an HTML log file. Script is embedded in the HTML log to provide filtering mechanisms, but by default the error is displayed. Paths to the MSI logs are also provided in the HTML log to diagnose specific installation problems.

Express SP1 are Major Upgrades

Visual Studio Express products are intended to be downloaded quickly. But VS2005 Express SP1 customers had to download both Express RTM and the appropriate SP1 package that was about the same size resulting in a download and install time of almost twice as long. For VS2008 Express products, customers can simply download Express SP1 whether they have Express RTM installed or not. The product will be upgraded if present in roughly the same amount of time as it takes to install the product fresh. The big advantage for new customers is that they only need to download and install a single package.

Known Issues

For a complete list of known issues, please read the Visual Studio 2008 SP1 Beta Readme.

Silverlight 2 Tools Beta 1 Must be Uninstalled

Before VS2008 SP1 can be installed, Silverlight 2 Tools Beta 1 must be uninstalled. This includes both "Silverlight Tools Beta 1 for Visual Studio 2008" and KB949325. You do not need to remove the Silverlight 2 runtime.

Microsoft .NET Framework 3.5 SP1 Fails to Install

As part of the .NET 3.5 SP1, .NET 2.0 SP2 is installed. A problem occurs on some customers machines due to registry corruption or missing files that prevents 2.0 SP2 from installing which will fail 3.5 SP1. If you run into problems installing 3.5 SP1, please read through KB951950.

Your Machine must be Upgraded Completely

Because a large number of files are shared between products being upgraded, Service Pack 1 must be installed on every applicable product installed on your machine or none of them may work correctly. This means if you have Visual Studio and Express installed, you must download the appropriate updates for each and install them.

Upgrades Must be Uninstalled Individually

For reasons that I'll go into in a future post, we do not provide a uninstall chainer. That is, in order to uninstall SP1 and return your machine back to an RTM state, you must go through Add or Remove Programs and uninstall the service pack components individually. If you have both Visual Studio and Express installed, you may have to uninstall both Express SP1 and Visual Studio and reinstall both at the RTM level again.

Feedback

To provide feedback on the SP1 installation experience or changes to Visual Studio 2008 or Express made by SP1, please visit our forums.

Visual Studio and .NET Log Collection Utility

Setup and deployment is a tricky business. Machines can be in many different and often unforeseen states that cause setup to fail. But rarely will setup actually crash, and that is why setup logs are vital to diagnose install, repair, and uninstall problems.

Setup applications for Visual Studio and .NET may write to many different logs because the products are actually comprised of many different packages. Aaron Stebner had documented several log file names for Visual Studio 2008, but with our new and improved patch wrapper we may write even more log files. As we onboard new CTPs for great new features in Visual Studio the list of log files may also grow.

So our QA team has written a tool to collect all these logs for VS 2005 and 2008, and .NET 2.0 through 3.5 aptly named, collect.exe. The link below is an updated version of the old collect.exe that you should use when reporting bugs with setup.

Using the Collect Utility

If you encounter any setup issues, we will need all relevant logs. Please follow the instructions below to collect all those logs.

  1. Download collect.exe from the link  below.
  2. You may choose to save the tool for later use, or to run directly.
  3. The utility creates a compressed cabinet of all the VS and .NET logs to %TEMP%\vslogs.cab.

Reporting Setup Errors

There are several options for reporting setup errors, but you might consider first checking to see if the issue is a known issue. This will save you time and provide more immediate results. In most scenarios, there will be a link on the error page after setup completes. Clicking on this should provide a smaller log that highlights the errors encountered. To dig deeper, check out some of the tips provided on Aaron's blog and on my blog.

If you would like to report an error, be sure to collect logs as described above and choose from the options below.

  1. Search or post on MSDN Forums in .NET Framework Setup or Visual Studio Setup and Installation. This is a community-driven web site on which Microsoft employees also participate.
  2. Report installation issues or provide feedback for Visual Studio on Microsoft Connect. You may upload logs using Connect. This allows us to view and manage bugs, and customers to vote or provide additional details in a consistent manner.
  3. Upload logs using Windows Error Reporting. Both the MSDN Forums and Microsoft Connect will most often provide faster help.

MSIZap is not Uninstall

The tool msizap.exe that is available in the Windows SDK and elsewhere on the web (remember to always download from a trusted source) is a powerful but dangerous tool that is often used to quickly and casually, and can leave your machine in a corrupted state if not used correctly. The same is true for the Windows Installer CleanUp Utility which uses msizap.exe.

Windows Installer is a transactional, data-driven deployment technology used by most of the products deployed on Windows platforms today. At its core, it is a loose referential database that describes software applications and that information can be updated by changes, or transforms. That package may describe files, registry values, assemblies, and even custom data that is acted upon by the engine by first generating a script and then executing it. One of the final typical actions of this script is to register product and patch information so that it is cataloged and can be queried; and so that Windows Installer itself can perform future maintenance installations which includes updates and uninstalls.

Updates are supported by actions that first remove older data and then install the newer data. An uninstall essentially skips the install actions. That means, then, that files, registry values, assemblies, and custom data is simply removed.

With that in mind, msizap.exe merely removes the product registration information from the registry and optionally files in the Windows Installer cache - a critical set of files that is necessary for future maintenance installations including proper uninstalls. Removing files from your Windows Installer cache can cause products like the Microsoft .NET Framework 2.0 Service Pack 1 to fail to upgrade older versions.

Msizap.exe is not magic, but merely a tool that acts only on Windows Installer registration data. It will not run the removal actions. So, for example, if you zapped the entire .NET 2.0 RTM products instead of just certain patches, actions that unregister WMI providers incompatible with .NET 2.0 SP1 would not run and, therefore, would not remove the WMI provider registration. In addition, files and other registry data is not removed so the .NET Framework is not truly removed from the system. Msizap.exe is no more of an uninstaller than simply forgetting that a program is installed, which is all it basically causes the Windows Installer engine to do.

Msizap.exe is an effective tool when product registration is already corrupt for whatever reason; however, it should only be used as an absolute last resort. Always try to uninstall a product first through the Add/Remove Programs control panel or the Software Explorer for newer Windows platforms like Vista. If you cannot see the product listed in the control panel, see if there is an "Uninstall" icon or similar in your Start menu for that program group. If you don't see such an item, search the web for what other people have done to uninstall a product. For Windows Installer products, by knowing certain data you can always uninstall from the command line using msiexec.exe. To help diagnose issues properly, always generate a log by passing /L*vx uninstall.log to the command line to msiexec.exe. In this log will almost always be the answer to determine what is wrong so that a product can be properly uninstalled.

For help uninstalling a product when errors are encountered, Aaron Stebner's and my blog can be helpful most often for Visual Studio and .NET installation problems. At times, they may even help in general since problems like registration or cache corruption can happen to any product - especially if msizap.exe was already used improperly. You can also search for error strings you find in the Windows Installer log files which are most often right after the string "Return value 3". The error message number like 1714 you will see is more helpful than a return code at the end of a log like 1603 (0x643).

Microsoft .NET Framework 2.0 Service Pack 1 Fails to Install

A lot of customers have recently started seeing the following errors, all stating in various ways that Microsoft .NET Framework 2.0 Service Pack 1 failed to install. You may also see this when attempting to install other updates on top of .NET 2.0 SP1. The error you will see depends on how you are applying updates.

If you are installing .NET 2.0 SP1 or other updates on top of .NET 2.0 RTM by installing the package directly, you may see the following dialog.

 

 

If you click on the Error Log hyperlink, the error log simply states the following.

[04/17/08,17:08:27] Microsoft .NET Framework 2.0a: [2] Error: Installation failed for component Microsoft .NET Framework 2.0a. MSI returned error code 1603

If you are attempting to install updates using Windows Update or Microsoft Update, you may see a dialog similar to the following.

 

 

If you view the history of the updates you've applied and click on the error icon, the following dialog denotes the same generic error.

 

 

To determine the root cause, you need to look in your %TEMP% directory for a file named dd_NET_Framework20_Setup*.txt, where * will be 4 random alphanumeric characters. Find the most recent log if there are multiple logs by sorting by Date Modified.

The problem described here can be found by searching for "Resolving Patch source" in the log file.

How to workaround this issue

If you found the text "Resolving Patch source" in the log file described in the problem description above, you can download the Microsoft .NET Framework 2.0 Registration Correction Tool attached as clwireg.zip and extract the contents. There are three directories corresponding to different computer architectures. Most customers will need to open x86ret and run clwireg.exe. You need to be an administrator to run this utility, and it is only to repair this issue with Microsoft .NET Framework 2.0.

Administrators may also use this utility in scripts by passing either /q or /quiet and it will not display any user interface and will, therefore, not block scripts.

In either case, this tool keeps a running log in %TEMP%\dd_clwireg.txt in which you can read more information about what it has done.

Description of the issue

The specific failure detailed here is caused by corrupted patch registration or a missing patch package.

When Windows Installer performs any maintenance installation - that is any installation after the initial installation, including repairs, patch install and uninstall, and uninstall of the product - it must load the cached installation database and all applicable patches. If those packages are not found in the Windows Installer cache, then Windows Installer attempts to find them previous source directories. Failing to find them, Windows Installer fails the installation with error message 1714, which reads,

Error 1714.The older version of Microsoft .NET Framework 2.0 Service Pack 1 cannot be removed.  Contact your technical support group.  System Error 1612.

System error 1612 is a Windows error code, which identifies the message,

The installation source for this product is not available. Verify that the source exists and that you can access it.

Because .NET 2.0 SP1 is a major upgrade which uninstalls previous versions of .NET 2.0, toward the end of the installation it attempts the uninstall of .NET 2.0 which is a maintenance installation. Because a patch package could not be found, the uninstall attempt fails which causes .NET 2.0 SP1 to rollback and report failure. This may also cause .NET applications to err because of an incomplete rollback.

This problem likely occurs for one of the following two reasons.

The Installer cache is missing the necessary files

The Windows Installer cache located in %WINDIR%\Installer is critical for repairing, updating, and even uninstalling products. It must not be removed, nor any files in it. It is safe - though not advised - to only remove %WINDIR%\Installer\$PatchCache$ or subdirectories if space is critical. This may lead to prompts for source for any products, however, when you attempt to repair or update them.

If this is the case, the line above where you found "Resolving Patch source" would read something similar to the following.

MSI (s) (D0:B0) [19:05:57:843]: Couldn't find local patch 'C:\WINDOWS\Installer\50bad.msp'. Looking for it at its source.
MSI (s) (D0:B0) [19:05:57:843]: Resolving Patch source.

The attached tool attempts to fix this by deleting all patch registration specific to this patch so that future maintenance installations do not attempt to load the patch package.

You may also attempt to fix this by rebuilding the installer cache. You will most often find the KB# for the patch in the lines that follow "Resolving Patch Source", as shown in the following example.

MSI (s) (D0:B0) [19:05:57:859]: SOURCEMGMT: Source is invalid due to missing/inaccessible package.
MSI (s) (D0:B0) [19:05:57:859]: Note: 1: 1706 2: -2147483647 3: NDP20-KB917283-X86.msp

Browse to http://support.microsoft.com and search for the KB# to download the patch again. You can extract the patch using /x or /extract and then following the instructions on rebuilding the installer cache.

Patch registration is corrupt

While we have not yet determined the cause, patch registration may have become corrupted. If this is the case, the line above where you found "Resolving Patch source" would read something similar to the following.

MSI (s) (CC:5C) [03:02:56:181]: Couldn't find local patch ''. Looking for it at its source.
MSI (s) (CC:5C) [03:02:56:181]: Resolving Patch source.

Notice that the location of the patch is missing. In this particular case, a patch is still registered to a product but location information for the patch is missing. The file may or may not exist, but Windows Installer wouldn't even know the path to the file to load.

The attached tool attempts to fix this by deleting all patch registration for this patch so that future maintenance installations do not attempt to load the patch package.

How to prevent this issue

It is critical that you do not remove files located directly in %WINDIR%\Installer, and that you are careful using any disk space reclamation utilities that free up space by deleting large or seldom used files so that you do not allow them to remove these same files. If you have used such a utility that did this, please leave a comment with information about that tool and we'll work with developers to try to mitigate this problem in the future.

The Windows Installer CleanUp Utility which uses msizap.exe (also shipped with the Windows SDK) is capable of deleting some or all files in the Installer cache but should be used only as a last resort and after carefully reading all information and warnings about the tool. It is always best to uninstall a product or patch correctly using Windows Installer either through Add/Remove Programs on Windows 2000, XP, or Server 2003; Software Explorer on Vista and newer; or using msiexec.exe on the command line if the product does not provide its own uninstaller.

Updated: the issue and workaround have been adapted for KB951950 and I have updated the attachment to refer to the Microsoft Download Center location.

Functional Testing of Cmdlets

While developing unit and functional tests for Windows Installer PowerShell Extensions, I needed a way to invoke cmdlets without requiring elevation on Vista. That is, of course, because running elevated has always been a bad idea unless it is required. In order to load a PowerShell snap-in, however, one must write to HKEY_LOCAL_MACHINE which requires elevated privileges. Other than that, there really isn't another reason to run elevated.

Fortunately, PowerShell allows developers to define a RunspaceConfiguration object which, among other properties, allows developers to add specific types as cmdlets. Without being defined by a registered snap-in, cmdlets can then be invoked in a Runspace as shown below in a sample Visual Studio test class.

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.Windows.Installer.PowerShell.Commands;
using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class GetFileHashCommandTest
{
    private RunspaceConfiguration config;

    [TestInitialize]
    public void Initialize()
    {
        config = RunspaceConfiguration.Create();
        config.Cmdlets.Append(new CmdletConfigurationEntry(
            "Get-MSIFileHash",
            typeof(GetFileHashCommand),
            "Microsoft.Windows.Installer.PowerShell.dll-Help.xml"));
    }

    [TestMethod]
    [DeploymentItem(@"data\example.txt")]
    public void PathTest()
    {
        using (Runspace rs = RunspaceFactory.CreateRunspace(config))
        {
            rs.Open();
            using (Pipeline p = rs.CreatePipeline(@"get-msifilehash -path example.txt"))
            {
                Collection<PSObject> objs = p.Invoke();
                Assert.AreEqual<int>(1, objs.Count);
            }
        }
    }
}

When it is time to install and register your PowerShell snap-in, I recommend you take a look at the WiX PowerShell extension to avoid using managed custom actions which can also cause problems.

Windows Installer 4.5 Beta 2 Available

The Windows Installer team released Windows Installer 4.5 Beta 2 recently. While not a lot has visibly changed since the first beta for which I provided an overview, it's important to note that a new column was added to the CustomAction table since changes to column types are not supported in a transform or patch but adding a new column is supported.

The ExtendedType column is defined as a nullable DoubleInteger, or I4 using IDT format codes. Currently the only supported value is the new msidbCustomActionTypePatchUninstall (0x8000) that denotes a patch uninstall custom action, which is the feature to deploy a custom action in a patch that will execute when that patch is uninstalled. This was previously impossible without hooks in a baseline product because a patch is uninstalled by removing the patch from the aggregate view of the product and all applicable updates, and then repairing the product.

For more information and to sign up for the Windows Installer 4.5 pre-release program, visit Windows Installer 4.5 on Microsoft Connect.

Group by Different Properties for Format-Table

For my Windows Installer PowerShell Extensions, I've been simplifying some of the use cases and adding additional formats. One thing I wanted to do was display source list information in a table and group either by the attached ProductCode or PatchCode properties. The format-table cmdlet doesn't support multiple properties and doesn't appear to allow you to condition the label. It also seemed that Display.xml, or *.formats.ps1xml files, didn't natively support grouping by multiple property names.

The help topic about_Display.xml hinted at a CustomControl tag, but examples of this and related tags in the default *.formats.ps1xml files offered little insight about their true power. With some help from a simple user-generated XML schema and some trial and error, I was able to display a label with an appropriate value conditionally, such that the following expressions displayed the partial table shown below.

PS> $packages = get-msiproductinfo | ?{ $_.Name -match "Visual Studio" }
PS> $packages += get-msipatchinfo
PS> $packages | get-msisource | format-table -view package

    ProductCode: {388E4B09-3E71-4649-8921-F44A3A2954A7}

Index Type    Path
----- ----    ----
    0 Network m:\c0367ae0d89851da1a\
    1 Network C:\Program Files\Common Files\Microsoft Shared\VSTO\8.0\Micros...
    2 Network m:\3d218a0f32f61beaf41a01459217\

    PatchCode: {6E52C409-0D0D-4B84-AB63-463438D4D33B}

Index Type    Path
----- ----    ----
    0 Network m:\ec91ccc92c8f730e8d87188036\

I accomplished this by using a scriptblock to group, but referencing a CustomControl with multiple ExpressionBinding elements as shown in the partial example below.

<Configuration>
  <Controls>
    <Control>
      <Name>PatchOrProductGrouping</Name>
      <CustomControl>
        <CustomEntries>
          <CustomEntry>
            <CustomItem>
              <Frame>
                <LeftIndent>4</LeftIndent>
                <CustomItem>
                  <ExpressionBinding>
                    <ItemSelectionCondition>
                      <ScriptBlock><![CDATA[$_.ProductCode -ne $null]]></ScriptBlock>
                    </ItemSelectionCondition>
                    <ScriptBlock><![CDATA["ProductCode: " + $_.ProductCode]]></ScriptBlock>
                  </ExpressionBinding>
                  <ExpressionBinding>
                    <ItemSelectionCondition>
                      <ScriptBlock><![CDATA[$_.PatchCode -ne $null]]></ScriptBlock>
                    </ItemSelectionCondition>
                    <ScriptBlock><![CDATA["PatchCode: " + $_.PatchCode]]></ScriptBlock>
                  </ExpressionBinding>
                  <NewLine/>
                </CustomItem>
              </Frame>
            </CustomItem>
          </CustomEntry>
        </CustomEntries>
      </CustomControl>
    </Control>
  </Controls>
  <ViewDefinitions>
    <View>
      <Name>Package</Name>
      <ViewSelectedBy>
        <TypeName>Microsoft.Windows.Installer.PackageSource</TypeName>
      </ViewSelectedBy>
      <GroupBy>
        <ScriptBlock><![CDATA[
          if ($_.ProductCode -ne $null)
          {
            $_.ProductCode
          }
          elseif ($_.PatchCode -ne $null)
          {
            $_.PatchCode
          }
        ]]></ScriptBlock>
        <CustomControlName>PatchOrProductGrouping</CustomControlName>
      </GroupBy>
      <TableControl>
        <!-- Omitted for brevity -->
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>
Hopefully this serves as a good example of more powerful features of formatting in PowerShell.
Posted by Heath Stewart | 1 Comments
Filed under:

Installing Silverlight 2 Beta 1 Tools for Visual Studio 2008

While attempting to install Microsoft Silverlight Tools Beta 1 for Visual Studio 2008, you may get a prompt for source that looks like the following screenshot.

Insert the 'Microsoft Visual Studio Team System 2008 Team Suite - ENU' disk and click OK.

This problem commonly occurs if you have not installed one or more of the features Visual Basic, Visual C++, or Visual C# when installing Visual Studio 2008 (VS2008).

If you have your VS2008 installation media handy, insert it into your DVD drive, click the Browse button shown above, and navigate to vs_setup.msi in the root of your DVD drive.

How to work around this issue

If you do not have your VS2008 installation media handy, you can work around this issue by extracting the patch and installing it directly.

  1. Open a command shell like cmd.exe. If running on Windows Vista or newer, open an elevated command shell.
  2. Change directories to where you have saved Silverlight 2 Beta 1 Tools for Visual Studio 2008.
  3. Run the following command to extract the contents of the download to a sub-directory:
    silverlight_chainer.exe /extract:"%CD%\SL2"
  4. Change directories to the new sub-directory:
    cd SL2
  5. Install the patch once to add the new features to VS 2008:
    msiexec /p VS90-KB949325.msp /L*vx VS90-KB949325.log REINSTALL=ALL
  6. To list these Silverlight tools in Visual Studio's Help->About dialog and to be able to uninstall these tools from Add/Remove Programs (ARP), install the patch again using the following command:
    msiexec /p VS90-KB949325.msp /L*vx VS90-KB949325-2.log ADDLOCAL=KB947520,KB949325

Description of the Issue

This issue is caused by a new component being added to an existing feature. If you don't have that feature installed, it and all its parent features are installed automatically when installing the patch. This is the problem I described previously, but you can work around this issue if you don't have source media available using an alternative method.

To completely install the patch, two commands are necessary because the REINSTALL property takes precedence over the ADDLOCAL property, and those two features that should be added will not be added the first time. By installing the patch a second time specifying only ADDLOCAL, the conditions evaluate correctly and the patch registration is updated. This last step isn't necessary, but is recommended so that you can see the patch is installed later and so that you can copy complete information from the Help->About dialog for a support call.

You can find more installation tips for Silverlight Tools Beta 1 in Bradley's blog post.

Another Workaround to Add New Components to Existing Features

Yesterday I described an issue when adding new components to existing, not-installed (absent) features the feature tree is installed. This can lead to prompts for source or failed installations.

One workaround is to add new, top-level hidden features. This works well unless new resources have a dependency on the older resources installed by the would-be feature tree - the feature tree where the new components should've been parented.

Another workaround is to reinstall everything by setting REINSTALL=ALL. Setting any of the feature, component, or file selection properties listed below bypasses Windows Installer's functionality that automatically determines what to install or reinstall (available in Windows Installer 2.0 and newer).

While this prevents the issue described above when adding new components to existing, absent feature, the problem is that if you do add new features in your patches, you'll need to manage ADDLOCAL yourself as well.Workaround2 in the attached example WiX projects sets REINSTALL and also adds a new feature, but you can see from the feature state in the log that the feature "Workaround" is not installed.

MSI (s) (F8:B0) [15:16:04:886]: Feature: NotInstalled; Installed: Absent;   Request: Null;   Action: Null
MSI (s) (F8:B0) [15:16:04:886]: Feature: Example; Installed: Local;   Request: Reinstall;   Action: Reinstall
MSI (s) (F8:B0) [15:16:04:886]: Feature: Servicing; Installed: Local;   Request: Reinstall;   Action: Reinstall
MSI (s) (F8:B0) [15:16:04:886]: Feature: Workaround; Installed: Absent;   Request: Null;   Action: Null

Managing properties like ADDLOCAL with custom actions can be very tricky. If you add a feature or features to ADDLOCAL and any of these features are parented to existing, absent features, that feature tree is still installed; and a prompt for source or installation failure will still happen. If you create custom actions as shown in the WiX example below that are conditioned on parent feature states, those custom actions must be scheduled after CostFinalize but then it is practically too late to change feature state without re-costing by calling CostFinalize again. This potentially causes the same problem as when using type 35 custom actions carelessly.

<CustomAction Id="SetADDLOCAL_Workaround" Property="ADDLOCAL" Value="{[ADDLOCAL];}Workaround"/>

If you are not adding features in a patch, you may be fine setting REINSTALL=ALL. Note that this does incur a performance penalty to re-cost every feature and can potentially end up repairing a feature with a missing file that you're not patching, which in turn may lead to a prompt for source or installation failure. For products with few features this workaround should be appropriate.

Posted by Heath Stewart | 2 Comments
Filed under: , ,

Attachment(s): Example.zip

Adding New Components to Existing Features Installs the Feature Tree

As Developer Division starts to ship patches for the Visual Studio 2008, some users are being prompted for installation source media. This is a resulting of Windows Installer needing the original source files if, for example, files are missing from disk when you repair your product or backup files are not available during patch install.

If you are prompted for source media during install or uninstall, put in your source media disk or browse to the local or network path that contains the original source media like vs_setup.msi. Some of our products do not actually contain loose source .msi files like vstor30.exe under WCU\VS Tools for Office found on your VS2008 DVD. If you're being prompted for source for a product such as this, in most cases you can pass /extract to the .exe to extract the sources.

This most recent issue we're seeing occurs when people are adding new components to install new files or other resources. Though adding new components to an existing feature is allowed when installing with Windows Installer 2.0 and newer, this causes the components' parent features to be installed. This in turn forces those features' parent features to be installed, and so on up the feature tree. Any child features that follow their parents' install actions also get installed. If any components in any of these features install files, then Windows Installer needs the source media to install those files to disk.

If you're an installation developer and are running into this problem when adding components to a feature in a patch package, you can workaround this issue by adding new components to new top-level features. You can see an example of this approach written for WiX in the attached sample in the Workaround folder.

Because there are different reasons you might be prompted for source, you can identify this issue as the cause of the prompt by comparing what the command line to install the patch is, what the ADDLOCAL property is set to, and what features are being transitioned from the Absent to the Local state. Notice in the log below that ADDLOCAL gets set to NotInstalled, and the NotInstalled feature is transitioning from Absent to Local.

MSI (s) (BC:90) [19:34:31:704]: Command Line: PATCH=C:\Users\heaths\Documents\Visual Studio 2005\Projects\Adding Components\Patch_Introduced.msp CURRENTDIRECTORY=C:\Users\heaths\Documents\Visual Studio 2005\Projects\Adding Components CLIENTUILEVEL=2 CLIENTPROCESSID=5172

MSI (s) (BC:90) [19:34:32:059]: PROPERTY CHANGE: Adding REINSTALL property. Its value is 'Example'.
MSI (s) (BC:90) [19:34:32:059]: PROPERTY CHANGE: Adding ADDLOCAL property. Its value is 'NotInstalled'.
MSI (s) (BC:90) [19:34:32:059]: PROPERTY CHANGE: Adding INSTALLLEVEL property. Its value is '1'.

MSI (s) (BC:90) [19:34:32:070]: Feature: NotInstalled; Installed: Absent; Request: Local; Action: Local
MSI (s) (BC:90) [19:34:32:070]: Feature: Example; Installed: Local; Request: Reinstall; Action: Reinstall

MSI (s) (BC:90) [19:34:35:056]: Resolving source.

NotInstalled is explicitly referenced in ADDLOCAL, though it wasn't specified on the command line. Since NotInstalled is getting installed and does contain files, source is required to find the files within that feature to be copied.

If we use the workaround of adding a new top-level feature, NotInstalled is only updated if it was already installed locally and the new feature - "Workaround" in the attached example - is added.

MSI (s) (BC:8C) [19:39:46:866]: PROPERTY CHANGE: Adding REINSTALL property. Its value is 'Example'.
MSI (s) (BC:8C) [19:39:46:866]: PROPERTY CHANGE: Adding ADDLOCAL property. Its value is 'Workaround'.
MSI (s) (BC:8C) [19:39:46:866]: PROPERTY CHANGE: Adding INSTALLLEVEL property. Its value is '1'.

MSI (s) (BC:8C) [19:39:46:880]: Feature: NotInstalled; Installed: Absent; Request: Null; Action: Null
MSI (s) (BC:8C) [19:39:46:880]: Feature: Example; Installed: Local; Request: Reinstall; Action: Reinstall
MSI (s) (BC:8C) [19:39:46:880]: Feature: Workaround; Installed: Absent; Request: Local; Action: Local

This new feature contains only new components with all the required file resources in a cabinet embedded in the patch so that they are always available, even during future maintenance installs since patches are cached in whole.

Posted by Heath Stewart | 5 Comments
Attachment(s): Example.zip

Debugging Custom Actions: Leaked Handles

Debugging custom actions isn't exactly the easiest action to do; Windows Installer spawns separate processes - remoting servers - to run in-process custom actions. Any opportunity to diagnose issues without debugging can be helpful.

For example, an issue that comes up from time to time is leaked handles. A Windows Installer debug log might show something similar to the following:

MSI (s) (CC:1C) [17:40:29:055]: Doing action: MyCustomAction
MSI (s) (CC:58) [17:40:29:165]: Invoking remote custom action. DLL: C:\WINDOWS\Installer\MSI1B.tmp, Entrypoint: MyCustomAction
Action start 17:40:29: MyCustomAction.
MSI (s) (CC:58) [17:40:29:906]: Leaked MSIHANDLE (219) of type 790531 for thread 3676
MSI (s) (CC:58) [17:40:29:906]: Leaked MSIHANDLE (190) of type 790540 for thread 3676
MSI (s) (CC:58) [17:40:29:906]: Leaked MSIHANDLE (189) of type 790540 for thread 3676
MSI (s) (CC:58) [17:40:29:906]: Leaked MSIHANDLE (188) of type 790540 for thread 3676
MSI (s) (CC:58) [17:40:29:906]: Leaked MSIHANDLE (179) of type 790541 for thread 3676
MSI (s) (CC:58) [17:40:29:906]: Note: 1: 2769 2: MyCustomAction 3: 5
DEBUG: Error 2769: Custom Action MyCustomAction did not close 5
Action ended 17:40:30: MyCustomAction. Return value 3.

Windows Installer provides a clue in the log that can help with a code review. The Windows Installer team has provided the following information:

  • MSIHANDLE type 790531 identifies a record
  • MSIHANDLE type 790540 identifies a view
  • MSIHANDLE type 790541 identifies a database

With this knowledge, you should be able to review your code and spot cause of the issue.

Get Binder Variables for Assemblies without Installing into the GAC

Binder variables in WiX are variables that are resolved, coincidentally, at bind time. This is when the linker, light.exe, collects file information, assigns auto-GUIDs, and generates the output packages among other things. There are binder variables for all versioned binaries, and binder variables specific to both managed and native assemblies or exclusive to one or the other.

The format for using binder variables follows a similar patter to preprocessor variables - variables resolved before compile time - but use a different prefix as shown below.

!(bind.VariableName.FileId)

Managed assemblies will cause the generation of the following list of binder variables, but only if you set the File/@Assembly attribute to ".net". By default, however, this will cause Windows Installer to install your assembly into the Global Assembly Cache (GAC).

Example usage Example value
!(bind.assemblyCulture.MyAssembly) neutral
!(bind.assemblyFileVersion.MyAssembly) 1.0.0.0
!(bind.assemblyFullName.MyAssembly) MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0123456789abcdef, ProcessorArchitecture=MSIL
!(bind.assemblyName.MyAssembly) MyAssembly
!(bind.assemblyProcessorArchitecture.MyAssembly) MSIL
!(bind.assemblyPublicKeyToken.MyAssembly) 0123456789abcdef

Because WixPSExtension.dll automatically uses a binder variable to get the assembly name for more easily managed builds, you have to set the File/@Assembly attribute to ".net". I originally wrote this extension for installing PowerShell snap-ins - as opposed to using a managed custom action as recommended in the PowerShell developer guide which does nothing more than write registry values - so I figured it was time for me to use it for my own Windows Installer PowerShell Extension but I didn't want this assembly in the GAC.

Peter Marcu recommended I set the File/@AssemblyApplication attribute to the File/@Id for the same file as a workaround. I had considered that previously, but it seemed too odd to work. It turns out, however, this approach does work and in hindsight makes sense. Because the component key path will still resolve to the path as laid out by the Directory table and any type 35 and type 51 custom actions, that component directory is where a private assembly would be installed. The binder still collects all the assembly information about the file, but you can use the file itself to install the assembly as a private assembly.

So, to get binder variables for assemblies without installing into the GAC set File/@Assembly to ".net" or "win32", then for the same file set File/@AssemblyApplication to the value for File/@Id.

Posted by Heath Stewart | 0 Comments

Different Packages are Required for Different Processor Architectures

A common question is how to create a Windows Installer package that installs 32-bit binaries on 32-bit platforms, and both 32- and 64-bit binaries on 64-bit platforms. If you're actually trying to install 64-bit binaries to appropriate directories and write to the 64-bit view of the registry, the short answer is that you can't build a single package.

Before delving into the details, let me clarify that both 32- and 64-bit binaries can be installed to either ProgramFilesFolder or ProgramFiles64Folder, but may not load correctly into a 64- or 32-bit process, respectively. The Windows Installer SDK, for example, installs all of x86, IA64, and x64 binaries under ProgramFilesFolder for link time support.

But when you need to install files correctly, multiple packages are required because not all 64-bit features are lit up if the package isn't marked as a 64-bit package. That is, the Template summary property must distinctly list Intel for x86, Intel64 for IA64, and x64 for x64 platforms (AMD64 is supported for backward compatibility). The Template summary property documentation clearly states that only a single platform can be specified.

A Windows Installer package cannot be marked as supporting both Intel64 and x64; for example, the Template Summary property value of Intel64,x64 is invalid.

A Windows Installer package cannot be marked as supporting both 32-bit and 64-bit platforms; for example, Template Summary property values such as Intel,x64 or Intel,Intel64 are invalid.

Attempting to install a 64-bit package on a 32-bit platform results in Windows error 1633. Assuming no other errors, installing a 32-bit package on a 64-bit platform appears to work but components may not actually be installed correctly. Files in components to be installed under ProgramFiles64Folder, for example, wind up in ProgramFilesFolder.

If we examine a log from a 32-bit package with 64-bit components defined that is installed on an x64 platform, we can see that directories like ProgramFiles64Folder are initially defined correctly but are redirected back to the 32-bit equivalent directory.

MSI (s) (B4:20) [16:59:17:976]: WIN64DUALFOLDERS: 'C:\Program Files (x86)\' will substitute 17 characters in 'C:\Program Files\' folder path. (mask argument = 0, the folder pair's iSwapAttrib member = 0).
MSI (s) (B4:20) [16:59:17:976]: PROPERTY CHANGE: Modifying ProgramFiles64Folder property. Its current value is 'C:\Program Files\'. Its new value: 'C:\Program Files (x86)\'.

But when writing registry values, you can see by the BinaryType parameter that Windows Installer knows the difference and Windows Installer will write to the correct 32- or 64-bit view of the registry. You can confirm this using a tool like regedit.exe.

MSI (s) (B4:20) [16:59:18:445]: Executing op: RegOpenKey(Root=-2147483646,Key=Software\Heath Stewart\Example,,BinaryType=0)
MSI (s) (B4:20) [16:59:18:445]: Executing op: RegAddValue(,Value=32-bit Example,)
MSI (s) (B4:20) [16:59:18:445]: Executing op: RegAddValue(Name=Example,Value=32-bit Registry Example,)
MSI (s) (B4:20) [16:59:18:445]: Executing op: RegOpenKey(Root=-2147483646,Key=Software\Heath Stewart\Example,,BinaryType=1)
MSI (s) (B4:20) [16:59:18:445]: Executing op: RegAddValue(,Value=64-bit Example,)
MSI (s) (B4:20) [16:59:18:445]: Executing op: RegAddValue(Name=Example,Value=64-bit Registry Example,)

You can't simply condition components using standard properties like VersionNT64. Even when installing a package marked as Intel on a 64-bit machine, properties like VersionNT64, Msix64, and Intel64 are still defined.

Essentially, most features are lit-up depending on the machine type except for where files are installed. Even 64-bit custom actions will run in a 64-bit custom action server despite how the package is attributed as shown in the log snippet below. For binary custom actions, the bitness of the binary will dictate whether a 32- or 64-bit custom action server is created. For script custom actions, the custom action must be attributed with msidbCustomActionType64BitScript (0x1000); of course, you shouldn't use script custom actions anyway.

MSI (s) (74:14) [11:04:43:203]: Executing op: CustomActionSchedule(Action=CA_OutputString32,ActionType=1025,Source=BinaryData,Target=OutputString,)
MSI (s) (74:14) [11:04:43:203]: Creating MSIHANDLE (1) of type 790536 for thread 3604
MSI (s) (74:44) [11:04:43:203]: Invoking remote custom action. DLL: C:\WINDOWS\Installer\MSI243.tmp, Entrypoint: OutputString
MSI (s) (74:2C) [11:04:43:203]: Generating random cookie.
MSI (s) (74:2C) [11:04:43:219]: Created Custom Action Server with PID 2260 (0x8D4).
MSI (s) (74:64) [11:04:43:250]: Running as a service.
MSI (s) (74:64) [11:04:43:250]: Hello, I'm your 32bit Impersonated custom action server.

MSI (s) (74:14) [11:04:43:250]: Executing op: CustomActionSchedule(Action=CA_OutputString64,ActionType=1025,Source=BinaryData,Target=OutputString,)
MSI (s) (74:14) [11:04:43:250]: Creating MSIHANDLE (3) of type 790536 for thread 3604
MSI (s) (74:8C) [11:04:43:266]: Invoking remote custom action. DLL: C:\WINDOWS\Installer\MSI244.tmp, Entrypoint: OutputString
MSI (s) (74:2C) [11:04:43:266]: Generating random cookie.
MSI (s) (74:2C) [11:04:43:266]: Created Custom Action Server with PID 3480 (0xD98).
MSI (s) (74:08) [11:04:43:282]: Running as a service.
MSI (s) (74:64) [11:04:43:282]: Hello, I'm your 64bit Impersonated custom action server.

This is predicated on whether or not you're invoking embedded binaries or installed binaries. Since your installed binaries in a 32-bit package will install to the 32-bit location even on a 64-bit machine, whichever file was installed last - taking into account default file versioning - would dictate the bitness of the custom action server.

If the goal is to decrease the payload, you can still create separate packages but define your media entries so that 32- and 64-bit payloads (each of IA64 and x64 if you'll be installing either) are in separate cabinets. Read more about file sequences and media entries. You can then put all the .msi packages in the same directory and put all of the cabinets in that directory as well. This is actually how the .NET Framework 2.0 SP1 and 3.0 SP1 packages are laid out. Cabinets can be shared between packages for common files, rather than having distinct sets for each supported platform.

More Posts Next page »
 
Page view tracker