INSTFORM.CPP
// --InstForm.cpp--------------------------------------------------------------- 
// Command line utility to install or remove Exchange forms. 
//   
// Copyright (C) Microsoft Corp. 1986-1996.  All Rights Reserved. 
// ----------------------------------------------------------------------------- 
 
#include "edk.h" 
#include "exchcli.h" 
 
class CUserParams;// must be declared before "instform.chk" 
 
#include "iformmsg.h"// created from instform.mc by the message compiler 
#include "instform.chk" 
 
// Define a warning to exit if user asks for help. 
const HRESULT EXIT_WARNING = MAPI_W_ERRORS_RETURNED; 
 
LPTSTRlpszAppName = TEXT("InstForm"); 
 
//$--INTERNAL_ERROR------------------------------------------------------------- 
//  Helper function for EventLogMsg 
// ----------------------------------------------------------------------------- 
static inline VOID INTERNAL_ERROR( 
    IN LPCTSTR str, 
    IN const HRESULT hr) 
{ 
    TCHAR   szErrorCode[16] = {0}; 
 
    EventLogMsg( 
        INSTFORM_INTERNAL_ERROR, 
        2, str, _itot( hr, szErrorCode, 16), 
        0); 
} 
 
//$--fFileExists()-------------------------------------------------------------- 
// RETURNS: TRUE if the file exists and FALSE if not. 
// ----------------------------------------------------------------------------- 
 
BOOL fFileExists(  
    IN LPTSTR lpszFileSpec)   // File to validate exists. 
{ 
    struct _tfinddata_t FileInfo = {0}; 
    long lhRet = _tfindfirst( lpszFileSpec, &FileInfo); 
 
    if( lhRet == -1) 
        return( FALSE); 
    _findclose( lhRet); 
     
    return( TRUE); 
} 
 
 
//$--CUserParams---------------------------------------------------------------- 
// Container class for user's parameters and parsing the command line. 
// ----------------------------------------------------------------------------- 
 
class CUserParams 
{ 
public: 
    CUserParams(); 
     
    HRESULT HrParseCommandLine( 
        IN int      argc,       // number of arguments on command line 
        IN char*    argv[]);    // array of command line arguments 
 
friend HRESULTHrSetupAndDoIt( CUserParams&); 
 
    // These members will contain the arguments  
    // and values specified by the user. 
    BOOL    m_fInstall;         // TRUE when installing a form. 
 
protected: 
    BOOL    m_fRemove;          // TRUE when removing a form. 
    HFRMREG m_hFrmReg;          // The registry to install form in. 
    char*   m_pszCfgFile;       // The configuration file name for installing a form. 
    char*   m_pszMsgClass;      // The message class for removing a form. 
    char*   m_pszFolder;        // The path of the folder for installing in a folder registry. 
    char*   m_pszProfile;       // The profile to logon to. 
    char*   m_pszPassword;      // The password for logon. 
    char*   m_pszMsgStore;      // The Display Name of the message store. 
 
protected: 
    void PrintUsage( IN BOOL fHelp = FALSE); 
    static char*    m_pszFlagArray[]; 
    static char*    m_pszRegArray[]; 
 
    // These MUST correspond to the m_pszFlagArray[]. 
    enum eFlagIndex 
    { 
        NON_FLAG = MAX_ULONG, 
        HELP1 = 0, 
        HELP2, 
        INSTALL, 
        REMOVE, 
        VALUE_REQUIRED, // Place flags that require a value below. 
        REGISTRY = VALUE_REQUIRED, 
        FOLDER, 
        PASSWORD, 
        EPROFILE, 
        MSGSTORE, 
    }; 
}; 
 
// ----------------------------------------------------------------------------- 
// Arrays that belong to CUserParams for parsing command line. 
// ----------------------------------------------------------------------------- 
 
char* CUserParams::m_pszFlagArray[] =  
{ 
    "?", 
    "HELP", 
    "INSTALL", 
    "REMOVE", 
    // Place flags that require a value below. 
    "REGISTRY", 
    "FOLDER", 
    "PASSWORD", 
    "PROFILE", 
    "MSGSTORE", 
}; 
 
