Figure 3   Key Installation Database Tables

Table Purpose
Class Information about COM servers installed by this product. Links one-to-one to Component.
Component Information about components installed by this product.
Feature Information about features installed by this product.
FeatureComponents Mapping from Feature to Component. This is a many-to-many relationship. That is, a single component can be shared among multiple features, and a single feature can be composed of multiple components.
File Information about files installed by this product. Links many-to-one to Component, each file is part of only one component.
InstallExecuteSequence List of actions to be performed to install this product.
InstallUISequence List of user interface items to show prior to installing this product. This could be used to collect user information, installation options, and so on.
Property List of property values for the product. Properties can be used as conditions and can be changed during installation to record events.
PublishComponent Used for qualified components. Links to Component.
Registry Information about registry entries to be written when a component is installed. Links many-to-one to Component, each registry entry is part of only one component.
RemoveFile Files that should be removed when a component is installed. Links many-to-one to Component.
RemoveRegistry Registry entries that should be removed when a component is installed. Links many-to-one to Component.
SelfReg For backwards compatibility with components that do not do their COM registration through Class (the preferred route). Links many-to-one to Component.
Shortcut Shortcuts that should be created for a component. Links many-to-one to Component.
TypeLib Visual Basic type library registration. Links many-to-one to Component.


Figure 4   Feature Installation States

State Meaning
INSTALLSTATE_LOCAL The feature is installed on the local machine; that is, the feature's files live in C:\Program Files\MyProduct.
INSTALLSTATE_SOURCE The feature is installed and runs from the source installation media (a CD or network server).
INSTALLSTATE_ABSENT The feature is not installed.
INSTALLSTATE_ADVERTISED The feature is advertised, meaning it is available but not installed.


Figure 5   PublishComponent Table

Column Type Description
ComponentID GUID The category GUID with which this published component is associated.
Qualifier Text A text string that qualifies the value in the ComponentID column. A qualifier is used to distinguish multiple forms of the same component, such as a component that is implemented in multiple languages. This qualifier is referred to by the MsiProvideQualifiedComponent function and the MsiEnumComponentQualifiers function.
AppData Text An optional localizable text string, owned and often parsed by the application. This can be retrieved with the MsiEnumComponentQualifiers function in the lpApplicationDataBuf buffer.
Feature_ Identifier Together, the Se two columns provide the information for installing the component referred to by this qualifier. Both a Feature and a Component are needed because a component cannot be installed; the Owning feature must be installed. The Component ID identifies the particular file or path within the feature.
Component_ Identifier


Figure 6   Qualified Component APIs


UINT MsiEnumComponentQualifiers(

    LPTSTR szComponent,             // component ID GUID (as a string)
    DWORD iIndex,                   // 0-based index into component qualifiers
    LPTSTR lpQualifierBuf,          // buffer to return qualifier
    DWORD *pcchQualifierBuf         // in/out qualifier buffer character count
    LPTSTR lpApplicationDataBuf,    // buffer to return application data
    DWORD *pcchApplicationDataBuf   // in/out app data character count
    )

UINT MsiProvideQualifiedComponent(

    LPCTSTR szComponent,            // component ID
    LPCTSTR szQualifier,            // specifies which component to access
    DWORD dwInstallMode,            // the install mode
    LPTSTR lpPathBuf,               // in/out returned path, NULL if not needed
    DWORD *pcchPathBuf              // in/out buffer character count
    )

Figure 7   Finding a Component


#include <windows.h>
#include <msi.h>

// --------------------------------------------------------------------------
// FindPerLangComponent()
//    Locates and provides the required per-language component using
//    MsiProvideQualifiedComponent.  It first tries the LCID passed in as
//    a qualifier; if that fails, it tries the primary language of that LCID.
//    If neither succeeds, it returns the error code from
//    MsiProvideQualifiedComponent for the last attempt, else ERROR_SUCCESS.
//    The path to the component is returned in szPath if successful.  The
//    szComponentCode is the GUID of the qualified component as a string:
//    TCHAR    szComponent[]=TEXT("{5CB2D5F5-19DD-11d1-9A9D-006097C4E489}");

UINT FindPerLangComponent (
    LPCTSTR    szComponentCode,    // GUID of the qual. Component
    LCID       lcid,               // Requested language
    LPTSTR     szPath,             // Buffer for returned path
    DWORD      *pcchPath)          // size of buffer
{
    DWORD    cchPathInitial = *pcchPath;
    TCHAR    szQualifier[MAX_PATH];
    UINT     iResult;
    *szPath = 0;
    for (UINT i = 0; i < 2 ; i++) 
    {
        wsprintf(szQualifier, TEXT("%4.4x"), i == 0 ?
                 LANGIDFROMLCID(lcid) :
                 PRIMARYLANGID(LANGIDFROMLCID(lcid)));
        *pcchPath = cchPathInitial;

        iResult = MsiProvideQualifiedComponent(szComponentCode, 
                          szQualifier, INSTALLMODE_DEFAULT, szPath,  pcchPath);

        if ( iResult == ERROR_SUCCESS || 
             iResult == ERROR_INSTALL_USEREXIT ||
             iResult == ERROR_INSTALL_FAILURE)
                 break;
    }

    return iResult;
}

