/**********************************************************************/
/**			  Microsoft Windows/NT			     **/
/**		   Copyright(c) Microsoft Corp., 1991		     **/
/**********************************************************************/

/*
    Install.Cxx

    OLDNAME - NCPDINST.CXX:    Windows/NT Network Control Panel Applet;

	    New product installation and reconfiguration dialogs.

    FILE HISTORY:
	DavidHov    2/9/92    Created

*/

#include "pch.hxx"  // Precompiled header
#pragma hdrstop

static const int MAX_TEMP = 1024;



// inf types
static const WCHAR PSZ_NETADAPTER[]  = L"NetAdapter";
static const WCHAR PSZ_NETSERVICE[]  = L"NetService";
static const WCHAR PSZ_NETPROTOCOL[] = L"NetTransport";
static const WCHAR PSZ_NETWORK[]     = L"Network";
static const WCHAR PSZ_NETPROVIDER[] = L"NetProvider";
static const WCHAR PSZ_NETDRIVER[]   = L"NetDriver";

// services names
const TCHAR * pszWkstaName           = SZ("LanmanWorkstation");

   //  This simple structure contains all that is needed to be remembered
   //   about the origin of the executing slave process and what to do
   //   when it completes.

enum NCPA_ACTION_CTL
{
    NCAC_NoOp    = 0x0000,  // 
    NCAC_Rebind  = 0x0001,  // rebind
    NCAC_Reboot  = 0x0002,  // reboot
    NCAC_Both    = 0x0003,  // reboot and rebind
    NCAC_Refill  = 0x0004,  // refill main listboxes
    NCAC_FillBind= 0x0005,  // refill, rebind
    NCAC_FillBoot= 0x0006,  // refill, reboot
    NCAC_All     = 0x0007   // refill, reboot, rebind.
};


NCPA_ACTION_CTL nacResultControl [ NCFG_FUNC_MAX ] [ NCFG_EC_MAX ] =
{
/** ACTION -->RESULT: SUCCESS      CANCELLED    FAILED       NO EFFECT    REBIND         REBOOT        **/
/*  Remove     */  {  NCAC_All,    NCAC_Refill, NCAC_Refill, NCAC_Refill, NCAC_FillBind, NCAC_FillBoot },
/*  Configure  */  {  NCAC_All,    NCAC_NoOp,   NCAC_NoOp,   NCAC_Refill, NCAC_FillBind, NCAC_FillBoot   },
/*  Update     */  {  NCAC_Both,   NCAC_NoOp,   NCAC_NoOp,   NCAC_NoOp,   NCAC_Rebind,   NCAC_Reboot   },
/*  Bind       */  {  NCAC_NoOp,   NCAC_NoOp,   NCAC_NoOp,   NCAC_NoOp,   NCAC_NoOp,     NCAC_Reboot   },
/*  Install    */  {  NCAC_All,    NCAC_NoOp,   NCAC_NoOp,   NCAC_Refill, NCAC_FillBind, NCAC_FillBoot },
/*  Review     */  {  NCAC_NoOp,   NCAC_NoOp,   NCAC_NoOp,   NCAC_NoOp,   NCAC_NoOp,     NCAC_Reboot   }
};

APIERR errResultControl [ NCFG_EC_MAX ] =
{
    NO_ERROR,                   // success
    IDS_NCPA_SETUP_CANCELLED,   // cancelled
    IDS_NCPA_SETUP_FAILED,      // failed
    NO_ERROR,                   // no_effect
    NO_ERROR,                   // rebind
    NO_ERROR                    // reboot
};