// This array is defined to correspond to MAPI defined constants listed in  
// the m_hFrmRegArray defined below, so the order is important. 
char* CUserParams::m_pszRegArray[] =  
{ 
    "LOCAL",      
    "PERSONAL",   
    "FOLDER",     
    "ENTERPRISE", 
}; 
 
// This array is defined to correspond to the strings  
// in the array m_pszRegArray defined above. 
static HFRMREG m_hFrmRegArray[] = 
{ 
    HFRMREG_LOCAL, 
    HFRMREG_PERSONAL, 
    HFRMREG_FOLDER, 
    HFRMREG_ENTERPRISE, 
}; 
 
// $--CUserParams::PrintUsage()------------------------------------------------- 
// Print the usage message for the command line parameters. 
// ----------------------------------------------------------------------------- 
 
void CUserParams::PrintUsage(  
    IN BOOL fHelp) // True if complete help is wanted. 
{ 
    printf(  
        "USAGE:  INSTFORM /INSTALL cfg_file [flags]\n" 
        "   OR:  INSTFORM /REMOVE msg_class [flags]\n"); 
         
    if( !fHelp) 
        return; 
 
    printf(      
        "\n" 
        "   /HELP or /? Show help information.\n" 
        "\n" 
        "   /INSTALL    To install the form specified in the cfg_file\n" 
        "\n" 
        "   /REMOVE     To remove the form specified by the msg_class.\n" 
        "\n" 
        "   /REGISTRY=  Flag to specify which registry to install form in.\n" 
        "               FOLDER the /FOLDER option must be specified.\n" 
        "               PERSONAL\n" 
        "               LOCAL\n" 
        "               ENTERPRISE\n" 
        "\n" 
        "   /FOLDER=    Specify the folder path of the registry to install in. Example:\n" 
        "                   /FOLDER=\"top of information store\\inbox\"\n" 
        "\n" 
        "               When this parameter is specified the /REGISTRY=FOLDER is\n" 
        "               assumed and need not be specified.  Any other /REGISTRY=\n" 
        "               option is an error.\n" 
        "\n" 
        "   /PROFILE=   Specify the profile for logon.  Optional for local registry.\n" 
        "\n" 
        "   /PASSWORD=  Specify the password if needed.\n" 
        "\n" 
        "   /MSGSTORE=  Specify the display name of the message store that contains\n" 
        "               the folder specified.  This is only valid with folders.  If\n" 
        "               not specified the default message store will be used.\n" 
        "\n" 
        "   cfg_file    The name of the configuration file of the form to install.\n" 
        "\n" 
        "   msg_class   The message class of the form to be removed from the\n" 
        "               forms registry.\n" 
    ); 
} 
 
// $--CUserParams::CUserParams()------------------------------------------------ 
// CONSTRUCTOR to initialize the user parameter container. 
// ----------------------------------------------------------------------------- 
 
CUserParams::CUserParams() 
{ 
    m_fInstall      = FALSE; 
    m_fRemove       = FALSE; 
    m_hFrmReg       = MAX_ULONG; 
    m_pszMsgClass   = NULL; 
    m_pszCfgFile    = NULL; 
    m_pszFolder     = NULL; 
    m_pszProfile    = NULL; 
    m_pszPassword   = NULL; 
    m_pszMsgStore   = NULL; 
} 
 
// $--CUserParams::HrParseCommandLine()----------------------------------------- 
// Parse the command line arguments and place their values in the appropriate  
// member variables. 
// ----------------------------------------------------------------------------- 
 
