mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2875 lines
81 KiB
2875 lines
81 KiB
/**********************************************************************/
|
|
/** Microsoft Windows NT **/
|
|
/** Copyright(c) Microsoft Corp., 1992 **/
|
|
/**********************************************************************/
|
|
/*
|
|
BindAlgo.cxx
|
|
|
|
OLDNAME: NCPAPBNDR.CXX:
|
|
|
|
Windows/NT Network Control Panel Applet
|
|
|
|
Binding Determination Algorithm
|
|
|
|
|
|
FILE HISTORY:
|
|
DavidHov 1/2/92 Created
|
|
|
|
*/
|
|
|
|
#include "pch.hxx" // Precompiled header
|
|
#pragma hdrstop
|
|
|
|
#include "utils.h"
|
|
|
|
// The maximum number of dependencies any service can have
|
|
|
|
const INT DEPEND_MAX = 500 ;
|
|
|
|
|
|
#define SERVICE_ACCESS_REQUIRED (GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE)
|
|
|
|
// Constant strings.
|
|
|
|
const TCHAR * pszBindingsQuery = SZ("(makebindstrings)") ;
|
|
const TCHAR * pszBindItem1 = SZ("(bindstring ") ;
|
|
|
|
// WARNING: do not change the following string without changing the
|
|
// token string components immediately following.
|
|
const TCHAR * pszBindItem2 = SZ(" Sif Ifname List Str Expstr)") ;
|
|
const TCHAR * pszVarStr = SZ("Str") ;
|
|
const TCHAR * pszVarExpstr = SZ("Expstr") ;
|
|
const TCHAR * pszVarSif = SZ("Sif") ;
|
|
const TCHAR * pszVarIfname = SZ("Ifname") ;
|
|
|
|
// Numeric constants
|
|
|
|
const ULONG lcbMaxQueryResult = 40000 ;
|
|
const USHORT ucbMaxLine = 300 ;
|
|
const USHORT ucbMaxName = 100 ;
|
|
|
|
#if defined(DEBUG)
|
|
#define DEBUG_VALIDATE Validate()
|
|
#else
|
|
#define DEBUG_VALIDATE
|
|
#endif
|
|
|
|
// Parsing validation macros; see BindItem().
|
|
|
|
#define ParseOk(ptr,type) (ptr->QueryType() == type)
|
|
#define ParseStep(ptr,type) \
|
|
if ( ptr->QueryNext() == NULL \
|
|
|| (ptr = ptr->QueryNext())->QueryType() != type ) break
|
|
#define ParseCheck(ptr,type) \
|
|
if ( ptr->QueryType() != type ) break
|
|
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//
|
|
// UTILITY FUNCTIONS
|
|
//
|
|
//////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
* See if a table of atoms already contains a given atom.
|
|
*/
|
|
static BOOL containsAtom ( HUATOM ahuaTable [], INT cAtoms, HUATOM huaTest )
|
|
{
|
|
INT i ;
|
|
for ( i = 0 ; i < cAtoms && ahuaTable[i] != huaTest ; i++ ) ;
|
|
return i < cAtoms ;
|
|
}
|
|
|
|
|
|
/*
|
|
* Convert a STRLIST to a flat buffer of strings delimited
|
|
* by a null string (double zero). This is the format the
|
|
* Win32 Service Controller accepts for service dependencies.
|
|
*
|
|
* If the passed pointer is NULL, generate an empty list of strings.
|
|
*/
|
|
static TCHAR * dependencyString ( STRLIST * pSlist )
|
|
{
|
|
UINT cchRequired = 2 ;
|
|
TCHAR * pchResult = NULL,
|
|
* pchNext ;
|
|
|
|
if ( pSlist != NULL )
|
|
{
|
|
ITER_STRLIST itSl( *pSlist ) ;
|
|
NLS_STR * pnlsNext ;
|
|
|
|
while ( pnlsNext = itSl.Next() )
|
|
{
|
|
cchRequired += pnlsNext->QueryTextLength() + 1 ;
|
|
}
|
|
}
|
|
|
|
pchResult = new TCHAR [ cchRequired ] ;
|
|
if ( pchResult == NULL )
|
|
return NULL ;
|
|
|
|
pchNext = pchResult ;
|
|
|
|
if ( pSlist != NULL )
|
|
{
|
|
// Add every NLS_STR to the dependency list.
|
|
// Don't copy duplicates.
|
|
|
|
ITER_STRLIST itSl( *pSlist ) ;
|
|
NLS_STR * pnlsNext ;
|
|
|
|
while ( pnlsNext = itSl.Next() )
|
|
{
|
|
ITER_STRLIST itSl2( *pSlist ) ;
|
|
NLS_STR * pnls ;
|
|
|
|
while ( (pnls = itSl2.Next()) != pnlsNext )
|
|
{
|
|
if ( pnlsNext->_stricmp( *pnls ) == 0 )
|
|
break ;
|
|
}
|
|
|
|
// If it's not a duplicate, append it.
|
|
|
|
if ( pnls == pnlsNext )
|
|
{
|
|
::strcpyf( pchNext, pnlsNext->QueryPch() );
|
|
pchNext += pnlsNext->QueryTextLength() ;
|
|
*pchNext++ = 0 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
*pchNext++ = 0 ;
|
|
*pchNext = 0 ; // The second is just for safety
|
|
|
|
return pchResult ;
|
|
}
|
|
|
|
/*
|
|
* Regenerate the given buffer of facts, inserting a
|
|
* CR/LF pair after every fact; this is used to generate
|
|
* a support output file.
|
|
*/
|
|
static TCHAR * addCrLfsToFactBuffer ( const TCHAR * pchFactBuffer )
|
|
{
|
|
int cbBuffer,
|
|
cNl ;
|
|
const TCHAR * pch ;
|
|
TCHAR * pch2,
|
|
* pchTemp ;
|
|
|
|
cbBuffer = ::strlenf( pchFactBuffer ) ;
|
|
|
|
for ( cNl = 0, pch = pchFactBuffer ; *pch ; pch++ )
|
|
{
|
|
if ( *pch == TCH(')') )
|
|
cNl += 2 ;
|
|
}
|
|
|
|
// Allocate the temporary buffer
|
|
|
|
pchTemp = new TCHAR [cbBuffer + cNl + 1] ;
|
|
|
|
if ( pchTemp == NULL )
|
|
{
|
|
return NULL ;
|
|
}
|
|
|
|
// Insert a newline after each right paren (end of fact)
|
|
|
|
for ( pch2 = pchTemp, pch = pchFactBuffer ; *pch ; )
|
|
{
|
|
*pch2++ = *pch ;
|
|
if ( *pch++ == TCH(')') )
|
|
{
|
|
*pch2++ = TCH('\r') ;
|
|
*pch2++ = TCH('\n') ;
|
|
}
|
|
}
|
|
*pch2 = 0 ;
|
|
|
|
return pchTemp ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::WriteLinkageValues
|
|
|
|
SYNOPSIS: Write STRLISTs of binding information to the give
|
|
Linkage key and its subordinate Disabled key.
|
|
|
|
Private.
|
|
|
|
ENTRY: REG_KEY * the Linkage key to update
|
|
Lots of STRLISTs
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: APIERR
|
|
|
|
NOTES: "pslIfs" & "pslDisabledIfs" are NULL if the component
|
|
does not support multiple interfaces.
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
APIERR BINDERY :: WriteLinkageValues (
|
|
REG_KEY * prkLinkage,
|
|
STRLIST * pslBinds,
|
|
STRLIST * pslExports,
|
|
STRLIST * pslRoutes,
|
|
STRLIST * pslIfs,
|
|
STRLIST * pslDisabledBinds,
|
|
STRLIST * pslDisabledExports,
|
|
STRLIST * pslDisabledRoutes,
|
|
STRLIST * pslDisabledIfs )
|
|
{
|
|
APIERR err = prkLinkage->SetValue( RGAS_BIND_VALUE_NAME,
|
|
pslBinds ) ;
|
|
APIERR err2 = prkLinkage->SetValue( RGAS_EXPORT_VALUE_NAME,
|
|
pslExports ) ;
|
|
APIERR err3 = prkLinkage->SetValue( RGAS_ROUTE_VALUE_NAME,
|
|
pslRoutes ) ;
|
|
APIERR err4 = 0 ;
|
|
|
|
if ( pslIfs )
|
|
{
|
|
err4 = prkLinkage->SetValue( RGAS_IF_VALUE_NAME, pslIfs ) ;
|
|
}
|
|
|
|
if ( err == 0 )
|
|
err = err2 ;
|
|
if ( err == 0 )
|
|
err = err3 ;
|
|
if ( err == 0 )
|
|
err = err4 ;
|
|
|
|
// Open or create the \Linkage\Disabled key.
|
|
|
|
REG_KEY * prkDisabled = new REG_KEY( *prkLinkage,
|
|
HUATOM( RGAS_DISABLED_KEY_NAME ) ) ;
|
|
|
|
if ( prkDisabled != NULL
|
|
&& prkDisabled->QueryError() )
|
|
{
|
|
// Key doesn't exist... attempt to create it.
|
|
|
|
REG_KEY_CREATE_STRUCT rkcStruct ;
|
|
|
|
rkcStruct.dwTitleIndex = 0 ;
|
|
rkcStruct.ulOptions = 0 ;
|
|
rkcStruct.ulDisposition = 0 ;
|
|
rkcStruct.regSam = 0 ;
|
|
rkcStruct.pSecAttr = NULL ;
|
|
rkcStruct.nlsClass = RGAS_GENERAL_CLASS ;
|
|
|
|
delete prkDisabled ;
|
|
prkDisabled = new REG_KEY( *prkLinkage,
|
|
HUATOM( RGAS_DISABLED_KEY_NAME ),
|
|
& rkcStruct ) ;
|
|
}
|
|
|
|
if ( prkDisabled != NULL
|
|
&& prkDisabled->QueryError() == 0 )
|
|
{
|
|
prkDisabled->SetValue( RGAS_BIND_VALUE_NAME,
|
|
pslDisabledBinds ) ;
|
|
prkDisabled->SetValue( RGAS_EXPORT_VALUE_NAME,
|
|
pslDisabledExports ) ;
|
|
prkDisabled->SetValue( RGAS_ROUTE_VALUE_NAME,
|
|
pslDisabledRoutes ) ;
|
|
if ( pslDisabledIfs )
|
|
{
|
|
prkDisabled->SetValue( RGAS_IF_VALUE_NAME,
|
|
pslDisabledIfs ) ;
|
|
}
|
|
}
|
|
|
|
delete prkDisabled ;
|
|
return err ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::DeleteLinkageValues
|
|
|
|
SYNOPSIS: Delete all old linkage information from the given
|
|
Linkage key and its subordinate Disabled key. This
|
|
is used in preparation for storing the new information.
|
|
|
|
Private.
|
|
|
|
ENTRY: REG_KEY * the Linkage key to clear
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: APIERR
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
APIERR BINDERY :: DeleteLinkageValues ( REG_KEY * prkLinkage )
|
|
{
|
|
HUATOM huaBind( RGAS_BIND_VALUE_NAME ) ;
|
|
HUATOM huaExport( RGAS_EXPORT_VALUE_NAME ) ;
|
|
HUATOM huaRoute( RGAS_ROUTE_VALUE_NAME ) ;
|
|
HUATOM huaIf( RGAS_IF_VALUE_NAME ) ;
|
|
|
|
REG_KEY rkDisabled( *prkLinkage, HUATOM( RGAS_DISABLED_KEY_NAME ) ) ;
|
|
|
|
APIERR err = prkLinkage->DeleteValue( huaBind );
|
|
APIERR err2 = prkLinkage->DeleteValue( huaExport );
|
|
APIERR err3 = prkLinkage->DeleteValue( huaRoute );
|
|
APIERR err4 = prkLinkage->DeleteValue( huaIf );
|
|
|
|
if ( err == 0 )
|
|
err = err2 ;
|
|
if ( err == 0 )
|
|
err = err3 ;
|
|
if ( err == 0 )
|
|
err = err4 ;
|
|
|
|
if ( rkDisabled.QueryError() == 0 )
|
|
{
|
|
rkDisabled.DeleteValue( huaBind );
|
|
rkDisabled.DeleteValue( huaExport );
|
|
rkDisabled.DeleteValue( huaRoute );
|
|
rkDisabled.DeleteValue( huaIf );
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::SetBindState
|
|
|
|
SYNOPSIS: Directly control the state of the binding information
|
|
|
|
Private.
|
|
|
|
ENTRY:
|
|
|
|
EXIT:
|
|
|
|
RETURNS:
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
|
|
BIND_STATE BINDERY :: SetBindState ( BIND_STATE bstNew )
|
|
{
|
|
BIND_STATE bstOld = _bindState ;
|
|
_bindState = bstNew ;
|
|
|
|
#if defined(TRACE)
|
|
if ( (bstOld >= BND_CURRENT || bstOld < BND_UPDATED)
|
|
&& (bstNew == BND_OUT_OF_DATE_NO_REBOOT || bstNew == BND_OUT_OF_DATE) )
|
|
{
|
|
TRACEEOL(SZ("NCPA/BNDR: setting rebind"));
|
|
}
|
|
#endif
|
|
|
|
return bstOld ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::Reset
|
|
|
|
SYNOPSIS: Destroy all intermediate or previous results of
|
|
Registry scanning.
|
|
|
|
ENTRY: Nothing
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: APIERR if failure
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
APIERR BINDERY :: Reset ()
|
|
{
|
|
// Delete all previously allocated information about the components
|
|
|
|
_bindState = BND_NOT_LOADED ;
|
|
|
|
delete _paCompAssoc ;
|
|
_paCompAssoc = NULL ;
|
|
|
|
ResetLists();
|
|
|
|
_nlsFacts = SZ("") ;
|
|
|
|
return NERR_Success ;
|
|
}
|
|
|
|
APIERR BINDERY :: ResetLists ()
|
|
{
|
|
// Delete all previously allocated lists of components
|
|
|
|
delete _pcdlAdapters ;
|
|
_pcdlAdapters = NULL ;
|
|
|
|
delete _pcdlTransports ;
|
|
_pcdlTransports = NULL ;
|
|
|
|
delete _pcdlServices ;
|
|
_pcdlServices = NULL ;
|
|
|
|
delete _pcdlDrivers ;
|
|
_pcdlDrivers = NULL ;
|
|
|
|
return NERR_Success ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::GetAdapterList
|
|
BINDERY::GetProductList
|
|
|
|
SYNOPSIS: Recreate the lists of products and adapters from
|
|
the configuration Registry.
|
|
|
|
ENTRY: Nothing
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: BOOL FALSE if failure
|
|
|
|
NOTES: Destroys the old info, if any.
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
BOOL BINDERY :: GetAdapterList ( BOOL fIncludeHidden )
|
|
{
|
|
delete _pcdlAdapters ;
|
|
_pcdlAdapters = ListOfNetAdapters( fIncludeHidden ) ;
|
|
return _pcdlAdapters != NULL ;
|
|
}
|
|
|
|
BOOL BINDERY :: GetServiceList ( BOOL fIncludeHidden )
|
|
{
|
|
delete _pcdlServices ;
|
|
_pcdlServices = ListOfNetServices( fIncludeHidden ) ;
|
|
return _pcdlServices != NULL ;
|
|
}
|
|
|
|
BOOL BINDERY :: GetTransportList ( BOOL fIncludeHidden )
|
|
{
|
|
delete _pcdlTransports ;
|
|
_pcdlTransports = ListOfNetTransports( fIncludeHidden ) ;
|
|
return _pcdlTransports != NULL ;
|
|
}
|
|
|
|
BOOL BINDERY :: GetDriverList ( BOOL fIncludeHidden )
|
|
{
|
|
delete _pcdlDrivers ;
|
|
_pcdlDrivers = ListOfNetDrivers( fIncludeHidden ) ;
|
|
return _pcdlDrivers != NULL ;
|
|
}
|
|
|
|
COMPONENT_DLIST *BINDERY :: GetNetProductList ( BOOL fIncludeHidden )
|
|
{
|
|
return (ListOfNetProducts( fIncludeHidden , LNT_PRODUCT)) ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::Init
|
|
|
|
SYNOPSIS: Extract all the lists from the Registry, perform
|
|
the associations and generate the SProlog facts.
|
|
|
|
This operates as follows:
|
|
|
|
find all products and adapters (COMPONENT_DLISTs);
|
|
|
|
find all services (COMPONENT_DLIST);
|
|
|
|
convert NetRules data to SProlog facts;
|
|
|
|
associate each service with its original product
|
|
or adapter;
|
|
|
|
consult the generated facts;
|
|
|
|
ENTRY: Nothing
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: APIERR if failure.
|
|
|
|
NOTES: An error will occur if there is not at least one
|
|
hardware network adapter in the Registry.
|
|
|
|
These case labels must be executed in order, since each
|
|
creates data structures upon which the successors depend.
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
APIERR BINDERY :: Init ( BIND_STAGE bindStStart, BIND_STAGE bindStEnd )
|
|
{
|
|
TCHAR chLine [ ucbMaxLine ] ;
|
|
INT bindNext ;
|
|
APIERR err = 0 ;
|
|
|
|
for ( bindNext = bindStStart;
|
|
err == 0 && bindNext <= bindStEnd ;
|
|
bindNext++ )
|
|
{
|
|
switch ( bindNext )
|
|
{
|
|
case BST_RESET:
|
|
// Discard all old information
|
|
Reset();
|
|
|
|
// Reset the SProlog interpreter
|
|
ResetInterpreter() ;
|
|
|
|
break ;
|
|
|
|
case BST_LIST_ADAPTERS:
|
|
ASSERT( _pcdlAdapters == NULL ) ;
|
|
ASSERT( _paCompAssoc == NULL ) ;
|
|
|
|
_pcdlAdapters = ListOfNetAdapters() ;
|
|
if ( _pcdlAdapters == NULL )
|
|
{
|
|
err = _lastErr ;
|
|
}
|
|
else
|
|
if ( _pcdlAdapters->QueryNumElem() == 0 )
|
|
{
|
|
}
|
|
break ;
|
|
|
|
case BST_LIST_DRIVERS:
|
|
ASSERT( _pcdlDrivers == NULL ) ;
|
|
ASSERT( _paCompAssoc == NULL ) ;
|
|
|
|
_pcdlDrivers = ListOfNetDrivers() ;
|
|
if ( _pcdlDrivers == NULL )
|
|
{
|
|
err = _lastErr ;
|
|
}
|
|
else if ( _pcdlDrivers->QueryNumElem() == 0 )
|
|
{
|
|
}
|
|
break ;
|
|
|
|
case BST_LIST_TRANSPORTS:
|
|
ASSERT( _pcdlTransports == NULL ) ;
|
|
ASSERT( _paCompAssoc == NULL ) ;
|
|
|
|
_pcdlTransports = ListOfNetTransports() ;
|
|
if ( _pcdlTransports == NULL )
|
|
{
|
|
err = _lastErr ;
|
|
}
|
|
else if ( _pcdlTransports->QueryNumElem() == 0 )
|
|
{
|
|
}
|
|
break ;
|
|
|
|
case BST_LIST_SERVICES:
|
|
ASSERT( _pcdlServices == NULL ) ;
|
|
ASSERT( _paCompAssoc == NULL ) ;
|
|
|
|
_pcdlServices = ListOfNetServices() ;
|
|
if ( _pcdlServices == NULL )
|
|
{
|
|
err = _lastErr ;
|
|
}
|
|
else if ( _pcdlServices->QueryNumElem() == 0 )
|
|
{
|
|
}
|
|
break ;
|
|
|
|
case BST_CONVERT_FACTS:
|
|
ASSERT( _paCompAssoc == NULL ) ;
|
|
|
|
// ConvertFacts() will generate its own Event Log
|
|
// records if this fails.
|
|
|
|
err = ConvertFacts() ;
|
|
break;
|
|
|
|
case BST_CONSULT_RULES:
|
|
{
|
|
TCHAR * pszRules = NULL ;
|
|
|
|
err = IDS_NCPA_BNDR_CNSLT_BASE ;
|
|
|
|
if ( _pszRuleFileName )
|
|
{
|
|
// Use the disk file
|
|
DISKFILE dfRules( _pszRuleFileName ) ;
|
|
|
|
if ( dfRules.QueryError() == 0
|
|
&& dfRules.QueryOpen() )
|
|
{
|
|
pszRules = (TCHAR *) dfRules.Load( FALSE ) ;
|
|
if ( pszRules == NULL )
|
|
break ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Use the rule data in memory
|
|
pszRules = _pszRuleData ;
|
|
}
|
|
|
|
if ( _queryEngine.ConsultData( pszRules ) )
|
|
{
|
|
err = 0 ;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
// Delete the memory copy of file data
|
|
if ( pszRules != _pszRuleData )
|
|
delete pszRules ;
|
|
}
|
|
break ;
|
|
|
|
case BST_CONSULT_FACTS:
|
|
if ( ! _queryEngine.ConsultData( _nlsFacts.QueryPch() ) )
|
|
{
|
|
err = IDS_NCPA_BNDR_CNSLT_FACT ;
|
|
|
|
}
|
|
break ;
|
|
|
|
case BST_QUERY_BINDINGS:
|
|
if ( ! _queryEngine.QueryData( pszBindingsQuery, chLine, sizeof chLine ) )
|
|
{
|
|
err = IDS_NCPA_BNDR_QURY_FAIL ;
|
|
}
|
|
break ;
|
|
}
|
|
}
|
|
|
|
// See if there's an event to be logged
|
|
|
|
return err ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::LogQueryFailure
|
|
|
|
SYNOPSIS: Create an event log record when a serious SProlog
|
|
failure occurs. The entire generated fact set is
|
|
written to either a temporary file or the event log
|
|
(if creating the temporary file fails).
|
|
|
|
Private.
|
|
|
|
ENTRY: DWORD dwLogToFile message number if
|
|
file was used
|
|
DWORD dwLogToElog message number if
|
|
event log was used
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: Nothing
|
|
|
|
NOTES: Resulting temporary file is written to the
|
|
System32\Config directory; its prefix is "NCPFCT".
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
VOID BINDERY :: LogQueryFailure ( DWORD dwLogToFile, DWORD dwLogToElog )
|
|
{
|
|
TCHAR tchTempFileName [MAX_PATH] ;
|
|
const TCHAR * pszPath = SZ(".\\CONFIG") ;
|
|
const TCHAR * pszPrefix = SZ("NCP") ;
|
|
BOOL fOk = FALSE ;
|
|
|
|
if ( ::GetTempFileName( pszPath,
|
|
pszPrefix,
|
|
0,
|
|
tchTempFileName ) )
|
|
{
|
|
DISKFILE dfFacts( tchTempFileName, OF_WRITE ) ;
|
|
|
|
TCHAR * pszFactsWithCrLf = addCrLfsToFactBuffer( _nlsFacts.QueryPch() ) ;
|
|
|
|
if ( fOk = pszFactsWithCrLf != NULL && dfFacts.QueryOpen() )
|
|
{
|
|
dfFacts.Write( pszFactsWithCrLf, ::strlenf( pszFactsWithCrLf ) ) ;
|
|
}
|
|
|
|
delete pszFactsWithCrLf ;
|
|
}
|
|
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::Bind
|
|
|
|
SYNOPSIS: Run the binding generation algorithm and generate
|
|
ARRAY_COMP_ASSOC. This operates as follows:
|
|
|
|
query the SProlog engine to generate all bind
|
|
strings;
|
|
|
|
walk the list of services; at each item call
|
|
BindItem() to query for the bind strings
|
|
and add them to the service's value items.
|
|
|
|
ENTRY: Nothing
|
|
|
|
EXIT: Nothing. If successful, ARRAY_COMP_ASSOC is fully
|
|
generated.
|
|
|
|
RETURNS: APIERR if failure.
|
|
|
|
CAVEATS: Init() member MUST have been called.
|
|
|
|
NOTES: The SProlog code MUST be self-cleaning; that is,
|
|
any steps necessary to remove the results of older queries
|
|
from the internal database must be performed as part
|
|
of the predicate's initialization functions, since no
|
|
explicit "clean up" queries are executed here.
|
|
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
|
|
APIERR BINDERY :: Bind ()
|
|
{
|
|
APIERR err = NERR_Success ;
|
|
|
|
REQUIRE( _paCompAssoc != NULL ) ;
|
|
|
|
int i,
|
|
cmax = _paCompAssoc->QueryCount(),
|
|
cok ;
|
|
|
|
// Iterate over the component association array, querying
|
|
// the binding information for each. A component is not
|
|
// required to have bindings.
|
|
|
|
for ( cok = i = 0 ; i < cmax ; i++ )
|
|
{
|
|
APIERR itemErr = BindItem( i ) ;
|
|
cok += itemErr == NERR_Success
|
|
|| itemErr == IDS_NCPA_BNDR_QURY_FAIL ;
|
|
|
|
// Mark hidden bindings
|
|
|
|
MarkHidden( i ) ;
|
|
|
|
// Sort the bindings into historical sequence.
|
|
|
|
SortBindings( i ) ;
|
|
}
|
|
if ( cok != cmax )
|
|
{
|
|
err = IDS_NCPA_BNDR_QURY_FAIL ;
|
|
}
|
|
|
|
// Sort all component bindings into "historical" sequence
|
|
if ( err == 0 )
|
|
{
|
|
err = RestoreBindOrdering() ;
|
|
}
|
|
|
|
DEBUG_VALIDATE ; // Debugging only: check EVERYTHING!
|
|
|
|
// Suppress any bindings previously suppressed
|
|
AuditBindings( FALSE ) ;
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::BindItem
|
|
|
|
SYNOPSIS: Using the 'itemNo'th component of the component
|
|
association array (_paCompAssoc), perform a single
|
|
query which yields all computed bindings between this
|
|
component and any others.
|
|
|
|
Each binding is represented by a COMP_BINDING, which
|
|
contains the generated binding string to be written
|
|
into the Registry. Also, it contains an SLIST of
|
|
the names encountered along the path from the given
|
|
component to the final adapter.
|
|
|
|
ENTRY: int itemNo index to item be checked
|
|
|
|
EXIT: nothing
|
|
|
|
RETURNS: APIERR if failure
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
|
|
APIERR BINDERY :: BindItem ( int itemNo )
|
|
{
|
|
TCHAR chLine [ ucbMaxLine ] ;
|
|
TCHAR * pchResult ;
|
|
COMP_ASSOC * pcassoc = & (*_paCompAssoc)[itemNo] ;
|
|
CFG_RULE_SET ruleSet ;
|
|
CFG_RULE_NODE * prnode,
|
|
* prndev,
|
|
* prnbind,
|
|
* prniftok,
|
|
* prnifstr ;
|
|
COMP_BINDING * pcbBinding ;
|
|
APIERR err = IDS_NCPA_BNDR_QURY_FAIL ;
|
|
|
|
// Check to see if we successfully matched this component
|
|
// to a service. If not, ignore any result associated with it.
|
|
|
|
if ( pcassoc->_prnService == NULL )
|
|
{
|
|
NLS_STR nlsName ;
|
|
|
|
pcassoc->_prnSoftHard->QueryName( & nlsName ) ;
|
|
|
|
|
|
TRACEEOL( SZ("NCPA/BIND: Skipping bindings for ")
|
|
<< pcassoc->_huaDevName.QueryText()
|
|
<< SZ(", no service match") ) ;
|
|
|
|
return IDS_NCPA_BNDR_QURY_FAIL ;
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
int iParseStep = 0 ; // Debugging
|
|
#define SetParseStep(n) { iParseStep = n ; }
|
|
#else
|
|
#define SetParseStep(n)
|
|
#endif
|
|
|
|
::TstrConcat( chLine, sizeof chLine,
|
|
pszBindItem1,
|
|
pcassoc->_huaDevName.QueryText(),
|
|
pszBindItem2,
|
|
NULL ) ;
|
|
|
|
pchResult = new TCHAR [ lcbMaxQueryResult ] ;
|
|
if ( pchResult == NULL )
|
|
return ERROR_NOT_ENOUGH_MEMORY ;
|
|
|
|
//
|
|
// Run the query "(bindstring productName Sif Ifname List Str Expstr)"
|
|
//
|
|
// Since "Sif", "Ifname", "Str" and "Expstr" are Prolog variables
|
|
// (start with upper-case letter), each result will appear as:
|
|
//
|
|
// Sif = <secondary i/f name> <new line>
|
|
// Ifname = "interface name" <new line>
|
|
// List = (devname1 devname2 ...) <new line>
|
|
// Str = "first bind string" <new line>
|
|
// Expstr = "first export string" <new line> (end of first binding)
|
|
// Sif = <secondary i/f name> <new line> (start of new binding)
|
|
// Ifname = "interface name" <new line>
|
|
// List = (devname3 devname4 ...) <new line>
|
|
// Str = "Second bind string" <new line>
|
|
// Expstr = "second export string" <new line> (end of second binding)
|
|
//
|
|
|
|
if ( _queryEngine.QueryData( chLine,
|
|
pchResult,
|
|
lcbMaxQueryResult ) )
|
|
{
|
|
// Parse the resulting buffer into the CFG_RULE_SET
|
|
|
|
if ( ruleSet.Parse( pchResult, PARSE_CTL_RSP_SYNTAX ) == 0 )
|
|
{
|
|
// Top-level result is formed as a list of tokens.
|
|
|
|
prnode = ruleSet.QueryList() ;
|
|
SetParseStep( 1 ) ;
|
|
if ( ParseOk(prnode,CRN_NIL) )
|
|
{
|
|
// Iterate the binding info, creating bindings as we go.
|
|
|
|
while ( prnode = prnode->QueryNext() )
|
|
{
|
|
err = IDS_NCPA_BNDR_QURY_PARSE_FAIL ;
|
|
|
|
// Locate the interface token
|
|
|
|
SetParseStep( 2 );
|
|
ParseCheck(prnode,CRN_VAR);
|
|
SetParseStep( 3 );
|
|
ParseStep(prnode,CRN_EQUIV);
|
|
SetParseStep( 4 );
|
|
ParseStep(prnode,CRN_ATOM);
|
|
prniftok = prnode ;
|
|
|
|
// Locate the interface name string
|
|
|
|
SetParseStep( 5 );
|
|
ParseStep(prnode,CRN_VAR);
|
|
SetParseStep( 6 );
|
|
ParseStep(prnode,CRN_EQUIV);
|
|
SetParseStep( 7 );
|
|
ParseStep(prnode,CRN_STR);
|
|
prnifstr = prnode ;
|
|
|
|
// Locate the device path list and isolate
|
|
// its first element-- the bind target
|
|
// VAR,EQUIV,LIST
|
|
|
|
SetParseStep( 8 );
|
|
ParseStep(prnode,CRN_VAR);
|
|
SetParseStep( 9 );
|
|
ParseStep(prnode,CRN_EQUIV);
|
|
SetParseStep( 10 );
|
|
ParseStep(prnode,CRN_LIST);
|
|
|
|
// Save a pointer to the device path list
|
|
prndev = prnode->QueryList() ;
|
|
|
|
SetParseStep( 11 );
|
|
ParseCheck(prndev,CRN_NIL);
|
|
SetParseStep( 12 );
|
|
ParseStep(prndev,CRN_ATOM);
|
|
|
|
// Locate the binding string-- VAR,EQUIV,STR
|
|
|
|
SetParseStep( 13 );
|
|
ParseStep(prnode,CRN_VAR);
|
|
SetParseStep( 14 );
|
|
ParseStep(prnode,CRN_EQUIV);
|
|
SetParseStep( 15 );
|
|
ParseStep(prnode,CRN_STR);
|
|
|
|
// Save a pointer to the binding string
|
|
prnbind = prnode ;
|
|
|
|
// Locate the export string-- VAR,EQUIV,STR
|
|
|
|
SetParseStep( 16 );
|
|
ParseStep(prnode,CRN_VAR);
|
|
SetParseStep( 17 );
|
|
ParseStep(prnode,CRN_EQUIV);
|
|
SetParseStep( 18 );
|
|
ParseStep(prnode,CRN_STR);
|
|
|
|
// Create the binding; set it to "active"
|
|
|
|
SetParseStep( 19 );
|
|
pcbBinding = AddBinding( itemNo,
|
|
prnbind->QueryAtom().QueryText(),
|
|
prnode->QueryAtom().QueryText(),
|
|
prniftok->QueryAtom(),
|
|
prnifstr->QueryAtom().QueryText() );
|
|
if ( pcbBinding == NULL )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
pcbBinding->SetState( TRUE );
|
|
pcbBinding->SetLastState( TRUE ) ;
|
|
|
|
// Add all the binding path atoms to the list
|
|
|
|
do
|
|
{
|
|
err = IDS_NCPA_BNDR_QURY_PARSE_FAIL ;
|
|
SetParseStep( 20 );
|
|
ParseCheck(prndev,CRN_ATOM) ;
|
|
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
SetParseStep( 21 );
|
|
if ( ! pcbBinding->AddBindToName( prndev->QueryAtom() ) )
|
|
break ;
|
|
err = 0 ;
|
|
}
|
|
while ( prndev = prndev->QueryNext() ) ;
|
|
|
|
err = 0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete pchResult ;
|
|
|
|
#if defined(DEBUG)
|
|
if ( err != 0 && err != IDS_NCPA_BNDR_QURY_FAIL )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BNDITEM: item ") << itemNo
|
|
<< SZ(" bind item error = ") << (int) err
|
|
<< SZ(" at step ") << iParseStep << SZ(".") ) ;
|
|
}
|
|
#endif
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::AddBinding
|
|
|
|
SYNOPSIS: Add a single binding string to the DLIST of binding
|
|
strings.
|
|
|
|
ENTRY: int itemNo index to item in COMP_ASSOC array
|
|
const TCHAR * pszBindString generated binding string
|
|
const TCHAR * pszExportString generated export string
|
|
|
|
EXIT: nothing
|
|
|
|
RETURNS: APIERR if failure
|
|
|
|
NOTES: Each element of COMP_ASSOC contains a DLIST of
|
|
COMP_BINDING. This member function allocates a new
|
|
one and attaches it to the linked list.
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
|
|
COMP_BINDING * BINDERY :: AddBinding (
|
|
int itemNo,
|
|
const TCHAR * pszBindString,
|
|
const TCHAR * pszExportString,
|
|
HUATOM huaInterface,
|
|
const TCHAR * pszInterfaceName )
|
|
{
|
|
COMP_BINDING * pcbnd = new COMP_BINDING( pszBindString,
|
|
pszExportString,
|
|
huaInterface,
|
|
pszInterfaceName );
|
|
|
|
if ( pcbnd )
|
|
{
|
|
// Verify that the COMP_BINDING constructed properly
|
|
|
|
if ( pcbnd->QueryBindString() != NULL
|
|
&& pcbnd->QueryExportString() != NULL
|
|
&& pcbnd->QueryIfString() != NULL )
|
|
{
|
|
// It's OK; append it to the binding list
|
|
|
|
COMP_ASSOC * pCompAssoc = & (*_paCompAssoc)[itemNo] ;
|
|
pCompAssoc->_dlcbBinds.Append( pcbnd );
|
|
|
|
// Check for an alternate interface: name different
|
|
// from primary device name; set flag if so.
|
|
|
|
if ( pCompAssoc->_huaDevName != huaInterface )
|
|
{
|
|
pcbnd->SetFlag( CBNDF_ALT_IF ) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// It failed; delete it.
|
|
|
|
delete pcbnd ;
|
|
pcbnd = NULL ;
|
|
}
|
|
}
|
|
return pcbnd ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::FindComponent
|
|
|
|
SYNOPSIS: Given an (atom) device name, return the index into
|
|
the ARRAY_COMP_ASSOC which defines the named device.
|
|
|
|
ENTRY: HUATOM huaDevName atomized name of device
|
|
|
|
EXIT: nothing
|
|
|
|
RETURNS: int index of item in ARRAY_COMP_ASSOC
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
int BINDERY :: FindComponent ( HUATOM huaDevName )
|
|
{
|
|
int iComp = 0,
|
|
iCompMax = _paCompAssoc->QueryCount() ;
|
|
|
|
COMP_ASSOC * pCompAssoc = & (*_paCompAssoc)[iComp] ;
|
|
|
|
for ( ; pCompAssoc->_huaDevName != huaDevName ; )
|
|
{
|
|
if ( iComp >= iCompMax )
|
|
break ;
|
|
pCompAssoc = & (*_paCompAssoc)[++iComp] ;
|
|
}
|
|
|
|
return iComp < iCompMax ? iComp : -1 ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::Validate
|
|
|
|
SYNOPSIS: DEBUGGING. Iterate the component association array.
|
|
For each binding, traverse the list of device atoms
|
|
in the binding path and validate that each one exists
|
|
in the array.
|
|
|
|
ENTRY:
|
|
|
|
EXIT:
|
|
|
|
RETURNS:
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
|
|
BOOL BINDERY :: Validate ()
|
|
{
|
|
int iComp,
|
|
iCompMax,
|
|
iAtom,
|
|
cTried = 0,
|
|
cFound = 0 ;
|
|
COMP_BINDING * pCompBinding ;
|
|
HUATOM * phuaNext ;
|
|
const NLS_STR * pnlsDev,
|
|
* pnlsDev2 ;
|
|
|
|
// For each compoent ---
|
|
|
|
for ( iComp = 0, iCompMax = _paCompAssoc->QueryCount() ;
|
|
iComp < iCompMax ;
|
|
iComp++ )
|
|
{
|
|
// For each binding ---
|
|
|
|
COMP_ASSOC * pCompAssoc = & (*_paCompAssoc)[iComp];
|
|
ITER_DL_OF( COMP_BINDING ) itBind( pCompAssoc->_dlcbBinds ) ;
|
|
|
|
pnlsDev = pCompAssoc->_huaDevName.QueryNls() ;
|
|
|
|
while ( pCompBinding = itBind.Next() )
|
|
{
|
|
// For each atom in the binding path ---
|
|
|
|
for ( iAtom = 0 ;
|
|
phuaNext = pCompBinding->QueryBindToName( iAtom ) ;
|
|
iAtom++ )
|
|
{
|
|
pnlsDev2 = phuaNext->QueryNls() ;
|
|
cTried++ ;
|
|
cFound += FindComponent( *phuaNext ) >= 0 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(TRACE)
|
|
if ( cTried != cFound )
|
|
{
|
|
TRACEEOL( "NCPA/BIND: Validate failed; tried "
|
|
<< cTried << "components; found " << cFound );
|
|
}
|
|
#endif
|
|
return cTried == cFound ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::BindingsAltered
|
|
|
|
SYNOPSIS: Return TRUE if the bindings are not in their
|
|
last state.
|
|
|
|
ENTRY: BOOL fReset TRUE if bindings should
|
|
be reset
|
|
BOOL fToLastState (only if fReset is TRUE)
|
|
if TRUE, bindings will
|
|
be reset to "last" state,
|
|
not "current" state.
|
|
EXIT:
|
|
|
|
RETURNS:
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
|
|
BOOL BINDERY :: BindingsAltered ( BOOL fReset, BOOL fToLastState )
|
|
{
|
|
INT iComp, iAltered = 0 ;
|
|
COMP_ASSOC * pComp ;
|
|
COMP_BINDING * pBind ;
|
|
|
|
// If there's no component association array, exit.
|
|
|
|
if ( _paCompAssoc == NULL )
|
|
return FALSE ;
|
|
|
|
for ( iComp = 0 ; iComp < _paCompAssoc->QueryCount() ; iComp++ )
|
|
{
|
|
pComp = & (*_paCompAssoc)[iComp] ;
|
|
|
|
ITER_DL_OF( COMP_BINDING ) itb( pComp->_dlcbBinds ) ;
|
|
|
|
while ( pBind = itb.Next() )
|
|
{
|
|
iAltered += pBind->QueryLastState() != pBind->QueryState() ;
|
|
if ( fReset )
|
|
{
|
|
if ( fToLastState )
|
|
pBind->SetState( pBind->QueryLastState() ) ;
|
|
else
|
|
pBind->SetLastState( pBind->QueryState() ) ;
|
|
|
|
}
|
|
}
|
|
}
|
|
return iAltered > 0 ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::ServiceNeeded
|
|
|
|
SYNOPSIS: Given an index into the ARRAY_COMP_ASSOC,
|
|
return TRUE if the component is required to support
|
|
another component (i.e., is mentioned in its
|
|
binding information).
|
|
|
|
ENTRY: INT iComp index of the component
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: TRUE if component is required
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
|
|
BOOL BINDERY :: ServiceNeeded ( INT iComp )
|
|
{
|
|
ASSERT( _paCompAssoc != NULL ) ;
|
|
|
|
INT iCompMax = _paCompAssoc->QueryCount(),
|
|
iNext,
|
|
iAtom,
|
|
cUsed = 0 ;
|
|
HUATOM huaDevName = (*_paCompAssoc)[iComp]._huaDevName ;
|
|
|
|
for ( iNext = 0 ; iNext < iCompMax ; iNext++ )
|
|
{
|
|
COMP_ASSOC * pComp = & (*_paCompAssoc)[iNext] ;
|
|
ITER_DL_OF( COMP_BINDING ) itBind( pComp->_dlcbBinds ) ;
|
|
COMP_BINDING * pBind ;
|
|
HUATOM * phuaDev ;
|
|
|
|
// Don't check against ourself
|
|
if ( iNext = iComp )
|
|
continue ;
|
|
|
|
// Iterate every atom of every binding
|
|
for ( ; pBind = itBind.Next() ; )
|
|
{
|
|
// Skip disabled bindings
|
|
if ( ! pBind->QueryState() )
|
|
continue ;
|
|
|
|
for ( iAtom = 0 ;
|
|
phuaDev = pBind->QueryBindToName( iAtom++ ) ; )
|
|
{
|
|
if ( huaDevName == *phuaDev )
|
|
cUsed++ ;
|
|
}
|
|
}
|
|
}
|
|
return cUsed > 0 ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::GenerateDependencies
|
|
|
|
SYNOPSIS: Generate the service dependency list from the COMP_ASSOC
|
|
data structure. Write the result to the Registry,
|
|
and set the state of the service accordingly.
|
|
|
|
ENTRY: INT iComp index of the component in
|
|
ARRAY_COMP_INDEX.
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: APIERR error code, if any.
|
|
|
|
NOTES: The algorithm is as follows.
|
|
|
|
Find the "OtherDependencies" value, if any. If found,
|
|
use it as the starting STRLIST; otherwise, allocate a
|
|
new (empty) one.
|
|
|
|
The pointer to the COMP_ASSOC structure is obtained.
|
|
If it doesn't have a service, bail out.
|
|
|
|
Use an array of pointers to required components.
|
|
|
|
Iterate over the DLIST_OF_COMP_BINDING.
|
|
For each atom, see if its component is already in
|
|
the dependency array; if not, add it.
|
|
|
|
Create am empty STRLIST for the dependency REG_MULTI_SZ
|
|
value.
|
|
|
|
Walk the array of dependencies once for each class
|
|
of COMP_USE_TYPE. Add the service name corresponding
|
|
to each dependency for DRIVERs, TRANSPORTs, and finally
|
|
services.
|
|
|
|
Replace the original STRLIST of dependencies for each
|
|
component with its newly constructed STRLIST.
|
|
|
|
|
|
HISTORY: DavidHov 3/1/92 Created
|
|
DavidHov 4/26/92 Converted to use Groups and
|
|
REG_MULTI_SZ
|
|
|
|
********************************************************************/
|
|
APIERR BINDERY :: GenerateDependencies (
|
|
INT iComp,
|
|
REG_KEY * prkSvc,
|
|
REG_KEY * prkLinkage )
|
|
{
|
|
STRLIST * pslistDepend = NULL ;
|
|
APIERR err = 0;
|
|
COMP_ASSOC * apCompDepend [ DEPEND_MAX ] ;
|
|
HUATOM ahuaDepend [ DEPEND_MAX ] ;
|
|
HUATOM huaGroupOrService ;
|
|
INT iDep = 0,
|
|
iDepNext,
|
|
iDepAdded = 0,
|
|
iDepAtom ;
|
|
REG_VALUE_INFO_STRUCT rviStruct ;
|
|
|
|
UIASSERT( _paCompAssoc != NULL && iComp < _paCompAssoc->QueryCount() ) ;
|
|
|
|
COMP_ASSOC * pComp = & (*_paCompAssoc)[ iComp ],
|
|
* pCompNeeded ;
|
|
|
|
// Delete any older dependency list.
|
|
|
|
delete pComp->_pSlDepend ;
|
|
pComp->_pSlDepend = NULL ;
|
|
|
|
// See if there are "OtherDependencies". If not, allocate
|
|
// the STRLIST ourselves. Thus, the "others", if any, are first.
|
|
|
|
if ( prkLinkage->QueryValue( RGAS_OTHER_DEPEND_NAME,
|
|
& pComp->_pSlDepend ) )
|
|
{
|
|
pComp->_pSlDepend = new STRLIST ;
|
|
if ( pComp->_pSlDepend == NULL )
|
|
return ERROR_NOT_ENOUGH_MEMORY ;
|
|
}
|
|
|
|
// Iterate the bindings, adding new elements to "apCompDepend[]"
|
|
|
|
COMP_BINDING * pBind ;
|
|
|
|
ITER_DL_OF( COMP_BINDING ) itBind( pComp->_dlcbBinds ) ;
|
|
|
|
// For each binding...
|
|
|
|
TRACEEOL( SZ("NCPA/DEPEND: generate dependencies for ")
|
|
<< pComp->_huaServiceName.QueryText() ) ;
|
|
|
|
DEBUG_VALIDATE ; // Debugging only: check EVERYTHING!
|
|
|
|
for ( ; err == 0 && (pBind = itBind.Next()) ; )
|
|
{
|
|
HUATOM * phuaDevice ;
|
|
|
|
// If this binding is inactive, skip it.
|
|
if ( ! pBind->QueryState() )
|
|
continue ;
|
|
|
|
// For the first device atom in the binding...
|
|
|
|
if ( phuaDevice = pBind->QueryBindToName( 0 ) )
|
|
{
|
|
INT iCompNeeded = FindComponent( *phuaDevice ) ;
|
|
if ( iCompNeeded >= 0 )
|
|
{
|
|
// See if it's already been added to the list
|
|
|
|
pCompNeeded = & (*_paCompAssoc)[iCompNeeded] ;
|
|
|
|
for ( iDepNext = 0 ; iDepNext < iDep ; iDepNext++ )
|
|
{
|
|
if ( apCompDepend[iDepNext] == pCompNeeded )
|
|
break ;
|
|
}
|
|
|
|
if ( iDepNext >= iDep )
|
|
{
|
|
// A new dependency; add it to the array
|
|
|
|
if ( iDep >= DEPEND_MAX )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
}
|
|
else
|
|
{
|
|
apCompDepend[ iDep++ ] = pCompNeeded ;
|
|
|
|
TRACEEOL( SZ("NCPA/DEPN: ")
|
|
<< pComp->_huaServiceName.QueryText()
|
|
<< SZ(" depends upon ")
|
|
<< pCompNeeded->_huaServiceName.QueryText() ) ;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UIASSERT( ! "Unable to locate component by device name" ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// We now have an array of pointers to all the dependent products.
|
|
// Walk the array, building the string in the order of DRIVERS,
|
|
// TRANSPORTS, SERVICES.
|
|
|
|
if ( err == 0 )
|
|
{
|
|
INT cuseType = CUSE_DRIVER ;
|
|
|
|
for ( iDepAtom = 0 ; err == 0 && cuseType > CUSE_NONE ; --cuseType )
|
|
{
|
|
for ( iDepNext = 0 ; err == 0 && iDepNext < iDep ; iDepNext++ )
|
|
{
|
|
COMP_ASSOC * pCompDepend = apCompDepend[iDepNext] ;
|
|
|
|
COMP_USE_TYPE cuseTypeDep = pCompDepend->_cuseType ;
|
|
|
|
// Check if this is the type being handled this pass
|
|
|
|
if ( cuseTypeDep == cuseType )
|
|
{
|
|
// See if we should generate any dependencies
|
|
if ( (cuseTypeDep == CUSE_TRANSPORT && pComp->QueryFlag( CMPASF_XPORT_NO_DEPEND ) )
|
|
|| (cuseTypeDep == CUSE_DRIVER && pComp->QueryFlag( CMPASF_DRIVER_NO_DEPEND ) ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check the type of the dependency. If it's a driver
|
|
// or transport, check to see if the service wants group
|
|
// names or service names for its dependencies.
|
|
|
|
BOOL fUseGroup = (cuseTypeDep == CUSE_TRANSPORT && pComp->QueryFlag( CMPASF_XPORT_GROUPS ) )
|
|
|| (cuseTypeDep == CUSE_DRIVER && pComp->QueryFlag( CMPASF_DRIVER_GROUPS ) ) ;
|
|
|
|
huaGroupOrService = fUseGroup ? pCompDepend->_huaGroupName
|
|
: pCompDepend->_huaServiceName ;
|
|
|
|
//
|
|
// If we generate any dependencies on PNP_TDI, they must
|
|
// be changed to TDI.
|
|
//
|
|
|
|
if ( !::stricmpf(huaGroupOrService.QueryText(), RGAS_VALUE_PNP_TDI ) )
|
|
{
|
|
huaGroupOrService = HUATOM( RGAS_VALUE_TDI );
|
|
}
|
|
|
|
//
|
|
// If it's the correct type and its group or name is not
|
|
// already in the array, add it.
|
|
//
|
|
if ( ! containsAtom( ahuaDepend, iDepAtom, huaGroupOrService ) )
|
|
{
|
|
NLS_STR * pnlsNext = new NLS_STR ;
|
|
BOOL fIsGroup = fUseGroup
|
|
&& ( pCompDepend->_huaGroupName
|
|
!= pCompDepend->_huaServiceName );
|
|
|
|
if ( pnlsNext == NULL )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
}
|
|
else
|
|
{
|
|
// Construct the service name; if it's a group, prefix it
|
|
// with the "+" character.
|
|
|
|
if ( fIsGroup )
|
|
pnlsNext->AppendChar( RGAC_SERVICE_GROUP_PREFIX ) ;
|
|
|
|
pnlsNext->Append( *huaGroupOrService.QueryNls() ) ;
|
|
|
|
// If it's OK, mark the dependent service as "autostart"
|
|
// and add the composed string to the dependency list
|
|
// and add its atom to the "already processed" atom array.
|
|
|
|
if ( (err = pnlsNext->QueryError()) == 0 )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BNDR: Dependency for ")
|
|
<< pComp->_huaServiceName.QueryText()
|
|
<< SZ(" = ")
|
|
<< huaGroupOrService.QueryText() );
|
|
|
|
ahuaDepend[iDepAtom++] = huaGroupOrService ;
|
|
|
|
err = pComp->_pSlDepend->Append( pnlsNext ) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( err )
|
|
{
|
|
TRACEEOL( SZ("NCPA/DEPN: Dependency generation FAILED for ")
|
|
<< pComp->_huaServiceName.QueryText() );
|
|
|
|
delete pComp->_pSlDepend ;
|
|
pComp->_pSlDepend = NULL ;
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::UpdateServices
|
|
|
|
SYNOPSIS: Update the service start type based upon
|
|
the results of the binding operation
|
|
|
|
ENTRY: SC_MANAGER * pScManager
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: APIERR
|
|
|
|
NOTES: Walk through the component array. For each component
|
|
which mapped to a service, check its "autostart" setting;
|
|
if FALSE, mark the service as DISABLED, since it has
|
|
no binding information. Write this info and the
|
|
dependency list to the Registry.
|
|
|
|
"_pSlDepend" is created by GenerateDependencies(); it will
|
|
be NULL for adapters.
|
|
|
|
If the SC_MANAGER key is NULL, just use the Registry.
|
|
This may occur during installation.
|
|
|
|
This routine continues on in the face of error. If any occur,
|
|
only the first error is reported. All are stored into their
|
|
respective COMP_ASSOC structures, provided that no previous
|
|
error has occured against that component.
|
|
|
|
HISTORY: DavidHov 4/27/92 Created
|
|
DavidHov 5/26/92 Added SC_MANAGER provisions
|
|
|
|
********************************************************************/
|
|
APIERR BINDERY :: UpdateServices ( SC_MANAGER * pScManager, HWND hwndNotifyParent )
|
|
{
|
|
APIERR err = 0,
|
|
errLast = 0 ;
|
|
COMP_ASSOC * pComp ;
|
|
INT iComp,
|
|
iCompMax = _paCompAssoc->QueryCount() ;
|
|
|
|
ASSERT( pScManager != NULL ) ;
|
|
|
|
for ( iComp = 0 ;
|
|
iComp < iCompMax ;
|
|
iComp++ )
|
|
{
|
|
SC_SERVICE * pScService = NULL ;
|
|
TCHAR * pchDependencies = NULL ;
|
|
|
|
pComp = & (*_paCompAssoc)[ iComp ] ;
|
|
|
|
UIASSERT( pComp != NULL );
|
|
|
|
|
|
|
|
// No key, no update. Ditto for adapters.
|
|
|
|
if ( pComp->_prnService == NULL
|
|
|| pComp->_rncType == RGNT_ADAPTER )
|
|
{
|
|
continue ;
|
|
}
|
|
|
|
TRACEEOL( SZ("NCPA/BIND: Update service dependencies for ")
|
|
<< pComp->_huaServiceName.QueryText() ) ;
|
|
|
|
errLast = 0 ;
|
|
|
|
// lock the sc manager
|
|
if ( pScManager->Lock() == NERR_Success )
|
|
{
|
|
do // Pseudo-loop for breakout
|
|
{
|
|
pScService = new SC_SERVICE( *pScManager,
|
|
pComp->_huaServiceName.QueryText(),
|
|
SERVICE_ACCESS_REQUIRED ) ;
|
|
|
|
if ( pScService == NULL )
|
|
{
|
|
errLast = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
if ( errLast = pScService->QueryError() )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BNDR: cannot open service [")
|
|
<< pComp->_huaServiceName.QueryText()
|
|
<< SZ("] error ")
|
|
<< errLast ) ;
|
|
break ;
|
|
}
|
|
|
|
pchDependencies = dependencyString( pComp->_pSlDepend ) ;
|
|
if ( pchDependencies == NULL )
|
|
{
|
|
errLast = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
errLast = pScService->ChangeConfig( SERVICE_NO_CHANGE,
|
|
SERVICE_NO_CHANGE,
|
|
SERVICE_NO_CHANGE,
|
|
NULL,
|
|
NULL,
|
|
pchDependencies );
|
|
#if defined(DEBUG)
|
|
if ( errLast )
|
|
{
|
|
|
|
TRACEEOL( SZ("NCPA/BNDR: ChangeConfig() failed for service [")
|
|
<< pComp->_huaServiceName.QueryText()
|
|
<< SZ("] error ")
|
|
<< errLast ) ;
|
|
}
|
|
#endif
|
|
}
|
|
while ( FALSE ) ;
|
|
|
|
// unlock the scmanager
|
|
pScManager->Unlock();
|
|
}
|
|
|
|
delete pchDependencies ;
|
|
delete pScService ;
|
|
|
|
if ( errLast )
|
|
{
|
|
// Log the fact that we failed to update this service.
|
|
|
|
NLS_STR nlsSvcName ;
|
|
|
|
pComp->_prnService->QueryName( & nlsSvcName );
|
|
|
|
|
|
if ( pComp->_errSvcUpdate == 0 )
|
|
pComp->_errSvcUpdate = errLast ;
|
|
if ( err == 0 )
|
|
err = errLast ;
|
|
}
|
|
|
|
if (NULL != hwndNotifyParent)
|
|
{
|
|
// tell the UI to move meter
|
|
PostProgressPos( hwndNotifyParent, PGI_BINDSTORE, iComp + iCompMax );
|
|
}
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::RegenerateAllDependencies
|
|
|
|
SYNOPSIS: After bindings review, audit the bindings in the
|
|
Registry, mark the newly deactivated ones. If any
|
|
have been altered, rerun the dependency generation
|
|
routines.
|
|
|
|
|
|
ENTRY: SC_MANAGER * pScManager used to update services
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: APIERR if failure
|
|
|
|
NOTES: Components whose linkage keys cannot be opened
|
|
are left alone.
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
APIERR BINDERY :: RegenerateAllDependencies ( SC_MANAGER * pScManager )
|
|
{
|
|
if ( ! AuditBindings( TRUE ) )
|
|
{
|
|
TRACEEOL( SZ("NCPA/DEPN: dependency regeneration unnecessary") ) ;
|
|
return NO_ERROR ;
|
|
}
|
|
|
|
// Something has changed. Regenerate and update the
|
|
// dependencies.
|
|
|
|
APIERR err = 0 ;
|
|
COMP_ASSOC * pComp ;
|
|
NLS_STR nlsLinkageName( RGAS_LINKAGE_NAME ) ;
|
|
INT iComp,
|
|
iCompMax = _paCompAssoc->QueryCount() ;
|
|
|
|
TRACEEOL( SZ("NCPA/DEPN: regenerating dependencies") ) ;
|
|
|
|
for ( iComp = 0 ;
|
|
iComp < iCompMax ;
|
|
iComp++ )
|
|
{
|
|
pComp = & (*_paCompAssoc)[ iComp ] ;
|
|
|
|
REG_KEY rkLinkage( *pComp->_prnService, nlsLinkageName ) ;
|
|
|
|
if ( rkLinkage.QueryError() )
|
|
{
|
|
continue ;
|
|
}
|
|
|
|
err = GenerateDependencies( iComp,
|
|
pComp->_prnService,
|
|
& rkLinkage ) ;
|
|
if ( err )
|
|
break ;
|
|
}
|
|
|
|
// If things are OK, update the services.
|
|
|
|
if ( err == 0 )
|
|
{
|
|
err = UpdateServices( pScManager ) ;
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::ApplyBindings
|
|
|
|
SYNOPSIS: Write the bindings into the Registry.
|
|
|
|
ENTRY:
|
|
|
|
EXIT:
|
|
|
|
RETURNS:
|
|
|
|
NOTES: Along with writing the binding strings into the
|
|
"Linkage" key of each Service, dependency analysis
|
|
is done and dependency info is altered according
|
|
to usage.
|
|
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
|
|
APIERR BINDERY :: ApplyBindings ( SC_MANAGER * pScManager, HWND hwndNotifyParent )
|
|
{
|
|
COMP_ASSOC * pComp = NULL ;
|
|
COMP_BINDING * pBind ;
|
|
INT iComp,
|
|
iCompMax = _paCompAssoc->QueryCount(),
|
|
cBinds,
|
|
cActiveBindings ;
|
|
|
|
APIERR err = 0,
|
|
errUpdate = 0 ;
|
|
|
|
NLS_STR nlsLinkageName( RGAS_LINKAGE_NAME ) ;
|
|
|
|
REG_KEY * prkLinkage = NULL ;
|
|
|
|
ASSERT( pScManager != NULL ) ;
|
|
|
|
DEBUG_VALIDATE ; // Debugging only: check EVERYTHING!
|
|
|
|
for ( iComp = 0 ;
|
|
iComp < iCompMax ;
|
|
iComp++ )
|
|
{
|
|
pComp = & (*_paCompAssoc)[ iComp ] ;
|
|
pComp->_errSvcUpdate = 0 ;
|
|
|
|
|
|
UIASSERT( pComp != NULL );
|
|
|
|
UIASSERT( pComp->_prnService != NULL ) ;
|
|
|
|
if ( pComp->_rncType == RGNT_ADAPTER )
|
|
{
|
|
// Hardware adapters receive neither bindings nor dependencies.
|
|
|
|
continue ; // On to the next component.
|
|
}
|
|
|
|
//
|
|
// If this is an NDIS or PNP_TDI driver, we must make sure it is
|
|
// autostart. This is because for NT 4.0, PNP-aware transports no
|
|
// longer have a dependency on the NDIS group.
|
|
|
|
if (( pComp->_rncType == RGNT_DRIVER
|
|
&& !::stricmpf(pComp->_huaGroupName.QueryText(), RGAS_VALUE_NDIS))
|
|
|| ( pComp->_rncType == RGNT_TRANSPORT
|
|
&& !::stricmpf(pComp->_huaGroupName.QueryText(), RGAS_VALUE_PNP_TDI)))
|
|
{
|
|
DWORD dwStartType;
|
|
if (pComp->_prnService->QueryValue( RGAS_START_VALUE_NAME, & dwStartType ) == 0)
|
|
{
|
|
if (dwStartType == SERVICE_DEMAND_START)
|
|
{
|
|
pComp->_prnService->SetValue( RGAS_START_VALUE_NAME,
|
|
SERVICE_AUTO_START ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
prkLinkage = new REG_KEY( *pComp->_prnService, nlsLinkageName ) ;
|
|
|
|
if ( prkLinkage == NULL )
|
|
{
|
|
pComp->_errSvcUpdate = ERROR_NOT_ENOUGH_MEMORY ;
|
|
continue ;
|
|
}
|
|
|
|
if ( pComp->_errSvcUpdate = prkLinkage->QueryError() )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BIND: Linkage key open err: ")
|
|
<< pComp->_errSvcUpdate
|
|
<< SZ(", component ")
|
|
<< pComp->_huaDevName.QueryText() ) ;
|
|
continue ;
|
|
}
|
|
|
|
DEBUG_VALIDATE ; // Debugging only: check EVERYTHING!
|
|
|
|
// Reset all the Linkage key values so as not to leave
|
|
// erroneous information in the Registry in case of error
|
|
|
|
if ( err = DeleteLinkageValues( prkLinkage ) )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BIND: Linkage value reset error: ")
|
|
<< err
|
|
<< SZ(", component ")
|
|
<< pComp->_huaDevName.QueryText() );
|
|
}
|
|
|
|
if ( (err = GenerateDependencies( iComp,
|
|
pComp->_prnService,
|
|
prkLinkage )) == 0 )
|
|
{
|
|
// Iterate the bindings, adding each bind or export string to
|
|
// the proper STRLIST
|
|
|
|
ITER_DL_OF( COMP_BINDING ) itBind( pComp->_dlcbBinds ) ;
|
|
STRLIST strBindList,
|
|
strExportList,
|
|
strRouteList,
|
|
strIfList,
|
|
strDisabledBindList,
|
|
strDisabledExportList,
|
|
strDisabledRouteList,
|
|
strDisabledIfList ;
|
|
|
|
enum BL_TYPE
|
|
{ BL_Active,
|
|
BL_Bind = 0,
|
|
BL_Export,
|
|
BL_Route,
|
|
BL_If,
|
|
BL_Disabled
|
|
} blIndex ;
|
|
|
|
// CODEWORK: CFront won't allow an initialized array of
|
|
// local references, so do it by hand.
|
|
|
|
STRLIST * apStrList [BL_Disabled*2] ;
|
|
|
|
apStrList[BL_Active+BL_Bind] = & strBindList ;
|
|
apStrList[BL_Active+BL_Export] = & strExportList ;
|
|
apStrList[BL_Active+BL_Route] = & strRouteList ;
|
|
apStrList[BL_Active+BL_If] = & strIfList ;
|
|
apStrList[BL_Disabled+BL_Bind] = & strDisabledBindList ;
|
|
apStrList[BL_Disabled+BL_Export] = & strDisabledExportList ;
|
|
apStrList[BL_Disabled+BL_Route] = & strDisabledRouteList ;
|
|
apStrList[BL_Disabled+BL_If] = & strDisabledIfList ;
|
|
|
|
// Build up STRLISTs of the bind and export strings and
|
|
// the route strings
|
|
|
|
for ( cBinds = cActiveBindings = 0 ;
|
|
(err == 0) && (pBind = itBind.Next()) ;
|
|
cBinds++ )
|
|
{
|
|
cActiveBindings += pBind->QueryState() ;
|
|
|
|
NLS_STR * pnlsBind = new NLS_STR( pBind->QueryBindString() ) ;
|
|
NLS_STR * pnlsExport = new NLS_STR( pBind->QueryExportString() ) ;
|
|
NLS_STR * pnlsIf = new NLS_STR( pBind->QueryIfString() ) ;
|
|
NLS_STR * pnlsRoute = ServiceRouteList( pBind ) ;
|
|
|
|
if ( pnlsBind == NULL
|
|
|| pnlsExport == NULL
|
|
|| pnlsRoute == NULL
|
|
|| pnlsIf == NULL )
|
|
{
|
|
delete pnlsBind ;
|
|
delete pnlsExport ;
|
|
delete pnlsRoute ;
|
|
delete pnlsIf ;
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
|
|
blIndex = pBind->QueryState()
|
|
? BL_Active
|
|
: BL_Disabled ;
|
|
|
|
err = apStrList[blIndex+BL_Route]->Append( pnlsRoute ) ;
|
|
|
|
if ( (err == 0) && (err = pnlsBind->QueryError()) == 0 )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BIND: Add binding to service ")
|
|
<< pComp->_huaServiceName.QueryText()
|
|
<< SZ(" = ")
|
|
<< pnlsBind->QueryPch()
|
|
<< SZ(", state = ")
|
|
<< pBind->QueryState() ) ;
|
|
|
|
// Append the binding string to the STRLIST
|
|
err = apStrList[blIndex+BL_Bind]->Append( pnlsBind ) ;
|
|
}
|
|
|
|
if ( (err == 0) && (err = pnlsExport->QueryError()) == 0 )
|
|
{
|
|
// Append the export string to the STRLIST
|
|
err = apStrList[blIndex+BL_Export]->Append( pnlsExport ) ;
|
|
}
|
|
|
|
if ( (err == 0) && (err = pnlsIf->QueryError()) == 0 )
|
|
{
|
|
// Append the interface string to the STRLIST
|
|
err = apStrList[blIndex+BL_If]->Append( pnlsIf ) ;
|
|
}
|
|
}
|
|
|
|
// If ok, apply the lists as REG_MULTI_SZs;
|
|
|
|
if ( err == 0 )
|
|
{
|
|
STRLIST * pslIfList = NULL ;
|
|
STRLIST * pslDisIfList = NULL ;
|
|
|
|
// Write the "Interfaces" information if the component
|
|
// defines multiple interfaces.
|
|
|
|
if ( pComp->QueryFlag( CMPASF_MULTIPLE_INTERFACES ) )
|
|
{
|
|
pslIfList = & strIfList ;
|
|
pslDisIfList = & strDisabledIfList ;
|
|
}
|
|
|
|
err = WriteLinkageValues( prkLinkage,
|
|
& strBindList,
|
|
& strExportList,
|
|
& strRouteList,
|
|
pslIfList,
|
|
& strDisabledBindList,
|
|
& strDisabledExportList,
|
|
& strDisabledRouteList,
|
|
pslDisIfList ) ;
|
|
if ( err )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BIND:Linkage value update error: ")
|
|
<< err
|
|
<< SZ(", component ")
|
|
<< pComp->_huaDevName.QueryText() );
|
|
|
|
NLS_STR nlsSvcName ;
|
|
|
|
pComp->_prnService->QueryName( & nlsSvcName );
|
|
|
|
}
|
|
}
|
|
#if defined(DEBUG)
|
|
if ( err )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BIND:Binding value add error: ")
|
|
<< err
|
|
<< SZ(", component ")
|
|
<< pComp->_huaDevName.QueryText() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACEEOL( SZ("NCPA/BIND:Dependency add error: ")
|
|
<< err
|
|
<< SZ(", component ")
|
|
<< pComp->_huaDevName.QueryText() );
|
|
#endif
|
|
}
|
|
|
|
pComp->_errSvcUpdate = err ;
|
|
|
|
delete prkLinkage ;
|
|
prkLinkage = NULL ;
|
|
|
|
// tell the UI to move meter, and use the finding text
|
|
PostProgressPos( hwndNotifyParent, PGI_BINDSTORE, iComp );
|
|
|
|
}
|
|
|
|
delete prkLinkage ;
|
|
|
|
// Report the first error which occurred during bindings update
|
|
|
|
_nlsLastName = SZ("");
|
|
err = 0 ;
|
|
pComp = NULL ;
|
|
|
|
if ( pComp = ServiceInError() )
|
|
{
|
|
err = pComp->_errSvcUpdate ;
|
|
}
|
|
|
|
// The bindings are applied and the dependencies generated.
|
|
// Update the dependencies for all involved services, regardless
|
|
// of any error which may have occurred.
|
|
|
|
errUpdate = UpdateServices( pScManager, hwndNotifyParent ) ;
|
|
|
|
if ( err == 0 && errUpdate != 0 )
|
|
{
|
|
// Dependency update failed somewhere. Report the
|
|
// first such error which occurred.
|
|
|
|
err = errUpdate ;
|
|
if ( pComp = ServiceInError() )
|
|
{
|
|
err = pComp->_errSvcUpdate ;
|
|
}
|
|
}
|
|
|
|
if ( err && pComp )
|
|
{
|
|
pComp->_prnService->QueryName( & _nlsLastName ) ;
|
|
}
|
|
|
|
return _lastErr = err ;
|
|
}
|
|
|
|
|
|
// Find the first component which had an error during service update.
|
|
// Return NULL if no service is in error.
|
|
|
|
COMP_ASSOC * BINDERY :: ServiceInError ()
|
|
{
|
|
COMP_ASSOC * pComp ;
|
|
INT iComp,
|
|
iCompMax = _paCompAssoc->QueryCount() ;
|
|
|
|
for ( iComp = 0 ;
|
|
iComp < iCompMax ;
|
|
iComp++ )
|
|
{
|
|
pComp = & (*_paCompAssoc)[ iComp ] ;
|
|
if ( pComp->_errSvcUpdate )
|
|
return pComp ;
|
|
}
|
|
return NULL ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::ServiceRouteList
|
|
|
|
SYNOPSIS: Convert a binding's atom list to an NLS_STR of
|
|
service names separated by spaces.
|
|
|
|
ENTRY: const COMP_BINDING * pcmpBind the binding
|
|
const COMP_ASSOC * pCompAssoc optional pointer
|
|
to component info
|
|
|
|
EXIT:
|
|
|
|
RETURNS: NLS_STR * or NULL if unsuccessful
|
|
|
|
NOTES: The route through the protocol tower is maintained
|
|
in the a binding as an SLIST of HUATOMs. This routine
|
|
dereferences each HUATOM to its proper service name
|
|
and builds an NLS_STR of these names delimited by
|
|
double quotes.
|
|
|
|
If the 'pCompAssoc' pointer is non-NULL, the name of the
|
|
service represented by that COMP_ASSOC prefixes the
|
|
resulting string.
|
|
|
|
HISTORY: DavidHov 7/28/92 Created
|
|
|
|
********************************************************************/
|
|
NLS_STR * BINDERY :: ServiceRouteList (
|
|
const COMP_BINDING * pcmpBind,
|
|
const COMP_ASSOC * pCompAssocOwner )
|
|
{
|
|
INT iAtom, iComp ;
|
|
HUATOM * phuaNext ;
|
|
const NLS_STR * pnlsService ;
|
|
COMP_ASSOC * pCompAssoc ;
|
|
NLS_STR * pnlsRoute = new NLS_STR ;
|
|
BOOL fFirst = TRUE ;
|
|
|
|
if ( pnlsRoute == NULL )
|
|
return NULL ;
|
|
|
|
// If the COMP_ASSOC pointer was given, prefix the string
|
|
// with the name of the service for that component (the owner
|
|
// of the binding).
|
|
|
|
if ( pCompAssocOwner )
|
|
{
|
|
pnlsRoute->Append( SZ("\"") ) ;
|
|
pnlsRoute->Append( pCompAssocOwner->_huaServiceName.QueryText() ) ;
|
|
pnlsRoute->Append( SZ("\"") ) ;
|
|
fFirst = FALSE ;
|
|
}
|
|
|
|
for ( iAtom = 0 ;
|
|
phuaNext = ((COMP_BINDING *)pcmpBind)->QueryBindToName( iAtom ) ;
|
|
iAtom++ )
|
|
{
|
|
iComp = FindComponent( *phuaNext ) ;
|
|
if ( iComp < 0 )
|
|
break ;
|
|
|
|
if ( fFirst )
|
|
{
|
|
fFirst = FALSE ;
|
|
}
|
|
else
|
|
{
|
|
pnlsRoute->Append( SZ(" ") ) ;
|
|
}
|
|
|
|
// Cfront didn't like a complex expression, so
|
|
// break it up into stages...
|
|
|
|
pCompAssoc = & (*_paCompAssoc)[iComp] ;
|
|
|
|
pnlsRoute->Append( SZ("\"") ) ;
|
|
|
|
pnlsService = pCompAssoc->_huaServiceName.QueryNls() ;
|
|
|
|
pnlsRoute->Append( *pnlsService ) ;
|
|
|
|
pnlsRoute->Append( SZ("\"") ) ;
|
|
}
|
|
|
|
if ( pnlsRoute->QueryError() != 0 || phuaNext != NULL )
|
|
{
|
|
delete pnlsRoute ;
|
|
pnlsRoute = NULL ;
|
|
|
|
}
|
|
return pnlsRoute ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::MarkHidden
|
|
|
|
SYNOPSIS: For the given element of the COMP_ASSOC,
|
|
walk each binding's component list and mark
|
|
it as hidden if a hidden component appears
|
|
in its path.
|
|
|
|
ENTRY: int itemNo index of component
|
|
|
|
EXIT:
|
|
|
|
RETURNS:
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
VOID BINDERY :: MarkHidden ( int itemNo )
|
|
{
|
|
COMP_BINDING * pBind ;
|
|
COMP_ASSOC * pComp = & (*_paCompAssoc)[itemNo],
|
|
* pCompAtom ;
|
|
ITER_DL_OF( COMP_BINDING ) itb( pComp->_dlcbBinds ) ;
|
|
INT ia, iCompAtom ;
|
|
UINT cbf ;
|
|
HUATOM * phua ;
|
|
|
|
while ( pBind = itb.Next() )
|
|
{
|
|
cbf = pComp->_cbfBindControl ;
|
|
|
|
for ( ia = 0 ;
|
|
phua = pBind->QueryBindToName( ia ) ;
|
|
ia++ )
|
|
{
|
|
// Find the component and extract binding control
|
|
// information.
|
|
|
|
if ( (iCompAtom = FindComponent( *phua )) >= 0 )
|
|
{
|
|
// A binding is hidden if any of the
|
|
// components it passes through indicate so.
|
|
|
|
pCompAtom = & (*_paCompAssoc)[iCompAtom] ;
|
|
cbf |= pCompAtom->_cbfBindControl ;
|
|
}
|
|
}
|
|
|
|
// If the binding should be marked "hidden", do so.
|
|
|
|
if ( cbf & CBNDF_HIDDEN )
|
|
pBind->SetFlag( CBNDF_HIDDEN ) ;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::SortBindings
|
|
|
|
SYNOPSIS: Attempt to preserve any previous (manual) ordering of
|
|
bindings.
|
|
|
|
ENTRY: int itemNo component index
|
|
|
|
EXIT: nothing
|
|
|
|
RETURNS: APIERR if failure; failure is typically ignored
|
|
by caller, since errors do
|
|
do not directly affect the
|
|
system.
|
|
|
|
CAVEAT: This routine has no effect if RestoreBindOrdering()
|
|
is not called at some future time.
|
|
|
|
NOTES: This routine sets the sort order of the bindings such
|
|
that a later call to RestoreBindOrdering() will sort
|
|
the bindings into the same sequence they used to have
|
|
(before any component additions); all new bindings will
|
|
appear at the end of the list.
|
|
|
|
The algorithm is as follows:
|
|
|
|
retrieve the list of strings from the component's
|
|
Linkage\Bind value;
|
|
|
|
mark every binding with a sequential value that
|
|
will sort high to any prior binding;
|
|
|
|
match bindings between the current Registry info
|
|
and the new set; mark each matched binding with
|
|
its old ordering info.
|
|
|
|
|
|
HISTORY: DavidHov 11/17/92 Created
|
|
DavidHov 06/03/93 Sort hidden bindings high
|
|
|
|
********************************************************************/
|
|
APIERR BINDERY :: SortBindings ( int itemNo )
|
|
{
|
|
APIERR err = 0 ;
|
|
COMP_ASSOC * pcassoc = & (*_paCompAssoc)[itemNo] ;
|
|
NLS_STR nlsLinkage( RGAS_LINKAGE_NAME ) ;
|
|
REG_KEY prkLinkage( *pcassoc->_prnService, nlsLinkage ) ;
|
|
STRLIST * pslBinds = NULL ;
|
|
NLS_STR * pnlsBind ;
|
|
COMP_BINDING * pcb ;
|
|
INT cBinds = pcassoc->_dlcbBinds.QueryNumElem(),
|
|
cIndex ;
|
|
|
|
do
|
|
{
|
|
// Check for the trivial case: empty or unitary bind list.
|
|
if ( cBinds < 2 )
|
|
break ;
|
|
|
|
// Get the old bind strings.
|
|
if ( err = prkLinkage.QueryError() )
|
|
break ;
|
|
|
|
if ( err = prkLinkage.QueryValue( RGAS_BIND_VALUE_NAME,
|
|
& pslBinds ) )
|
|
break ;
|
|
|
|
// Check for the other trivial case: no old bindings.
|
|
if ( pslBinds->QueryNumElem() == 0 )
|
|
break ;
|
|
|
|
// Mark each binding with a relative ordering which will sort
|
|
// high to any prior binding, but equal to each other.
|
|
|
|
ITER_DL_OF(COMP_BINDING) itdlBind( pcassoc->_dlcbBinds ) ;
|
|
|
|
for ( cIndex = pslBinds->QueryNumElem() ; pcb = itdlBind.Next() ; )
|
|
{
|
|
pcb->SetSortOrder( cIndex + pcb->QueryFlag( CBNDF_HIDDEN ) ) ;
|
|
}
|
|
|
|
// Find each binding in order, see if it existed before.
|
|
// If so, mark it with the position it had in the old list.
|
|
|
|
ITER_STRLIST islBinds( *pslBinds ) ;
|
|
|
|
for ( cIndex = 0 ; pnlsBind = islBinds.Next() ; cIndex++ )
|
|
{
|
|
for ( itdlBind.Reset() ; pcb = itdlBind.Next() ; )
|
|
{
|
|
if ( ::stricmpf( pcb->QueryBindString(), *pnlsBind ) == 0 )
|
|
{
|
|
// It's a match; if it's not hidden, mark it with its old position.
|
|
|
|
if ( ! pcb->QueryFlag( CBNDF_HIDDEN ) )
|
|
pcb->SetSortOrder( cIndex ) ;
|
|
|
|
// Move on to the next old bind string.
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
} while ( FALSE ) ;
|
|
|
|
delete pslBinds ;
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::SaveBindOrdering
|
|
|
|
SYNOPSIS: Record each binding's position in its DLIST.
|
|
|
|
ENTRY: Nothing
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: Nothing
|
|
|
|
NOTES: This function just writes the zero-based index
|
|
of each binding into its "save" word. See
|
|
RestoreBindOrdering() for usage.
|
|
|
|
HISTORY:
|
|
|
|
*******************************************************************/
|
|
VOID BINDERY :: SaveBindOrdering ()
|
|
{
|
|
COMP_ASSOC * pComp ;
|
|
|
|
for ( INT i = 0 ; i < _paCompAssoc->QueryCount() ; i++ )
|
|
{
|
|
pComp = & (*_paCompAssoc)[i] ;
|
|
ITER_DL_OF( COMP_BINDING ) itb( pComp->_dlcbBinds ) ;
|
|
COMP_BINDING * pBind ;
|
|
|
|
for ( INT j = 0 ; pBind = itb.Next() ; j++ )
|
|
{
|
|
pBind->SetSortOrder( j ) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read the "InstallDate" value from the Registry.
|
|
// The value may be a string or a DWORD.
|
|
|
|
DWORD queryInstallDate ( REG_KEY * pRkComp )
|
|
{
|
|
const TCHAR * pszInstallDate = SZ("InstallDate") ;
|
|
DWORD dwResult ;
|
|
NLS_STR nlsDate ;
|
|
|
|
if ( pRkComp->QueryValue( pszInstallDate, & dwResult ) != 0 )
|
|
{
|
|
if ( pRkComp->QueryValue( pszInstallDate, & nlsDate ) == 0 )
|
|
{
|
|
dwResult = CvtDec( nlsDate.QueryPch() ) ;
|
|
}
|
|
else
|
|
{
|
|
dwResult = (DWORD) -1 ; // Default to highest possible value.
|
|
}
|
|
}
|
|
return dwResult ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::RestoreBindOrdering
|
|
|
|
SYNOPSIS: Reorder all the bindings back into the ordering
|
|
they had when SaveBindOrdering() was called.
|
|
|
|
ENTRY: Nothing
|
|
|
|
EXIT: Nothing
|
|
|
|
RETURNS: APIERR if memory exhausted
|
|
|
|
NOTES: Drains each component's DLIST of COMP_BINDING,
|
|
sorts the dynamic array, rebuilds the DLIST.
|
|
|
|
HISTORY: DavidHov 11/19/92 Created
|
|
|
|
*******************************************************************/
|
|
struct BIND_REF
|
|
{
|
|
COMP_BINDING * _pBind ;
|
|
DWORD _dwInstallDate ;
|
|
};
|
|
|
|
APIERR BINDERY :: RestoreBindOrdering ()
|
|
{
|
|
COMP_ASSOC * pComp ;
|
|
COMP_BINDING * pBind ;
|
|
APIERR err = 0 ;
|
|
|
|
for ( INT i = 0 ; i < _paCompAssoc->QueryCount() ; i++ )
|
|
{
|
|
pComp = & (*_paCompAssoc)[i] ;
|
|
ITER_DL_OF( COMP_BINDING ) itb( pComp->_dlcbBinds ) ;
|
|
BIND_REF * apBindRef = NULL ;
|
|
INT cBinds = pComp->_dlcbBinds.QueryNumElem() ;
|
|
int iComp ;
|
|
|
|
// Check for the trivial case: fewer than 2 elements
|
|
|
|
if ( cBinds < 2 )
|
|
continue ;
|
|
|
|
// Allocate and fill the reference structure array,
|
|
// while draining the current DLIST.
|
|
|
|
apBindRef = new BIND_REF [ cBinds ] ;
|
|
|
|
if ( apBindRef == NULL )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
|
|
// Provide a minor sort key by extracting the installation date
|
|
// of the bound-to component.
|
|
|
|
for ( INT j = 0 ;
|
|
pBind = pComp->_dlcbBinds.Remove( itb ) ;
|
|
j++ )
|
|
{
|
|
apBindRef[j]._pBind = pBind ;
|
|
apBindRef[j]._dwInstallDate = (DWORD) -1 ;
|
|
|
|
HUATOM * phuaComp = pBind->QueryBindToName( 0 ) ;
|
|
|
|
if ( phuaComp != NULL
|
|
&& (iComp = FindComponent( *phuaComp )) >= 0 )
|
|
{
|
|
COMP_ASSOC * pCompNext = & (*_paCompAssoc)[iComp] ;
|
|
apBindRef[j]._dwInstallDate = queryInstallDate( pCompNext->_prnSoftHard ) ;
|
|
}
|
|
}
|
|
|
|
ASSERT( j == cBinds ) ;
|
|
|
|
// Sort the reference array
|
|
|
|
::qsort( (PVOID) apBindRef,
|
|
cBinds,
|
|
sizeof apBindRef[0],
|
|
& BINDERY::BindOrderFunc ) ;
|
|
|
|
// Readd bindings in their sorted (physical) sequence
|
|
|
|
for ( INT k = 0 ; k < cBinds ; k++ )
|
|
{
|
|
pComp->_dlcbBinds.Append( apBindRef[k]._pBind ) ;
|
|
}
|
|
|
|
// Guarantee we're leakproof
|
|
ASSERT( pComp->_dlcbBinds.QueryNumElem() == (UINT)cBinds ) ;
|
|
|
|
// Discard the dynamic array
|
|
delete [] apBindRef ;
|
|
}
|
|
|
|
#if defined(DEBUG)
|
|
if ( err )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BNDR: bindings sort failed, error: ") << err );
|
|
}
|
|
#endif
|
|
|
|
return err ;
|
|
}
|
|
|
|
|
|
// Binding sort helper function. Sort is bind ordering major,
|
|
// install date minor.
|
|
|
|
INT _CRTAPI1 BINDERY :: BindOrderFunc ( const VOID * a, const VOID * b )
|
|
{
|
|
BIND_REF * pBindRef1 = (BIND_REF *) a ;
|
|
BIND_REF * pBindRef2 = (BIND_REF *) b ;
|
|
|
|
INT iResult ;
|
|
|
|
if ( pBindRef1->_pBind->QuerySortOrder() < pBindRef2->_pBind->QuerySortOrder() )
|
|
{
|
|
iResult = -1 ;
|
|
}
|
|
else
|
|
{
|
|
iResult = pBindRef1->_pBind->QuerySortOrder() > pBindRef2->_pBind->QuerySortOrder() ;
|
|
}
|
|
|
|
if ( iResult == 0 )
|
|
{
|
|
if ( pBindRef1->_dwInstallDate < pBindRef2->_dwInstallDate )
|
|
iResult = -1 ;
|
|
else
|
|
iResult = pBindRef1->_dwInstallDate > pBindRef2->_dwInstallDate ;
|
|
}
|
|
return iResult ;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: BINDERY::StopNetwork
|
|
|
|
SYNOPSIS: Stop LanmanWorkstation and all network functions
|
|
associated with it.
|
|
|
|
|
|
ENTRY: Nothing
|
|
|
|
EXIT:
|
|
|
|
RETURNS: APIERR if failure
|
|
|
|
NOTES: Performs a SProlog query to create a list of services
|
|
to stop in the correct order.
|
|
|
|
This function is called during system installation when
|
|
the network has failed to start. By unloading all
|
|
network components, the user has a chance to reconfigure
|
|
and try again.
|
|
|
|
HISTORY:
|
|
|
|
********************************************************************/
|
|
APIERR BINDERY :: StopNetwork ()
|
|
{
|
|
APIERR err = 0 ;
|
|
TCHAR * pszRulesData = NULL ;
|
|
TCHAR * pchResult = NULL ;
|
|
static const TCHAR * pszDependQuery = SZ("(stoplist \"LanmanWorkstation\" List)") ;
|
|
CFG_RULE_SET ruleSet ;
|
|
CFG_RULE_NODE * prnode ;
|
|
STRLIST slServiceNames ;
|
|
SC_MANAGER scMgr( NULL, GENERIC_READ | GENERIC_EXECUTE ) ;
|
|
NLS_STR * pnlsSvcName ;
|
|
SERVICE_STATUS svcStatus ;
|
|
|
|
do
|
|
{
|
|
// Check that we have a healthy service controller
|
|
if ( err = scMgr.QueryError() )
|
|
break ;
|
|
|
|
// Allocate the query buffer.
|
|
pchResult = new TCHAR [ lcbMaxQueryResult ] ;
|
|
if ( pchResult == NULL )
|
|
{
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
|
|
// Read the service dependency handling rules from our
|
|
// resource fork and munge them into the proper form.
|
|
|
|
pszRulesData = GetRulesResource( RGAS_RES_DEPEND_RULES_NAME ) ;
|
|
if ( pszRulesData == NULL )
|
|
{
|
|
err = ERROR_FILE_NOT_FOUND ; // BUGBUG: error code?
|
|
break ;
|
|
}
|
|
|
|
// Reset the SProlog interpreter.
|
|
ResetInterpreter() ;
|
|
|
|
// Consult the dependency rules
|
|
if ( ! _queryEngine.ConsultData( pszRulesData ) )
|
|
{
|
|
err = IDS_NCPA_BNDR_CNSLT_BASE ;
|
|
break;
|
|
}
|
|
|
|
err = IDS_NCPA_BNDR_QURY_FAIL ;
|
|
|
|
//
|
|
// Run the query (stoplist "LanmanWorkstation" List)
|
|
//
|
|
// Since "List" is a Prolog variable, the result will appear as:
|
|
//
|
|
// List = ("name" "name" "name"...)
|
|
//
|
|
// Query the list of dependencies for LanmanWorkstation
|
|
//
|
|
if ( ! _queryEngine.QueryData( pszDependQuery,
|
|
pchResult,
|
|
lcbMaxQueryResult ) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
if ( ! (ruleSet.Parse( pchResult, PARSE_CTL_RSP_SYNTAX ) >= 0) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
err = IDS_NCPA_BNDR_QURY_PARSE_FAIL ;
|
|
|
|
// Get the top-level list pointer
|
|
prnode = ruleSet.QueryList() ;
|
|
|
|
// Walk the outer list to the nested list
|
|
ParseCheck(prnode,CRN_NIL);
|
|
ParseStep(prnode,CRN_VAR);
|
|
ParseStep(prnode,CRN_EQUIV);
|
|
ParseStep(prnode,CRN_LIST);
|
|
|
|
// Access list of service names
|
|
prnode = prnode->QueryList() ;
|
|
// Check that there's a NIL to start with
|
|
ParseCheck(prnode,CRN_NIL);
|
|
|
|
// Build up a STRLIST of the names of the services to
|
|
// be stopped.
|
|
|
|
for ( err = 0, prnode = prnode->QueryNext() ;
|
|
prnode && prnode->QueryType() == CRN_STR ;
|
|
prnode = prnode->QueryNext() )
|
|
{
|
|
pnlsSvcName = new NLS_STR( prnode->QueryAtom().QueryText() ) ;
|
|
if ( err = pnlsSvcName->QueryError() )
|
|
break ;
|
|
|
|
if ( pnlsSvcName->_stricmp(SZ("ndistapi")) == 0 )
|
|
{
|
|
ITER_STRLIST iter( slServiceNames );
|
|
NLS_STR *pTmp;
|
|
while((( pTmp = iter.Next()) != NULL ) && ( pTmp->_stricmp(SZ("ndiswan"))!=0))
|
|
{
|
|
}
|
|
if ( pTmp != NULL )
|
|
{
|
|
err = slServiceNames.Insert( pnlsSvcName, iter );
|
|
}
|
|
else
|
|
{
|
|
err = slServiceNames.Append( pnlsSvcName );
|
|
}
|
|
}
|
|
else if ( pnlsSvcName->_stricmp(SZ("ndiswan")) == 0 )
|
|
{
|
|
ITER_STRLIST iter( slServiceNames );
|
|
NLS_STR *pTmp;
|
|
while((( pTmp = iter.Next()) != NULL ) && ( pTmp->_stricmp(SZ("asyncmac"))!=0))
|
|
{
|
|
}
|
|
if ( pTmp != NULL )
|
|
{
|
|
err = slServiceNames.Insert( pnlsSvcName, iter );
|
|
}
|
|
else
|
|
{
|
|
err = slServiceNames.Append( pnlsSvcName );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
err = slServiceNames.Append( pnlsSvcName );
|
|
}
|
|
if ( err )
|
|
break ;
|
|
}
|
|
|
|
// Break out if NLS_STR or STRLIST allocation failure.
|
|
if ( err )
|
|
break ;
|
|
|
|
// Break out if we're not at the end of the list.
|
|
if ( prnode != NULL )
|
|
{
|
|
err = IDS_NCPA_BNDR_QURY_PARSE_FAIL ;
|
|
break ;
|
|
}
|
|
|
|
// Now append all members of the PNP_TDI and NDIS groups.
|
|
|
|
// loop twice once for NDIS, once for PNP_TDI
|
|
for ( int i = 0; i<2; i++ )
|
|
{
|
|
SERVICE_ENUM enumServices( NULL,
|
|
TRUE,
|
|
SERVICE_WIN32|SERVICE_DRIVER,
|
|
i == 0 ? RGAS_VALUE_NDIS
|
|
: RGAS_VALUE_PNP_TDI );
|
|
|
|
if ( (err = enumServices.GetInfo()) == NERR_Success )
|
|
{
|
|
|
|
SERVICE_ENUM_ITER iterServices( enumServices );
|
|
const SERVICE_ENUM_OBJ * psvc;
|
|
|
|
while( ( psvc = iterServices() ) != NULL )
|
|
{
|
|
pnlsSvcName = new NLS_STR( psvc->QueryServiceName() ) ;
|
|
if ( err = pnlsSvcName->QueryError() )
|
|
break ;
|
|
|
|
err = slServiceNames.Append( pnlsSvcName );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( err )
|
|
break ;
|
|
|
|
// Ok. We now have a list of services to stop. Do so.
|
|
|
|
ITER_STRLIST islSvcs( slServiceNames ) ;
|
|
|
|
while ( pnlsSvcName = islSvcs.Next() )
|
|
{
|
|
SC_SERVICE svc( scMgr, *pnlsSvcName ) ;
|
|
APIERR errSvc ;
|
|
|
|
TRACEEOL( SZ("NCPA/BNDR: (stop network) stopping: ")
|
|
<< pnlsSvcName->QueryPch() );
|
|
|
|
if ( errSvc = svc.QueryError() )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BNDR: (stop network) ctor failed: ")
|
|
<< pnlsSvcName->QueryPch()
|
|
<< SZ(", err = ")
|
|
<< errSvc );
|
|
continue ;
|
|
}
|
|
|
|
// Stop any dependent services.
|
|
|
|
|
|
|
|
// enumerate the dependent services
|
|
|
|
LPENUM_SERVICE_STATUS pServices;
|
|
UINT uServices;
|
|
|
|
err = svc.EnumDependent(SERVICE_ACTIVE,
|
|
&pServices,
|
|
(DWORD *)&uServices ) ;
|
|
|
|
// while OK and we aint thru with all yet
|
|
while (err == NERR_Success && uServices--)
|
|
{
|
|
// CODEWORK: No error handling
|
|
SC_SERVICE svcDep( scMgr, pServices->lpServiceName ) ;
|
|
|
|
if ( svcDep.QueryError() == NERR_Success )
|
|
{
|
|
// Stop each dependent service
|
|
svcDep.Control( SERVICE_CONTROL_STOP, & svcStatus );
|
|
}
|
|
|
|
pServices++ ;
|
|
}
|
|
|
|
|
|
// Now stop the service. Save the first error encountered.
|
|
|
|
if ( errSvc = svc.Control( SERVICE_CONTROL_STOP, & svcStatus ) )
|
|
{
|
|
TRACEEOL( SZ("NCPA/BNDR: (stop network) stop failed: ")
|
|
<< pnlsSvcName->QueryPch()
|
|
<< SZ(", err = ")
|
|
<< errSvc );
|
|
|
|
if ( err == 0 )
|
|
err = errSvc ;
|
|
}
|
|
}
|
|
|
|
} while ( FALSE ) ;
|
|
|
|
delete pchResult ;
|
|
delete pszRulesData ;
|
|
|
|
return err ;
|
|
}
|
|
|
|
// End of NCPABNDR.CXX
|