/*******************************************************************

    NAME:       NCP::RunInstaller

    SYNOPSIS:

    ENTRY:

    EXIT:

    RETURNS:

    NOTES:

    HISTORY:

********************************************************************/
BOOL NCP :: RunInstaller ( HWND hwndParent,
                          NLS_STR nlsInfName,
                          NLS_STR nlsInfOption,
                          NLS_STR nlsTitle,
                          NLS_STR nlsPath )
{
    SetupInterpreter siConfig;
    do
    {
        _dwError = ERROR_NOT_ENOUGH_MEMORY ;

        if (!siConfig.Initialize( hwndParent ))
        {
            break;
        }
        if (!siConfig.SetNetShellModes( SIM_INSTALL ))
        {
            break;
        }
        if (_dwError = siConfig.SetNetComponent( nlsInfOption.QueryPch(), nlsInfName.QueryPch() ))
        {
            break;
        }

        // if the path is filled in, use it
        if (nlsPath.QueryTextLength())
        {
            if (!siConfig.IncludeSymbol( PSZ_NETSRCPATH, nlsPath.QueryPch(), TRUE ))
            {
                break;
            }
        }

        if (_dwError = siConfig.Run())
        {
            break;
        }
        _dwError = InfCompleted( siConfig.QueryReturnValue(), NCFG_INSTALL );
    }
    while ( FALSE ) ;

    return ((_dwError == 0) || _fRefill);

}

/*******************************************************************

    NAME:       NCP::RunInstallAndCopy

    SYNOPSIS:

    ENTRY:

    EXIT:

    RETURNS:

    NOTES:

    HISTORY:

********************************************************************/


BOOL NCP :: RunInstallAndCopy( HWND hwndParent,
        HWND hwndNotify,
        PCWSTR pchInfs,
        PCWSTR pchOptions,
        PCWSTR pchText,
        PCWSTR pchDetectInfo,
        PCWSTR pchOemPaths,
        PCWSTR pchSections,
        PCWSTR pszSrcPath ,
        PCWSTR pchRegBases ,
        BOOL   fExpress,
        BOOL   fUnattended,
        PCWSTR pszUnattendFile ,
        SETUP_INSTALL_MODE simMode,
        BOOL   fUpgradeWarn)
{
    SetupInterpreter siConfig;
    do
    {
        _dwError = ERROR_NOT_ENOUGH_MEMORY ;

        if (!siConfig.Initialize( hwndNotify ))
        {
            break;
        }
        if (simMode == SIM_UPDATE)
        {
            if (!siConfig.SetNetShellModes( SIM_INSTALL, SIO_INSTALL ))
            {
                break;
            }
        }
        else
        {
            if (!siConfig.SetNetShellModes( simMode, SIO_INSTALL ))
            {
                break;
            }
        }
        if (!siConfig.SetNetInf( PSZ_NETINSTALLANDCOPYSECTION ))
        {
            break;
        }

        // add the source path
        if (!siConfig.IncludeSymbol( PSZ_NETSRCPATH, pszSrcPath, TRUE ))
        {
            break;
        }

        // add our specific parameters
        if (!siConfig.IncludeSymbol( PSZ_NETOPTIONS, pchOptions ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETINFS, pchInfs ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETTEXT, pchText ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETDETECTINFOS, pchDetectInfo ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETOEMPATHS, pchOemPaths ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETSECTIONS, pchSections ))
        {
            break;
        }

        if (!siConfig.IncludeSymbol( PSZ_NETNOTIFYHWND, (DWORD)hwndNotify, TRUE ))
        {
            break;
        }

        // express mode?
        if (fExpress)
        {
            if (!siConfig.IncludeSymbol( PSZ_NETINSTALLMODE, L"EXPRESS" ))
            {
                break;
            }
        }
        else
        {
            if (!siConfig.IncludeSymbol( PSZ_NETINSTALLMODE, L"CUSTOM" ))
            {
                break;
            }
        }

        // add reg bases, used only for upgrade, though
        if (simMode == SIM_UPDATE)
        {
            if (!siConfig.IncludeSymbol( PSZ_NETREGBASES, pchRegBases ))
            {
                break;
            }
        }

        // whether in upgrade mode
        if (simMode == SIM_UPDATE)
        {
            if (!siConfig.IncludeSymbol( PSZ_NETUPGRADEMODE, L"YES" ))
            {
                break;
            }
        }
        else
        {
            if (!siConfig.IncludeSymbol( PSZ_NETUPGRADEMODE, L"NO" ))
            {
                break;
            }
        }

        // Whether Warnings are to be displayed during 
        // upgrade. Unattended mode will ignore this
        if (fUpgradeWarn)
        {
            if (!siConfig.IncludeSymbol( PSZ_NETUPGRADEWARN, L"YES" ))
            {
                break;
            }
        }
        else
        {
            if (!siConfig.IncludeSymbol( PSZ_NETUPGRADEWARN, L"NO" ))
            {
                break;
            }
        }

        // unattended mode?

        if (simMode == SIM_UPDATE)
        {
            if (!siConfig.IncludeSymbol( PSZ_GUIUNATTENDED, L"NO" ))
            {
                break;
            }
            if (fUnattended)
            {
                if (!siConfig.IncludeSymbol( PSZ_UNATTENDED, L"YES"))
                {
                    break;
                }
            }
            else
            {
                if (!siConfig.IncludeSymbol( PSZ_UNATTENDED, L"NO"))
                {
                    break;
                }
            }
        }
        else
        {
            if (fUnattended)
            {

                if (!siConfig.IncludeSymbol( PSZ_GUIUNATTENDED, L"YES" ))
                {
                    break;
                }
                if (!siConfig.IncludeSymbol( PSZ_UNATTENDED, pszUnattendFile, TRUE ))
                {
                    break;
                }
            }
            else
            {
                if (!siConfig.IncludeSymbol( PSZ_GUIUNATTENDED, L"NO" ))
                {
                    break;
                }
                if (!siConfig.IncludeSymbol( PSZ_UNATTENDED, L"NO" ))
                {
                    break;
                }
            }
        }

        if (_dwError = siConfig.Run( FALSE ))
        {
            break;
        }
        _dwError = InfCompleted( siConfig.QueryReturnValue(), NCFG_INSTALL );
        if (_fRefill)
        {
            // clear the lists
            _bindery.Reset() ;
        }

    }
    while ( FALSE ) ;

    return ((_dwError == 0) || _fRefill);


}

