Support Just-In-Time installation |
With the traditional installation model, whenever an installation task needed to be performed, the user needed to exit the application and run setup. This most commonly occurred whenever a user needed functionality that they chose not to install on the first pass through setup. In this scenario, users needed to anticipate what features they would need from an application before they actually used the application.
By using the Microsoft® Windows® Installer Management API, your application can free users from this burden. If, while using your program, the user requires functionality that was not previously installed, your application can call the Windows Installer to install the necessary feature on the user’s behalf – the user does not have to explicitly re-run setup. Essentially, all features of your application are available to the user even if they’re not installed. This notion of availability in the absence of the files themselves being installed is known as "advertisement." Of course all this great functionality requires that you’ve designed you application along feature lines. Providing you’ve split up your application to support this kind on granularity, supporting install on demand is relatively simple, and uses the same principles as self repair.
As an example, lets imagine a graphing application. At setup time the user installs the main graphing program, STGraph, but decides not to install the PriceHistory component – which gives them the history of stocks over time. A single MSI feature represents this PriceHistory component. If, at a later date the user decides that they really would like to see a historical view of their stock's performance, instead of having to re-run setup and install the PriceHistory feature, they simply select the PriceHistory option from the menu bar. The main STGraph program then calls the Windows Installer Management API and installs the PriceHistory feature automatically on the users behalf. All the user sees is a brief progress dialog and the feature is then available for them to use – all without running through the original setup UI.
The code sample below illustrates how to use the Windows Installer API to install features on demand. This code is triggered when the user selects the View Price History option from the main application’s menu bar. First, call MsiQueryFeatureState to determine if our component’s feature is actually already installed. If it’s not installed, but is advertised we then call MsiConfigureFeature to install the feature locally. The Windows Installer will then locate the source files and install our feature for us. The rest of the code deals with repairing the component if it is installed, but missing. As you can see, the code required to support install on demand is no different from the code to support self repair. In essence, if you design your application correctly, you can get two cool features for the price of one!
//This code uses the installer APIs to locate the DLL if installed,
// and install it if not installed.
// Product/Feature/Component IDs from MSI Database
CString strProduct = "{3A26942E-532D-11D2-BAD8-00805F9B1139}";// product ID code
CString strFeature = "PriceHistory";// feature ID code
CString strComponent = "{3A269430-532D-11D2-BAD8-00805F9B1139}"; // component ID
_TCHAR strBuf[MAX_PATH];
DWORD dwCount = MAX_PATH;
UINT uiState;
// Find where to load from and load the DLL.
// Use MsiGetComponentPath() when it becomes available
INSTALLSTATE IState = MsiQueryFeatureState(strProduct, strFeature);
switch (IState)
{
case INSTALLSTATE_ADVERTISED :
// The feature is installable on demand
MsiConfigureFeature(strProduct, strFeature, INSTALLSTATE_LOCAL);
// Fall through to the next case
case INSTALLSTATE_LOCAL :
case INSTALLSTATE_SOURCE :
{
// Should be OK to load
// Find path to component Key File
MsiLocateComponent(strComponent, strBuf, &dwCount);
hDLL = LoadLibrary(strBuf);
if (hDLL == NULL)
{
// The feature should be installable but LoadLibrary has failed
// Try using the Installer API to reinstall .
uiState = MsiReinstallFeature(strProduct, strFeature, REINSTALLMODE_FILEMISSING);
if (uiState != ERROR_SUCCESS)
{
AfxMessageBox( "Reinstall failed" );
return;
}
else
{
MsiLocateComponent(strComponent, strBuf, &dwCount);
hDLL = LoadLibrary(strBuf);
if (hDLL == NULL)
{
// Couldn't load after the reinstall.
AfxMessageBox("Price History Feature: Component error");
return;
}
}
}
break;
}
default :
{
// Something is wrong - no point in trying a reinstall
AfxMessageBox("The Price History Feature is not Installable");
return;
}
}
// now use loaded DLL
Installer Function Reference, MsiConfigureFeature, MSILocateComponent, MsiQueryFeatureState, MsiReinstallFeature, Organizing Applications into Components, Roadmap to Windows Installer Documentation, Windows Installer