Installing an Integrated or Isolated Shell Application
You must perform the following steps to install an integrated or isolated shell application.
Prepare your solution.
Create a Windows Installer (MSI) package for your application.
Create a Setup bootstrapper.
All of the example code in this document comes from the Isolated Shell Deployment Sample on the MSDN Code Gallery Web site. The sample shows the results of performing each of these steps.
Prerequisites
To perform the procedures described in this topic, you must have the following tools installed on your system.
The Visual Studio 2012 SDK
The Windows Installer XML Toolset version 3.5
Preparing Your Solution
By default, the Shell Templates build to a VSIX package, but this is intended for debugging purposes only. VSIX does not support deployment to other systems. We recommend that you deploy Shell applications in MSI packages to allow for registry access and for restarts during installation. To prepare your application for MSI deployment, perform the following steps.
To prepare a shell application for MSI deployment
Edit each .vsixmanifest file in your solution.
In the Identifier element, add an InstalledByMSI element and a SystemComponent element, and set their values to true.
This prevents the VSIX installer from trying to install your components, and prevents the user from uninstalling them in Extensions and Updates.
If your application includes project templates or item templates,
In the project properties, edit the build tasks to output the template to a compressed file.
Or, use the Export Template wizard to create the compressed file, add it to the solution as a solution item, and remove the project.
If you created your templates by using the templates for creating templates, you can skip this step.
For each project that contains a VSIX manifest, edit the build tasks to output the content to the location that your MSI will install from. Include the VSIX manifest in the build output, but do not build a .vsix file.
Creating an MSI for Your Shell
To build your MSI package, we recommend that you use the Windows Installer XML Toolset because it gives greater flexibility than using a standard Setup project.
Set following elements in your Product.wxs file:
Detection Blocks
Layout of Shell components
Custom Actions
Then, create Registry entries, both in the .reg file for your solution, and in ApplicationRegistry.wxs.
Detection Blocks
A detection block consists of a Property element that specifies a pre-requisite to detect, and a Condition element that specifies a message to return if the prerequisite is not present on the system. For example, your Shell application will require the Microsoft Visual Studio Shell redistributable, and the detection block will resemble the following markup.
<Property Id="ISOSHELLSFX">
<RegistrySearch Id="IsoShellSfx" Root="HKLM" Key="Software\Microsoft\VisualStudio\$(var.ShellVersion)\Setup\IsoShell\$(var.ProductLanguage)" Name="ProductDir" Type="raw" />
</Property>
<Condition Message="This application requires $(var.ShellName). Please install $(var.ShellName) then run this installer again.">
<![CDATA[Installed OR ISOSHELLSFX]]>
</Condition>
The example block above assumes an isolated Shell application. For an integrated Shell application, the Id values would be set to "IsoShellSfx" or "ISOSHELLSFX", and the registry key would point to \IntShell\$(var.ProductLanguage) instead of \IsoShell\$(var.ProductLanguage).
Layout of Shell Components
You must add elements to identify the target directory structure and components to install.
To set layout of Shell components
Create a hierarchy of Directory elements to represent all of the directories to create on the file system on the target computer, as shown in the following example.
<Directory Id="TARGETDIR" Name="SourceDir"> <Directory Id="ProgramFilesFolder"> <Directory Id="CompanyDirectory" Name="$(var.CompanyName)"> <Directory Id="INSTALLDIR" Name="$(var.FullProductName)"> <Directory Id="ExtensionsFolder" Name="Extensions" /> <Directory Id="Folder1033" Name="1033" /> </Directory> </Directory> </Directory> <Directory Id="ProgramMenuFolder"> <Directory Id="ApplicationProgramsFolder" Name="$(var.FullProductName)"/> </Directory> </Directory>
These directories are referred to by Id when files that have to be installed are specified.
Next, identify the components that are required for the Shell and your Shell application, as shown in the following example.
Note
Some elements may refer to definitions in other .wxs files.
<Feature Id="ProductFeature" Title="$(var.ShortProductName)Shell" Level="1"> <ComponentGroupRef Id="ApplicationGroup" /> <ComponentGroupRef Id="HelpAboutPackage" /> <ComponentRef Id="GeneralProfile" /> <ComponentGroupRef Id="EditorAdornment"/> <ComponentGroupRef Id="SlideShowDesignerGroup"/> <!-- Note: The following ComponentGroupRef is required to pull in generated authoring from project references. --> <ComponentGroupRef Id="Product.Generated" /> </Feature>
The ComponentRef element refers to an additional .wxs file that identifies files that are required by the current component. For example, GeneralProfile has the following definition in HelpAbout.wxs.
<Fragment Id="FragmentProfiles"> <DirectoryRef Id="INSTALLDIR"> <Directory Id="ProfilesFolder" Name="Profiles"> <Component Id='GeneralProfile' Guid='*'> <File Id='GeneralProfile' Name='General.vssettings' DiskId='1' Source='$(var.BuildOutputDir)Profiles\General.vssettings' KeyPath='yes' /> </Component> </Directory> </DirectoryRef> </Fragment>
The DirectoryRef element says where these files go on the user computer. The directory element says that it will be installed into a sub-directory, and each File element represents a file that is built or exists as part of the solution and tells where it can be found when the MSI file is created.
The ComponentGroupRef element refers to a group of other components (or components and component groups). For instance, the ApplicationGroup ComponentGroupRef is defined as follows in Application.wxs.
<ComponentGroup Id="ApplicationGroup"> <ComponentGroupRef Id="DebuggerProxy" /> <ComponentRef Id="MasterPkgDef" /> <ComponentRef Id="SplashResource" /> <ComponentRef Id="IconResource" /> <ComponentRef Id="WinPrfResource" /> <ComponentRef Id="AppExe" /> <ComponentRef Id="AppConfig" /> <ComponentRef Id="AppPkgDef" /> <ComponentRef Id="AppPkgDefUndef" /> <ComponentRef Id="$(var.ShortProductName)UI1033" /> <ComponentRef Id="ApplicationShortcut"/> <ComponentRef Id="ApplicationRegistry"/> </ComponentGroup>
Note
Required Dependencies for Isolated Shell Applications are: DebuggerProxy, MasterPkgDef, Resources (especially the .winprf file), Application, and PkgDefs. Integrated shell has all of these already installed.
Custom Actions (Integrated Shell)
As part of the layout of Shell components, there may be Extensions and Templates to add to the user computer. In the case of Isolated shell, nothing extra has to be done because it is a separate product. However, in the case of Integrated Shell, the user may already be a Visual Studio user and that instance of Visual Studio will not be aware of added extensions or templates until you tell it to check for new templates and extensions. This is handled by a custom action.
You can ensure that your extensions load by specifying custom actions in product.wxi, just after the detection block, as shown in the following example.
<InstallExecuteSequence>
<Custom Action="SetInstallDir" Before="CostFinalize" />
<Custom Action="SetDevEnv" Before="CostFinalize" />
<Custom Action="RunSlashSetup" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
<CustomAction Id="SetInstallDir" Property="INSTALLDIR" Value="[INTSHELLSFX]$(var.ExtensionsFolder)" />
<CustomAction Id="SetDevEnv" Property="DEVENV" Value="[INTSHELLSFX]$(var.IdeFolder)\devenv.exe" />
<CustomAction Id="RunSlashSetup" Property="DEVENV" ExeCommand="/setup" Return="ignore" />
The SetInstallDir action tells the system where to find your extensions and the SetDevEnv action tells it where to find devenv.exe. The RunSlashSetup action runs the devenv /setup command, which reloads all installed extensions.
Registry Entries
The Isolated Shell project template includes a ProjectName.reg file for registry keys to merge on installation. These registry entries must be part of the MSI for both installation and cleanup purposes. You must also create matching registry blocks in ApplicationRegistry.wxs.
To integrate registry entries into the MSI
In the Shell Customization folder, open ProjectName.reg.
Replace all instances of the $RootFolder$ token with the path of the target installation directory.
Add any additional registry entries that are required to run your application.
Open ApplicationRegistry.wxs.
For each registry entry in ProjectName.reg, add a corresponding registry block, as shown in the following examples.
ProjectName.reg
ApplicationRegisty.wxs
[HKEY_CLASSES_ROOT\CLSID\{bb431796-a179-4df7-b65d-c0df6bda7cc6}]
@="PhotoStudio DTE Object"
<RegistryKey Id='DteClsidRegKey' Root='HKCR' Key='$(var.DteClsidRegKey)' Action='createAndRemoveOnUninstall'>
<RegistryValue Type='string' Name='@' Value='$(var.ShortProductName) DTE Object' />
</RegistryKey>
[HKEY_CLASSES_ROOT\CLSID\{bb431796-a179-4df7-b65d-c0df6bda7cc6}\LocalServer32]
@="$RootFolder$\PhotoStudio.exe"
<RegistryKey Id='DteLocSrv32RegKey' Root='HKCR' Key='$(var.DteClsidRegKey)\LocalServer32' Action='createAndRemoveOnUninstall'>
<RegistryValue Type='string' Name='@' Value='[INSTALLDIR]$(var.ShortProductName).exe' />
</RegistryKey>
Var.DteClsidRegKey in this example resolves to the registry key in the top row. Var.ShortProductName resolves to PhotoStudio.
Running the Application MSI
After the Visual Studio Shell installer returns ERROR_SUCCESS, you can run the MSI for your application. Because your Setup program is providing the user interface, start your MSI in quiet mode (/q), and with logging (/L), as shown in the following example.
TCHAR temp[MAX_PATH];
GetTempPath(MAX_PATH, temp);
CString boutiqueInstallCmd, msi, log;
CString cmdLine(MAKEINTRESOURCE("msiexec /q /I %s /L*vx %s REBOOT=ReallySuppress"));
CString name(MAKEINTRESOURCE("PhotoStudioIntShell.msi"));
log.Format(_T("\"%s%s.log\""), temp, name);
msi.Format(_T("\"%s%s\""), GetSetupPath(), name);
boutiqueInstallCmd.Format(cmdLine, msi, log);
//TODO: You can use MSI API to gather and present install progress feedback from your MSI.
dwResult = ExecCmd(boutiqueInstallCmd, FALSE);
See Also
Tasks
Walkthrough: Creating a Basic Isolated Shell Application
Concepts
Integrated Shell and Isolated Shell
Deploying an Isolated Shell-Based Application on a 64-Bit Operating System