//-------------------------------------------------------------------
//
//
//-------------------------------------------------------------------

BOOL NCP :: RunRemove( HWND hwndParent,
        HWND hwndNotify,
        PCWSTR pchInfs,
        PCWSTR pchOptions,
        PCWSTR pchText,
        PCWSTR pchRegBases)
{
    SetupInterpreter siConfig;
    do
    {
        _dwError = ERROR_NOT_ENOUGH_MEMORY ;

        if (!siConfig.Initialize( hwndNotify ))
        {
            break;
        }
        if (!siConfig.SetNetShellModes( SIM_DEINSTALL, SIO_INSTALL ))
        {
            break;
        }
        if (!siConfig.SetNetInf( PSZ_NETREMOVESECTION ))
        {
            break;
        }

        // add our specific parameters
        if (!siConfig.IncludeSymbol( PSZ_NETOPTIONS, pchOptions ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETINFS, pchInfs ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETTEXT, pchText ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETREGBASES, pchRegBases ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETNOTIFYHWND, (DWORD)hwndNotify, TRUE ))
        {
            break;
        }

        if (_dwError = siConfig.Run( FALSE ))
        {
            break;
        }
        _dwError = InfCompleted( siConfig.QueryReturnValue(), NCFG_REMOVE );
        if (_fRefill)
        {
            // clear the lists
            _bindery.Reset() ;
        }

    }
    while ( FALSE ) ;

    return ((_dwError == 0) || _fRefill);

}

//-------------------------------------------------------------------
//
//
//-------------------------------------------------------------------