Figure 8   Finding and Installing a File


#include <windows.h>
#include <msi.h>

// --------------------------------------------------------------------------
// FGetFilePath()
//  Returns the path to a setup-provided file using the Windows installer
//  API.  Handles both key and non-key files from a component.  If the
//  file is not installed, will install it if fInstall is TRUE.  The
//  szComponentCode is the GUID of the component as a string, e.g.:
//  TCHAR   szComponent[]=TEXT("{5CB2D5F5-19DD-11d1-9A9D-006097C4E489}");

//  The product code for this application.  This would be initialized when
//  the application starts using MsiGetProductCode.

TCHAR   vszProductCode[39] = {0};       // Room for a GUID string.

UINT FGetFilePath (
    LPCTSTR szFeature,           // Feature this component is part of
    LPCTSTR szComponentCode,     // GUID of the particular component
    LPCTSTR szFileName,          // File within component; can be NULL
                                 // for key file of component.
    BOOL fInstall,               // TRUE to install if not present
    BOOL fFix,                   // TRUE to reinstall even if present.
    LPTSTR szPath,               // Buffer for returned path
    DWORD *pcchPath)             // size of buffer
{
    UINT cchPath = *pcchPath;    // remember size of buffer
    UINT is;                     // install state of component
    DWORD er = ERROR_SUCCESS;
    *szPath = 0;
    is = MsiGetComponentPath(vszProductCode,
                             szComponentCode, szPath, pcchPath);

    switch (is)
        {
        case INSTALLSTATE_DEFAULT:
        case INSTALLSTATE_LOCAL:
        case INSTALLSTATE_SOURCE:
            // component is there
            if (!fFix)
                break;
            // fall through to fix the component

        case INSTALLSTATE_UNKNOWN: 
            // component is not there
            // look up a level to determine installation state
            // of the feature for this component.
            is = MsiQueryFeatureState(vszProductCode, szFeature);

            // if the feature is disabled, we can't install it.  Note
            // this is a convention: we use INSTALLSTATE_ABSENT to
            // mean not installed and not available to be installed
            // and INSTALLSTATE_ADVERTISED to mean not installed, but
            // available to be installed. 

            if (is == INSTALLSTATE_ABSENT)
                return INSTALLSTATE_ABSENT;

            // Setting install state to default makes this
            // feature be installed either locally or to run from
            // the install source, depending on the authored affinity.
            if (fInstall || fFix)
                er = MsiConfigureFeature(vszProductCode, szFeature,
                                         INSTALLSTATE_DEFAULT);
            if (!fFix && er == ERROR_SUCCESS)
                {
                // Let's now try to get the installed path of
                // the component.  If that fails, we need to
                // fix it.
                is = MsiGetComponentPath(vszProductCode,
                                         szComponentCode, szPath, pcchPath);
                if (is == INSTALLSTATE_LOCAL || 
                    is == INSTALLSTATE_DEFAULT ||
                    is == INSTALLSTATE_SOURCE)
                    break;
                }

            // Fall through to fix this component.

        case INSTALLSTATE_BROKEN:
        case INSTALLSTATE_INCOMPLETE:
            // Feature is broken, try reinstalling it, verifying
            // files and registry data (both HKEY_LOCAL_MACHINE
            // and HKEY_CURRENT_USER)
            if (fInstall || fFix)
                er = MsiReinstallFeature(vszProductCode,
                                         szFeature,
                                         (REINSTALLMODE_FILEVERIFY | 
                                          REINSTALLMODE_REPAIR | 
                                          REINSTALLMODE_USERDATA |
                                          REINSTALLMODE_MACHINEDATA));
            if (er == ERROR_SUCCESS)
                {
                // OK, reinstall succeeded, let's try to
                // get the component path again..
                is = MsiGetComponentPath(vszProductCode,
                                         szComponentCode, szPath, pcchPath);
                if (is == INSTALLSTATE_LOCAL || 
                    is == INSTALLSTATE_DEFAULT ||
                    is == INSTALLSTATE_SOURCE)
                    break;
                else
                    return is;      // can't fix component.
                }
        }

    // If we've been able to install or reinstall the component,
    // get the path to the particular file we're interested in.
    // If we want the keyfile, we've already got that.
    if (er == ERROR_SUCCESS && szFileName != NULL)
        {
        TCHAR   *pchSlash = NULL;
        TCHAR *pch;
        for (pch = szPath; *pch != 0; pch++)
            if (*pch == '\\')
                pchSlash = pch;
        if (pchSlash++ && 
            (pchSlash-szPath)+lstrlen(szFileName) < cchPath)
            {
            lstrcpy(pchSlash, szFileName);
            }
        else
            {
            er = ERROR_MORE_DATA;   // buffer too small.
            }
        }
        
    SetLastError(er);
    return er == ERROR_SUCCESS ? is : INSTALLSTATE_BROKEN;
}