HRESULT CUserParams::HrParseCommandLine( 
    IN int      argc,           // number of arguments on command line 
    IN char*    argv[])         // array of command line arguments 
{ 
    HRESULT     hr              = NOERROR; 
    int         iArg            = 0; 
    int         cNonFlagArgs    = 0; 
    eFlagIndex  nFlagIndex      = NON_FLAG; 
    char*       pszValue        = NULL; 
    char*       pszFirstArg     = NULL; 
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 
    DEBUGPRIVATE( "CUserParams::HrParseCommandLine()"); 
 
    // If there are no flags on the command line then just print a usage message. 
    if( argc < 2) 
    { 
        PrintUsage(); 
        return( EXIT_WARNING); 
    } 
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Do an initial check for /? or /HELP.  If found, don't do any other parsing. 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 
    for (iArg = 1; iArg < argc; iArg++) 
    {   // Ignore return value while we look for help flags. 
        hr = _HrExpandCommandLineArgument( argv[iArg], m_pszFlagArray,  
            ARRAY_CNT( m_pszFlagArray), (ULONG*) &nFlagIndex, NULL, &pszValue); 
 
        if( SUCCEEDED( hr) && nFlagIndex == HELP1 || nFlagIndex == HELP2) 
        { 
            PrintUsage( TRUE); 
            return( EXIT_WARNING); 
        } 
    } 
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Loop through and parse all the command line arguments. 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 
    for( iArg = 1; iArg < argc; iArg++) 
    { 
        hr = _HrExpandCommandLineArgument( argv[iArg], m_pszFlagArray, 
            ARRAY_CNT( m_pszFlagArray), (ULONG*) &nFlagIndex, NULL, &pszValue); 
        if( FAILED(hr)) 
        { 
            fprintf(stderr, "ERROR: unknown command line parameter: %s.\n", argv[ iArg]); 
            goto cleanup; 
        } 
 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        // Parse non-flag arguments. 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        if( nFlagIndex == NON_FLAG && pszValue != NULL) 
        { 
            switch( cNonFlagArgs ++) 
            { 
                case 0:     // Either cfg_file or msg_class 
                    pszFirstArg = pszValue; 
                    break; 
 
                default:    // Too many arguments!!! 
                    fprintf( stderr, "ERROR: too many arguments: %s\n", argv[iArg]); 
                    hr = HR_LOG(E_FAIL); 
                    goto cleanup; 
            } 
        } 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        else // Parse the flag arguments. 
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
        { 
            if( nFlagIndex < VALUE_REQUIRED) 
            {                
                if( pszValue) 
                {   // No value needed here. 
                    fprintf( stderr, "ERROR: flag /%s does not take a value.\n", m_pszFlagArray[ nFlagIndex]); 
                    hr = HR_LOG(E_FAIL); 
                    goto cleanup; 
                } 
            } 
            else // nFlagIndex >= VALUE_REQUIRED 
            { 
                if( !pszValue) 
                {   // Make sure user supplied required values. 
                    fprintf( stderr, "ERROR: flag /%s requires a value.\n", m_pszFlagArray[ nFlagIndex]); 
                    hr = HR_LOG(E_FAIL); 
                    goto cleanup; 
                } 
            } 
 
            switch( nFlagIndex) 
            { 
                case INSTALL: 
                    m_fInstall = TRUE; 
                    break; 
 
                case REMOVE: 
                    m_fRemove = TRUE; 
                    break; 
 
                case REGISTRY: 
                    // Look up the registry value entered by the user and convert  
                    // to a value that MAPI will understand. 
                    hr = _HrFindArrayValue( pszValue, m_pszRegArray, ARRAY_CNT( m_pszRegArray), &m_hFrmReg); 
                    if (FAILED(hr)) 
                    { 
                        fprintf(stderr, "ERROR: invalid registry value: %s\n", pszValue); 
                        goto cleanup; 
                    } 
                    m_hFrmReg = m_hFrmRegArray[ m_hFrmReg]; 
 
                    // If they specified the /FOLDER= flag then the only registry 
                    // flag they can specify is FOLDER. 
                    if( m_hFrmReg != HFRMREG_FOLDER && m_pszFolder != NULL) 
                    { 
                        fprintf( stderr, "ERROR: When specifying \"/FOLDER=\" omit the \"/REGISTRY=\" flag.\n"); 
                        hr = HR_LOG(E_FAIL); 
                        goto cleanup; 
                    } 
                    break; 
 
                case FOLDER: 
                    if( m_hFrmReg != HFRMREG_FOLDER && m_hFrmReg != MAX_ULONG) 
                    { 
                        fprintf( stderr, "ERROR: When specifying \"/FOLDER=\" omit the \"/REGISTRY=\" flag.\n"); 
                        hr = HR_LOG(E_FAIL); 
                        goto cleanup; 
                    } 
                    m_hFrmReg = HFRMREG_FOLDER; 
                    m_pszFolder = pszValue; 
                    break; 
                 
                case PASSWORD: 
                    m_pszPassword = pszValue; 
                    break; 
 
                case EPROFILE: 
                    m_pszProfile = pszValue; 
                    break; 
 
                case MSGSTORE: 
                    m_pszMsgStore = pszValue; 
                    break; 
 
                default: 
                    // Unexpected value in m_pszFlagArray and the user specified it. 
                    hr = HR_LOG(E_FAIL); 
                    goto cleanup; 
            } 
        } 
    }   // End For Loop 
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// Final parameter validation. 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 
    // Validate that either INSTALL or REMOVE was specifed. 
    if( m_fInstall) 
    {   // They specified /INSTALL 
        if( m_fRemove) 
        { 
            fprintf( stderr, "ERROR: Conflicting command line arguments.\n" 
                             "       Both /INSTALL and /REMOVE can not be specified.\n"); 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
        if( !pszFirstArg) 
        { 
            fprintf( stderr, "ERROR: please specify the cfg_file name.\n"); 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
        if( !fFileExists( pszFirstArg)) 
        { 
            fprintf( stderr, "ERROR: can not find file %s\n", pszFirstArg); 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
 
        m_pszCfgFile = pszFirstArg; 
    } 
    else if( m_fRemove) 
    {   // They specified /REMOVE 
        if( !pszFirstArg) 
        { 
            fprintf( stderr, "ERROR: please specify the msg_class name.\n"); 
            hr = HR_LOG(E_FAIL); 
            goto cleanup; 
        } 
        m_pszMsgClass = pszFirstArg; 
    } 
    else 
    { 
        fprintf( stderr, "ERROR: please specify either /INSTALL or /REMOVE.\n"); 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    // It is an error to specify the folder registry but no folder name. 
    if( m_hFrmReg == HFRMREG_FOLDER && !m_pszFolder) 
    {    
        fprintf( stderr, "ERROR: You must specify \"/FOLDER=\" with the \"/REGISTRY=FOLDER\" flag.\n"); 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    // It is an error to specify message store without specifiying the folder registry. 
    if( m_pszMsgStore && m_hFrmReg != HFRMREG_FOLDER) 
    {    
        fprintf( stderr, "ERROR: \"/MSGSTORE=\" is only valid when \"/FOLDER=\" has been specified.\n"); 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    // The profile must be specified unless using the local registry. 
    if( m_hFrmReg != HFRMREG_LOCAL && !m_pszProfile) 
    {    
        fprintf( stderr, "ERROR: You must specify the profile name.\n"); 
        hr = HR_LOG(E_FAIL); 
        goto cleanup; 
    } 
 
    // If user did not specify the registry then use the default one. 
    if( m_hFrmReg == MAX_ULONG) 
        m_hFrmReg = HFRMREG_DEFAULT; 
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
cleanup: 
    RETURN( hr); 
} 
 
//$--HrOpenMsgStoreFolderByName()----------------------------------------------- 
// Returns pointer to open folder resource.  If MsgStore is NULL, default message 
// store is assumed. 
// ----------------------------------------------------------------------------- 
 
HRESULT 
HrOpenMsgStoreFolderByName( 
INLPMAPISESSIONlpMAPISession,  // Active session handle 
INLPTSTRlpszMsgStore,   // Name of message store, or NULL for default 
INLPTSTRlpszFolder,     // Folder path name to open 
OUTLPMAPIFOLDER*lppFolder)     // RETURN: open folder interface 
{ 
HRESULThr = NOERROR; 
ULONGcbeid  = 0L; 
LPENTRYIDlpeid = NULL; 
LPMDBlpMDB = NULL; 
LPMAPIFOLDERlpFolder = NULL; 
 
DEBUGPUBLIC( "HrOpenMsgStoreFolderByName()"); 
 
hr = CHK_HrOpenMsgStoreFolderByName( 
lpMAPISession, lpszMsgStore, lpszFolder, 
lppFolder); 
if( FAILED( hr)) 
RETURN( hr); 
 
// Get the entry ID of the specified or default message store. 
if( lpszMsgStore) 
    hr = HrMAPIFindStore( lpMAPISession, lpszMsgStore, &cbeid, &lpeid); 
else 
    hr = HrMAPIFindDefaultMsgStore( lpMAPISession, &cbeid, &lpeid); 
if( FAILED( hr)) 
goto cleanup; 
 
ASSERTERROR( cbeid != 0, "Entry ID count should not be zero.");  
ASSERTERROR( lpeid != NULL, "NULL lpeid pointer"); 
 
// Open the message store. 
hr = lpMAPISession->OpenMsgStore( 
0, cbeid, lpeid, NULL,  
MDB_WRITE | MAPI_DEFERRED_ERRORS, 
&lpMDB); 
if( FAILED(hr)) 
    goto cleanup; 
 
ASSERT_IUNKNOWN_PTR( lpMDB, "Invalid store pointer"); 
 
    hr = HrMAPIOpenFolderEx( lpMDB, TEXT('\\'), lpszFolder, &lpFolder); 
    if( FAILED(hr)) 
    goto cleanup; 
 
*lppFolder = lpFolder; 
 
cleanup: 
MAPIFREEBUFFER( lpeid); 
 
ULRELEASE( lpMDB); 
 
RETURN( hr); 
} 
 
//$--HrOpenFormContainer----------------------------------------------------- 
// Returns open form container interface.  NULLs may be passed for unnecessary 
// string values.  For all but HFRMREG_LOCAL, a MAPI session handle is also 
// returned.  The user assumes responsibility of logging off and releasing 
// this session. 
// 
// There are two container types for forms.  The first involves logging 
// on to a MAPI session to open the form container that the form will be  
// installed on.  The second is simpler and does not require logging on to a 
// MAPI session, but only works for installing local forms.  Both techniques 
// are demonstrated below. 
//---------------------------------------------------------------------------- 
 
HRESULT 
HrOpenFormContainer( 
INHFRMREGhFrmReg,            // Desired form registry container 
INLPTSTRlpszProfile,        // Session profile, if needed 
INLPTSTRlpszPassword,       // Session password, if needed 
INLPTSTRlpszMsgStore,       // Message store of folder, if needed 
INLPTSTRlpszFolder,         // Folder name, if needed 
OUTLPMAPISESSION*lppMAPISession,    // RETURN: active session 
OUTLPMAPIFORMCONTAINER*lppFormContainer)  // RETURN: open folder container 
{ 
HRESULThr= NOERROR; 
LPMAPIFOLDERlpFolder= NULL; 
    LPMAPIFORMMGRlpFormMgr= NULL; 
LPMAPISESSIONlpMAPISession= NULL; 
LPMAPIFORMCONTAINERlpFormContainer= NULL; 
 
hr = CHK_HrOpenFormContainer( 
hFrmReg, lpszProfile, lpszPassword, lpszMsgStore, lpszFolder, 
lppMAPISession, lppFormContainer); 
if( FAILED( hr)) 
RETURN( hr); 
 
    // Initialize return values 
    if( lppMAPISession) 
        *lppMAPISession = NULL; 
 
    *lppFormContainer = NULL; 
 
    if( hFrmReg == HFRMREG_LOCAL) 
    { 
    hr = MAPIOpenLocalFormContainer( &lpFormContainer); 
        if( FAILED( hr)) 
        { 
            INTERNAL_ERROR( TEXT("MAPIOpenLocalFormContainer()"), hr); 
            goto cleanup; 
        } 
    } 
    else 
    { 
        ASSERTERROR( lppMAPISession != NULL, "NULL lppMAPISession passed"); 
    ASSERTERROR( lpszProfile != NULL, "NULL Profile name"); 
 
        hr = MAPILogonEx(  
                NULL, lpszProfile, lpszPassword,  
                MAPI_LOGON_UI | MAPI_NO_MAIL | MAPI_NEW_SESSION,  
                &lpMAPISession); 
        if( FAILED( hr)) 
        {             
            INTERNAL_ERROR( TEXT("MAPILogonEx()"), hr); 
            goto cleanup; 
        } 
 
        if( hFrmReg == HFRMREG_FOLDER) 
        { 
        ASSERTERROR( lpszFolder != NULL, "NULL Folder name"); 
 
        hr = HrOpenMsgStoreFolderByName( lpMAPISession, 
        lpszMsgStore, lpszFolder, &lpFolder); 
        if( hr == EDK_E_NOT_FOUND) 
        { 
                TCHAR    szErrorCode[16] = {0}; 
 
        EventLogMsg( INSTFORM_NOTFOUND_ERROR, 
        1, _itot( hr, szErrorCode, 16), 
        0); 
 
        goto cleanup; 
        } 
        if( FAILED( hr)) { 
                INTERNAL_ERROR( TEXT("HrOpenMsgStoreFolderByName()"), hr); 
        goto cleanup; 
        } 
        } 
 
        // Open form manager interface. 
        hr = MAPIOpenFormMgr( lpMAPISession, &lpFormMgr); 
        if( FAILED( hr)) 
        { 
            INTERNAL_ERROR( TEXT("MAPIOpenFormMgr()"), hr); 
            goto cleanup; 
        } 
 
        // Open appropriate form container. 
        hr = lpFormMgr->OpenFormContainer( hFrmReg, lpFolder, &lpFormContainer); 
        if( FAILED( hr)) 
        { 
            INTERNAL_ERROR( TEXT("IMAPIFormMgr::OpenFormContainer()"), hr); 
            goto cleanup; 
        } 
 
        // Success!  Set return interface pointers. 
        if( lppMAPISession) 
            *lppMAPISession = lpMAPISession; 
    } 
 
*lppFormContainer = lpFormContainer; 
 
cleanup: 
ULRELEASE( lpFolder); 
ULRELEASE( lpFormMgr); 
 
if( FAILED( hr) && lpMAPISession) 
{ 
lpMAPISession->Logoff( 0L, 0L, 0L); 
ULRELEASE( lpMAPISession); 
} 
 
RETURN( hr); 
} 
 
//$--HrSetupAndDoIt()----------------------------------------------------------- 
// Open form container interface, and install or remove. 
// ----------------------------------------------------------------------------- 
 
static HRESULT HrSetupAndDoIt( 
    IN CUserParams& UserParams)     // Parsed parameters from the user. 
{ 
    HRESULThr = NOERROR; 
LPMAPISESSIONlpMAPISession= NULL; 
LPMAPIFORMCONTAINERlpFormContainer= NULL; 
 
    DEBUGPRIVATE( "HrSetupAndDoIt()"); 
 
    // Open appropriate form container interface. 
    hr = HrOpenFormContainer( 
UserParams.m_hFrmReg, 
UserParams.m_pszProfile, UserParams.m_pszPassword, 
UserParams.m_pszMsgStore, UserParams.m_pszFolder, 
&lpMAPISession, &lpFormContainer); 
if( FAILED( hr)) 
goto cleanup; 
 
    if( UserParams.m_fInstall) 
    { 
ULONGulUIFlags = MAPI_DIALOG; 
 
// Shouldn't use MAPI_DIALOG flag if installing to local forms registry. 
if( UserParams.m_hFrmReg == HFRMREG_LOCAL) 
ulUIFlags = 0L; 
 
        hr = lpFormContainer->InstallForm( NULL, ulUIFlags, UserParams.m_pszCfgFile); 
        if( FAILED( hr)) 
        { 
            if( hr == MAPI_E_USER_CANCEL) 
{ 
                EventLogMsg( INSTFORM_USER_CANCEL_ERROR, 
                0, 
                0); 
            } 
            else 
            { 
                LPMAPIERROR lpMAPIError = NULL; 
                HRESULT     hrT = NOERROR; 
 
                hrT = lpFormContainer->GetLastError (hr, 0L, &lpMAPIError); 
 
                if (SUCCEEDED(hrT) && lpMAPIError) 
                { 
EventLogMsg( INSTFORM_EXTENDED_ERROR, 
1, lpMAPIError->lpszError, 
0); 
                    MAPIFREEBUFFER (lpMAPIError); 
                } 
 
                INTERNAL_ERROR( TEXT("IMAPIFormContainer::InstallForm()"), hr); 
 
                hr = HR_LOG( E_FAIL); 
} 
        } 
    } 
    else 
    { 
        hr = lpFormContainer->RemoveForm( UserParams.m_pszMsgClass); 
        if( FAILED( hr) || hr == MAPI_W_PARTIAL_COMPLETION) 
        { 
            if( hr == MAPI_E_NOT_FOUND) 
{ 
                EventLogMsg( INSTFORM_FORM_NOT_FOUND_ERROR, 
                1, UserParams.m_pszMsgClass, 
                0); 
            } 
            else 
{ 
                LPMAPIERROR lpMAPIError = NULL; 
                HRESULT     hrT = NOERROR; 
 
                hrT = lpFormContainer->GetLastError (hr, 0L, &lpMAPIError); 
 
                if (SUCCEEDED(hrT) && lpMAPIError) 
                { 
EventLogMsg( INSTFORM_EXTENDED_ERROR, 
1, lpMAPIError->lpszError, 
0); 
                    MAPIFREEBUFFER (lpMAPIError); 
                } 
 
                INTERNAL_ERROR( TEXT("IMAPIFormContainer::RemoveForm()"), hr); 
 
                hr = HR_LOG( E_FAIL); 
} 
        } 
    } 
 
cleanup: 
ULRELEASE( lpFormContainer); 
 
if( lpMAPISession) 
{ 
lpMAPISession->Logoff( 0L, 0L, 0L); 
ULRELEASE( lpMAPISession); 
} 
 
    RETURN( hr); 
} 
 
//$--main()--------------------------------------------------------------------- 
// See CUserParams::PrintUsage() for user parameters. 
// ----------------------------------------------------------------------------- 
 
int main( int argc, char *argv[]) 
{ 
    HRESULThr = NOERROR; 
BOOLfMAPIInitialized = FALSE; 
BOOLfEventLogOpen = FALSE; 
 
    CUserParams UserParams; 
 
    DEBUGPUBLIC( "main()"); 
 
// Parse the user's parameters. 
    hr = UserParams.HrParseCommandLine( argc, argv); 
    if( hr == EXIT_WARNING || FAILED( hr)) 
        goto cleanup; 
 
    // Initialize MAPI. 
    hr = MAPIInitialize( NULL); 
    if( FAILED( hr)) 
        goto cleanup; 
     
    fMAPIInitialized = TRUE; 
 
    // Open an event logging handle for this application. 
    hr = HrEventOpenLog( 
        lpszAppName,// application name 
        NULL,// executable name (computed) 
        NULL,// event message file (computed) 
        NULL,// parameter message file (this) 
        NULL,// category message file (this) 
        NULL);// event logging handle 
    if( FAILED(hr)) 
    { 
        fprintf( stderr, "ERROR: unable to open event log.\n"); 
        goto cleanup; 
} 
 
fEventLogOpen = TRUE; 
 
    hr = HrSetupAndDoIt( UserParams); 
    if( FAILED( hr)) 
    { 
        printf( "FAILURE! Could not %s form.\n", UserParams.m_fInstall ? "install" : "remove"); 
        goto cleanup; 
    } 
 
    printf( "Form %s successfully.\n", UserParams.m_fInstall ? "installed" : "removed"); 
 
cleanup: 
 
if( fEventLogOpen) 
{ 
    EDKEVENTCOUNT   sEventCount     = {0}; 
        HRESULThrT= NOERROR; 
 
        hrT = HrEventGetCounts(&sEventCount); 
        if( SUCCEEDED( hrT))  
        { 
            // Print the number of errors logged. 
            if (sEventCount.cError == 1) 
                fprintf(stderr, "ERROR: 1 error written to NT event log.\n"); 
            else if (sEventCount.cError > 1) 
                fprintf(stderr, "ERROR: %d errors written to NT event log.\n",  
                    sEventCount.cError); 
 
            // Print the number of warnings logged. 
            if (sEventCount.cWarning == 1) 
                fprintf(stderr, "WARNING: 1 warning written to NT event log.\n"); 
            else if (sEventCount.cWarning > 1) 
                fprintf(stderr, "WARNING: %d warnings written to NT event log.\n",  
                    sEventCount.cWarning); 
        } 
else 
{ 
            fprintf(stderr, "WARNING: unable to get number of errors logged.\n"); 
        } 
 
(void)HrEventCloseLog(); 
    } 
 
if( fMAPIInitialized) 
MAPIUninitialize(); 
 
    return( _nEcFromHr(hr)); 
} 
 
// -----------------------------------------------------------------------------