//
// build an INF list of network types to request the buffer for
//
void BuildNetTypeInfList( PWSTR pszType, DWORD fNetType )
{
    BOOL fFirst = TRUE;
    lstrcpy( pszType, PSZ_BEGINBRACE );

    if (fNetType & QIFT_ADAPTERS)
    {

        //addParameter( &nlsInfParam, PSZ_NETTYPE, PSZ_NETADAPTER );
        lstrcat( pszType, L"\"" );
        lstrcat( pszType, PSZ_NETADAPTER );
        lstrcat( pszType, L"\"" );
        fFirst = FALSE;
    }
    if (fNetType & QIFT_SERVICES)
    {
        if (!fFirst)
        {
            lstrcat( pszType, PSZ_COMMA );
        }
        // addParameter( &nlsInfParam, PSZ_NETTYPE, PSZ_NETSERVICE );
        lstrcat( pszType, L"\"" );
        lstrcat( pszType, PSZ_NETSERVICE );
        lstrcat( pszType, L"\"" );
        lstrcat( pszType, PSZ_COMMA );

        lstrcat( pszType, L"\"" );
        lstrcat( pszType, PSZ_NETWORK );
        lstrcat( pszType, L"\"" );
        lstrcat( pszType, PSZ_COMMA );

        lstrcat( pszType, L"\"" );
        lstrcat( pszType, PSZ_NETPROVIDER );
        lstrcat( pszType, L"\"" );

        fFirst = FALSE;
    }
    if (fNetType & QIFT_PROTOCOLS)
    {
        if (!fFirst)
        {
            lstrcat( pszType, PSZ_COMMA );
        }
        // addParameter(&nlsInfParam, PSZ_NETTYPE, PSZ_NETPROTOCOL );
        lstrcat( pszType, L"\"" );
        lstrcat( pszType, PSZ_NETPROTOCOL );
        lstrcat( pszType, L"\"" );
        fFirst = FALSE;
    }
    lstrcat( pszType, PSZ_ENDBRACE );
}

/*******************************************************************

    NAME:       NCP::RunUpdateRegOemInfs

    SYNOPSIS:

    ENTRY:

    EXIT:

    RETURNS:

    NOTES:

    HISTORY:

********************************************************************/
/*
const DWORD QIFT_ADAPTERS  = 0x0001;
const DWORD QIFT_PROTOCOLS = 0x0002;
const DWORD QIFT_SERVICES  = 0x0004;
*/


BOOL NCP :: RunUpdateRegOemInfs( HWND hwndParent, DWORD fNetType )
{
    SetupInterpreter siConfig;
    WCHAR pszType[MAX_PATH];
    BOOL fDisableParent = TRUE;
    _dwError = 0;

    do
    {
        BuildNetTypeInfList( pszType, fNetType );

        _dwError = ERROR_NOT_ENOUGH_MEMORY ;

        if (!siConfig.Initialize( hwndParent ))
        {
            break;
        }
        if (!siConfig.SetNetInf( PSZ_NETQUERYCOMPINFSSECTION ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETTYPE, pszType ))
        {
            break;
        }

        // deinstall will skip starting detection
        if (!siConfig.SetNetShellModes( SIM_DEINSTALL, SIO_INSTALL ))
        {
            break;
        }

        // during main install, we don't want to disable the desktop
        //
        if (NULL == hwndParent)
        {
            fDisableParent = FALSE;
        }

        if (_dwError = siConfig.Run( fDisableParent ))
        {
            break;
        }
        _dwError = siConfig.QueryReturnValue();
    }
    while ( FALSE ) ;

    return (_dwError == 0);
}

//-------------------------------------------------------------------
//
//
//-------------------------------------------------------------------

BOOL NCP :: RunConfigureOnInf ( HWND hwndParent,
                          PCWSTR  pszInfName,
                          PCWSTR  pszInfOption,
                          PCWSTR  pszTitle,
                          PCWSTR  pszRegBase )
{
    SetupInterpreter siConfig;
    do
    {

        _dwError = ERROR_NOT_ENOUGH_MEMORY ;

        if (!siConfig.Initialize( hwndParent ))
        {
            break;
        }
        if (!siConfig.SetNetShellModes( SIM_CONFIGURE, SIO_INSTALL ))
        {
            break;
        }
        if (_dwError = siConfig.SetNetComponent( pszInfOption, pszInfName, pszRegBase ))
        {
            break;
        }

        if (_dwError = siConfig.Run())
        {
            break;
        }
        _dwError = InfCompleted( siConfig.QueryReturnValue(), NCFG_CONFIGURE );
    }
    while ( FALSE ) ;

    return ((_dwError == 0) || _fRefill);

}

