Category Archives: MSI

IS 2009 Bug – Patch Optimization & Custom CAB Names Mutually Exclusive

I realize this is a very unique scenario, but I thought I would post it in case you find yourself in this scenario. The bug only applies if you use InstallShield 2009 to build a ‘Basic MSI’ installation and you use ALL of the build options specified below:

  • You specify custom CAB names (by editing the ISFeatureCabName column of the custom InstallShield Feature table).
  • You specify the “One .cab per Feature” option on the Custom Compression Settings dialog of the Release Wizard.
  • You sync file IDs with a previous build using the “Previous package” option on the Advanced Settings dialog of the Release Wizard.

If you do build under the scenario described above, then you should be aware that the options appear to be mutually exclusive and the custom CAB names you specified will NOT be generated correctly by InstallShield at build time.

Below is a description of the problem I reported to Acresso support yesterday (incident #SIOA-000140045):

I have a serious problem with the IsCmdBld.exe in InstallShield 2009 Premier that I need a fix for ASAP.

We are in the process of upgrading our build environment to use IS 2009 to build our primary application installation and are seeing different behavior during the build between the IsSABld.exe we used with previous versions of IS (both IS 12 Premier and IS 2008 Premier) and the behavior seen using IsCmdBld.exe in IS 2009 Premier.

Our primary application installation is a very complex and large MSI installation. Since we must control the names of the CAB files we generate at build time, we use the InstallShield Direct Editor to modify the Feature table in the InstallShield source project and specify a different CAB name for each defined feature (using the ISFeatureCabName field). Using the Release Wizard, we also set the Release Configuration to ‘Custom’ and select the “One .cab per Feature” option (“Custom Compression Settings” dialog of the Release Wizard). In addition, we specify the fully qualified path and name of a previous MSI package build (by setting the “Previous package” option on the “Advanced Settings” dialog of the Release Wizard. The only other configuration information that may be relevant to this issue is the fact that we have multiple merge modules in the project and each defined feature has one or more merge modules associated with it (no merge module is associated with more than one feature).

When we build the installation (with NO CHANGES other than upgrading the project to IS 2009 schema format) using the IsCmdBld.exe command line utility from IS 2009 the CAB files are not generated correctly. In other words, the files associated with feature A are not being placed into the CAB file specified in the ISFeatureCabName for feature A. However, if I remove the option to point the build to a previous package and then build the project then the CAB files are generated correctly (the files associated with feature A are being correctly placed into the CAB file specified in the ISFeatureCabName for feature A.

In other words, the options to specify the CAB file name for each feature (ISFeatureCabName column of the Feature table) and the Release Wizard option for Patch optimization (“Previous package” option) ARE MUTUALLY EXCLUSIVE IN IS 2009.

I have confirmed this behavior by building under the different scenarios described below:

  • Build A: IS 12 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path specified, and IsSABld.exe used to build the project.
  • Build B: IS 12 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path NOT specified, and IsSABld.exe used to build the project.
  • Build C: IS 2008 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path specified, and IsSABld.exe used to build the project.
  • Build D: IS 2008 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path NOT specified, and IsSABld.exe used to build the project.
  • Build E: IS 2009 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path specified, and IsCmdBld.exe used to build the project.
  • Build F: IS 2009 project file, one .cab per feature enabled, custom CAB names specified in Feature table, previous package path NOT specified, and IsCmdBld.exe used to build the project.

In all scenarios specified above EXCEPT “Build E”, the CAB files are correctly generated during the build. In other words, in each of the scenarios EXCEPT “Build E”, the files associated with feature A are correctly placed into the CAB file whose name is specified in the ISFeatureCabName column of the Feature table.It is absolutely critical that this be fixed or we cannot use IS 2009 without completely redesigning our MSI installation packaging.

Multiple Language Resource Files – Quick & Dirty

Chris recently forwarded me a message from a reader asking for help installing language resource files via MSI and InstallShield. My response ended up being a lot more involved than I had originally planned so I thought I would blog about the topic.

First, a couple of notes:

  1. The information below is probably the easiest method for a few resource files with different names only. That does not mean it is a best practice. In fact, it isn’t a best practice – if you have a lot of resource files or all the resource files have the same name, then you’ll want to review MSDN topic Localizing a Windows Installer Package and the available Localization Example and author the MSI accordingly (to NOT use component conditions to control what files get installed).
  2. If you’re using merge modules, you should review the MSDN topic Authoring Multiple Language Merge Modules AND review the InstallShield topics (because IS doesn’t support authoring multi-language merge modules so if you need to exclude languages at MSI build time then you would need to create a different module for each language).
  3. If your MSI package has UI text streams that are localized, make sure the default code page property is set appropriately, that InstallShield is set up to generate multiple language transforms (1033.mst, 1036.mst, etc.) for each language you will support, and that the database summary information stream properties for the Template Summary and Codepage Summary are set correctly.

If you do need to only install one resource file depending on the OS language, then you need to add each resource file to the merge module as a separate component and then use a component condition to evaluate the SystemLanguageID property. Another advantage of this approach is that you can localize your shortcuts, registry entries, etc. because the records in those tables are tied to a particular component. So, if you had a shortcut with French text you would assign the shortcut table record to the component with resource-fr.xml as the key file and the shortcut would only be installed when the resource-fr.xml is installed.

If having multiple resource-??.xml files on your system is a problem, you need to do the following two things:

  1. Go smack the application developer upside the head. S/he should have coded the application to detect the language and load the approprate resource at run time.
  2. Make sure that the grouping of components is conditioned such that they are all mutually exclusive. IOW, only one of the components can possibly be installed at one time.

For example, to install only the French resource file, add a component with key file resource-fr.xml and set the component condition to:

SystemLanguageID=1036

The component will only be installed on systems where the System Locale Identifier Constant indicates French (0x040c hex – 1036 decimal).

If you need to install the French resource on other French locales (such as Belgium, Canada, Monaco, etc.) you would need to expand the condition to:

SystemLanguageID=1036 OR SystemLanguageID=2060 OR SystemLanguageID=3084 OR SystemLanaguageID=6156

Also, whatever your default language should be (English?) then you want the condition for the component that contains that resource file to evaluate so that it installs on all systems that don’t match any of the conditions for the other resource components. So if you only had French (with the previously mentioned locales) and English and you wanted English to be the default then you would set the condition for the English component to:

SystemLanguageID<>1036 AND SystemLanguageID<>2060 AND SystemLanguageID<>3084 AND SystemLanguageID<>6156

…and NOT to:

SystemLanguageID=1033

…since the latter will only install on systems where the local is set to English-US (IOW, any other system not covered by the other component conditions would never get any resource file installed).

A couple of other issues to consider:

  1. If your MSI can be installed per-user, you will also want to consider conditioning the components using the UserLanguageID property as that can be different from the SystemLanguageID (a user can set their user locale to ‘French’ when the system locale is set English so they see French and other users of the same system see English).
  2. To cover the scenario where your user installs under one language, changes the language settings, and then run’s ‘repair’. Make sure you set the msidbComponentAttributesTransitive attribute flags for your components with conditional statements so the conditions get reevaluated during a maintenance mode installation. This would allow the originally installed language component to be removed and the new language component installed for this scenario.