//-------------------------------------------------------------------
//
//
//
//
//-------------------------------------------------------------------

BOOL NCP::HaveDisk(HWND hwndParent, DWORD fNetType)
{
    SetupInterpreter siConfig;
    WCHAR pszType[MAX_PATH];

    _dwError = 0;

    do
    {
        BuildNetTypeInfList( pszType, fNetType );

        _dwError = ERROR_NOT_ENOUGH_MEMORY ;

        if (!siConfig.Initialize( hwndParent ))
        {
            break;
        }
        if (!siConfig.SetNetInf( PSZ_NETHAVEDISKSECTION ))
        {
            break;
        }
        if (!siConfig.IncludeSymbol( PSZ_NETTYPE, pszType ))
        {
            break;
        }
        if (!siConfig.SetNetShellModes( SIM_INSTALL, SIO_INSTALL ))
        {
            break;
        }

        if (_dwError = siConfig.Run())
        {
            break;
        }
        _dwError = siConfig.QueryReturnValue();
    }
    while ( FALSE ) ;

    return (_dwError == 0);
}
//-------------------------------------------------------------------
//
//
//-------------------------------------------------------------------

static const WCHAR PSZ_INFSETUPKEY[] = L"SOFTWARE\\Microsoft\\Ncpa\\InfOptions";
static const WCHAR PSZ_INFOPTIONVALUE[] = L"OptionList";
static const WCHAR PSZ_INFOPTIONTEXTVALUE[] = L"OptionTextList";

static int RegQueryList( HKEY hkey, PCWSTR pszValue, PWSTR* ppszBuff )
{
    //DWORD dwType = REG_MULTI_SZ;
    DWORD cbBuff = 0;
    PWCHAR pchBuff = NULL;
    LONG lrt;

    // get size of list
    lrt = RegQueryValueEx( hkey, pszValue, NULL, NULL, NULL, &cbBuff );
    if (ERROR_SUCCESS == lrt)
    {

        // new a temp buffer for it
        pchBuff = new WCHAR[cbBuff / sizeof(WCHAR)];

        // get the list
        lrt = RegQueryValueEx( hkey, pszValue, NULL, NULL, (PBYTE)pchBuff, &cbBuff );
        if (ERROR_SUCCESS != lrt)
        {
            delete [] pchBuff;
            pchBuff = NULL;
        }
    }
    *ppszBuff = pchBuff;


    return( cbBuff / sizeof(WCHAR) );
}
//-------------------------------------------------------------------
//
//
//-------------------------------------------------------------------

static INT CountEntries( PWSTR pszList )
{
    PWCHAR pch = pszList;
    INT cstr = 0;

    while (L'\0' != *pch)
    {
        while (L'\0' != *pch)
        {
            pch++;
        }
        pch++;
        cstr++;
    }
    return( cstr );
}
//-------------------------------------------------------------------
//
//
//-------------------------------------------------------------------

static int AppendOptionsToBuff( PWSTR* ppszBuff,
        int cchBuff,
        PWSTR pszName,
        PWSTR pszType,
        HKEY hkeyInf )
{
    HKEY hkey;
    PWCHAR pszOptionList;
    PWCHAR pszOptionTextList;
    int cchNew;
    int cchNewBuff;
    int cstrBuffs;
    int i;
    PWCHAR pszNewBuff;

    if (ERROR_SUCCESS == RegOpenKeyEx( hkeyInf,
            pszType,
            0,
            KEY_READ,
            &hkey ))
    {
        // retrieve option and option text lists from registry
        //
        cchNew = RegQueryList( hkey, PSZ_INFOPTIONVALUE, &pszOptionList );
        cchNew += RegQueryList( hkey, PSZ_INFOPTIONTEXTVALUE, &pszOptionTextList );
        cchNew -= 2; // the sizes returned include double null at end, remove

        // the number of entries we need to duplicate the inf file name
        cstrBuffs = CountEntries( pszOptionList );
        cchNew += cstrBuffs * (lstrlen(pszName) + 1);

        assert( cstrBuffs == CountEntries( pszOptionTextList ) );

        // calc new buff size
        if (cchBuff == 0)
        {
            cchNewBuff = cchNew + 1;
        }
        else
        {
            cchNewBuff = cchBuff + cchNew;
        }
        pszNewBuff = new WCHAR[cchNewBuff];


        PWCHAR pchDest = pszNewBuff;

        // duplicate old buffer
        //
        if (*ppszBuff != NULL )
        {
            PWCHAR pchSrc = *ppszBuff;

            // old buff size includes double null, don't copy it
            cchBuff--;

            // copy old buffer
            for (i=0; i<cchBuff; i++)
            {
                *pchDest = *pchSrc;
                pchDest++;
                pchSrc++;
            }
            delete [] *ppszBuff;
        }

        PWCHAR pchSrcOption = pszOptionList;
        PWCHAR pchSrcOptionText = pszOptionTextList;
        INT cchLen;

        // append new values
        //
        for (i=0; i<cstrBuffs; i++)
        {
            // append option
            lstrcpy( pchDest, pchSrcOption );
            cchLen = lstrlen( pchSrcOption ) + 1;
            pchDest += cchLen;
            pchSrcOption += cchLen;

            // append description
            lstrcpy( pchDest, pchSrcOptionText );
            cchLen = lstrlen( pchSrcOptionText ) + 1;
            pchDest += cchLen;
            pchSrcOptionText += cchLen;

            // append filename
            lstrcpy( pchDest, pszName );
            cchLen = lstrlen( pszName ) + 1;
            pchDest += cchLen;
        }
        // double null terminate the complete list
        *pchDest = L'\0';

        // return the new buff and size
        *ppszBuff = pszNewBuff;
        cchBuff = cchNewBuff;

        // delete option and text lists
        delete [] pszOptionList;
        delete [] pszOptionTextList;

        RegCloseKey( hkey );
    }
    return( cchBuff );
}

//-------------------------------------------------------------------
//
//
//-------------------------------------------------------------------


PWSTR NCP::GetAllOptionsText( DWORD fNetType ) // PCWSTR pszInfType )
{
    DWORD iKeyInf;
    DWORD iKeyType;
    LONG lrt;
    HKEY hkeyInfOptions;
    HKEY hkeyInf;
    WCHAR pszName[MAX_PATH];
    WCHAR pszType[MAX_PATH];
    DWORD cchBuffSize;
    FILETIME FileTime;
    PWSTR pszBuffer = NULL;
    INT cchBuffer = 0;
    HANDLE hFile;
    CPtrList strlRemoveKeys;

    if (ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE,
            PSZ_INFSETUPKEY,
            0,
            KEY_ALL_ACCESS,
            &hkeyInfOptions ))
    {
        //
        // enumerate infs saved in registry
        //
        cchBuffSize = MAX_PATH;
        for ( iKeyInf = 0;
              ERROR_NO_MORE_ITEMS != (lrt = RegEnumKeyEx( hkeyInfOptions,
                       iKeyInf,
                       pszName,
                       &cchBuffSize,
                       NULL,
                       NULL,
                       NULL,
                       &FileTime ) );
              cchBuffSize = MAX_PATH,
              iKeyInf++ )
        {
            // check if file exists, if not, remove reg entry and continue
            hFile = CreateFile( pszName,
                    GENERIC_READ,
                    FILE_SHARE_WRITE,
                    NULL,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,
                    NULL );
            if (INVALID_HANDLE_VALUE == hFile)
            {
                PWSTR pszChild;

                // skip for now, you can not remove sub keys while enuming the key
                // maybe keep a list and delete them latter?
                pszChild = new WCHAR[lstrlen(pszName) + 1];
                lstrcpy( pszChild, pszName );
                strlRemoveKeys.AddTail( pszChild );
            }
            else
            {
                CloseHandle( hFile );
                if (ERROR_SUCCESS == RegOpenKeyEx( hkeyInfOptions,
                        pszName,
                        0,
                        KEY_READ,
                        &hkeyInf ))
                {
                    //
                    // enumerate type saved in registry (should only be one)
                    //
                    cchBuffSize = MAX_PATH;
                    for ( iKeyType = 0;
                          ERROR_NO_MORE_ITEMS != (lrt = RegEnumKeyEx( hkeyInf,
                                   iKeyType,
                                   pszType,
                                   &cchBuffSize,
                                   NULL,
                                   NULL,
                                   NULL,
                                   &FileTime ) );
                          cchBuffSize = MAX_PATH,
                          iKeyType++ )
                    {
                        WCHAR pszTypeOnly[MAX_PATH];
                        BOOL fAppend = FALSE;
                        PWCHAR pchSrc;
                        PWCHAR pchDest;
                        //
                        // don't care about BUS identifier at end
                        //
                        for (pchSrc = pszType, pchDest = pszTypeOnly;
                                (*pchSrc != L'\0') && (*pchSrc != L'.');
                                pchSrc++, pchDest++ )
                        {
                            *pchDest = *pchSrc;
                        }
                        *pchDest = L'\0';

                        // only match requested type
                        if (fNetType & QIFT_ADAPTERS)
                        {
                            fAppend = fAppend ||
                                    (0 == lstrcmpi( PSZ_NETADAPTER, pszTypeOnly ));
                        }
                        if (fNetType & QIFT_SERVICES)
                        {
                            fAppend = fAppend ||
                                    (0 == lstrcmpi( PSZ_NETSERVICE, pszTypeOnly )) ||
                                    (0 == lstrcmpi( PSZ_NETPROVIDER, pszTypeOnly )) ||
                                    (0 == lstrcmpi( PSZ_NETWORK, pszTypeOnly ));
                        }
                        if (fNetType & QIFT_PROTOCOLS)
                        {
                            fAppend = fAppend ||
                                    (0 == lstrcmpi( PSZ_NETPROTOCOL, pszTypeOnly ));

                        }
                        if (fAppend)
                        {
                            cchBuffer = AppendOptionsToBuff( &pszBuffer, cchBuffer, pszName, pszType, hkeyInf );
                        }
                    }
                    RegCloseKey( hkeyInf );
                }
            }
        }

        // now remove those items that have no corrrisponding file (left overs)
        //
        POSITION poslist;
        PWSTR pszRemoveKey;

        poslist = strlRemoveKeys.GetHeadPosition();

        while (NULL != poslist)
        {
            pszRemoveKey = (PWSTR)strlRemoveKeys.GetNext( poslist );
            RegDeleteKeyTree( hkeyInfOptions, pszRemoveKey );
            delete [] pszRemoveKey;
        }
        if (strlRemoveKeys.GetCount())
        {
            strlRemoveKeys.RemoveAll();
        }
        RegCloseKey( hkeyInfOptions );
    }
    return( pszBuffer );
}

/*******************************************************************

    NAME:       NCP::CheckForLanManager

    SYNOPSIS:   See if the LanmanWorkstation service exists.

    ENTRY:      Nothing

    EXIT:       Nothing

    RETURNS:    BOOL TRUE if it is installed, false if not

    NOTES:

    HISTORY:    DavidHov     2/29/93    Created
                MikeMi      May-24-95   Modified to check only

********************************************************************/

BOOL NCP :: CheckForLanManager ()
{
    BOOL fResult = FALSE ;
    BOOL fTempScm = FALSE;

    if ( _pscm == NULL )
    {
        // this will occur if the user does not have admin access rights
        _pscm = new SC_MANAGER( NULL, GENERIC_READ );
        fTempScm = TRUE;
    }

    SC_SERVICE  svcWksta( *_pscm, pszWkstaName, GENERIC_READ ) ;
    fResult = svcWksta.QueryError() != ERROR_SERVICE_DOES_NOT_EXIST;

    if (fTempScm)
    {
        // not needed if the user does not have access
        delete _pscm ;
        _pscm = NULL ;

    }
    return( fResult );
}


/*******************************************************************

    NAME:       NCP::RunConfigurator

    SYNOPSIS:   Start the SETUP process to configure a component.

    ENTRY:

    EXIT:

    RETURNS:

    NOTES:      This function parameterizes a

    HISTORY:

********************************************************************/

BOOL NCP :: RunConfigurator( HWND hwndParent,
        REG_KEY * prnComponent,
        NCPA_CFG_FUNC ecfgFunc )
{
    SetupInterpreter siConfig;
    SETUP_INSTALL_MODE simMode ;
    _dwError = 0;

    switch ( ecfgFunc )
    {
    case NCFG_CONFIGURE:
        simMode = SIM_CONFIGURE ;
        break;

    case NCFG_UPDATE:
        simMode = SIM_UPDATE ;
        break;

    case NCFG_REMOVE:
        simMode = SIM_DEINSTALL ;
        // Make sure we can lock the service controller database
        if ( _pscm )
        {
            if (_dwError = _pscm->Lock())
            {

                break;
            }
            _pscm->Unlock();
        }
        break ;

    case NCFG_BIND:
        simMode = SIM_BIND ;
        break;
/*
    case NCFG_INSTALL:
        simMode = SIM_INSTALL;
        break;
*/
    default:
        UIASSERT( !"Invalid mode passed to NCP::RunConfigurator()" ) ;
        _dwError = ERROR_INVALID_PARAMETER ;
        break ;
    }

    do
    {
        if (_dwError)
        {
            break;
        }

        _dwError = ERROR_NOT_ENOUGH_MEMORY ;

        if (!siConfig.Initialize( hwndParent ))
        {
            break;
        }
        if (!siConfig.SetNetShellModes( simMode ))
        {
            break;
        }
        if (_dwError = siConfig.SetNetComponent( *prnComponent ))
        {
            break;
        }


        if ( simMode == SIM_DEINSTALL )
        {
            //  Product removal:  drain the listboxes, discard old binding data.
            //    This closes all open REG_KEYs, so that product and service
            //    deletion will work.

//            Drain() ;
            _bindery.Reset() ;
            _fRefill = TRUE;
        }

        if (_dwError = siConfig.Run())
        {
            break;
        }
        _dwError = InfCompleted( siConfig.QueryReturnValue(), ecfgFunc );

    }
    while ( FALSE ) ;

    return _dwError == 0 ;
}

//-------------------------------------------------------------------
//
//
//
//
//-------------------------------------------------------------------

DWORD NCP :: InfCompleted( DWORD dwExit, NCPA_CFG_FUNC ecfgFunc )
{

    NCPA_CFG_EXIT_CODE errExit = (NCPA_CFG_EXIT_CODE)dwExit;

    if ( errExit >= NCFG_EC_MAX )
    {
        //  Invalid result: force it to "success"
        errExit = NCFG_EC_SUCCESS ;
    }

    //  Get the action control mask from the table
    NCPA_ACTION_CTL nac = nacResultControl[ ecfgFunc ] [ errExit ] ;

    //  Set for rebooting if necessary.  This allows any review INF to
    //  indicate that a reboot is necessary and "OR" it into the result
    //  so far.

    if ( nac & NCAC_Reboot )
    {
        MustReboot() ;
    }

    if ( nac & NCAC_Rebind )
    {
        _bindery.SetBindState( BND_OUT_OF_DATE_NO_REBOOT ) ;
    }

    _fRefill = (nac & NCAC_Refill) > 0 ;

    return( errResultControl[ errExit ] );
}



// End of NCPDINST.CXX