windows-nt/Source/XPSP1/NT/base/ntsetup/ocmanage/common/ocstate.c
2020-09-26 16:20:57 +08:00

454 lines
11 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
ocstate.c
Abstract:
Routines to remember and restore the install state of subcomponents.
Author:
Ted Miller (tedm) 17-Oct-1996
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
typedef struct _I_S_PARAMS {
HKEY hKey;
BOOL Set;
BOOL AnyError;
BOOL Simple;
POC_MANAGER OcManager;
} I_S_PARAMS, *PI_S_PARAMS;
BOOL
pOcPersistantInstallStatesWorker(
IN POC_MANAGER OcManager,
IN BOOL Set,
IN LONG ComponentStringId
);
BOOL
pOcInitInstallStatesStringTableCB(
IN PVOID StringTable,
IN LONG StringId,
IN PCTSTR String,
IN POPTIONAL_COMPONENT Oc,
IN UINT OcStructSize,
IN PI_S_PARAMS Params
);
BOOL
pOcFetchInstallStates(
IN POC_MANAGER OcManager
)
/*++
Routine Description:
This routine retreives stored installation state for all leaf child
subcomponents, from the registry. It does NOT set or manipulate parent
selection states.
Both the selection state and original selection state memebers of the
optional component structures are set (to the same value) by this routine.
Arguments:
OcManager - supplies OC Manager context info.
Return Value:
Boolean value indicating outcome. If FALSE then some catastrophic
registry error occurred.
--*/
{
return(pOcPersistantInstallStatesWorker(OcManager,FALSE,-1));
}
BOOL
pOcRememberInstallStates(
IN POC_MANAGER OcManager
)
/*++
Routine Description:
This routine stores installation state for all leaf child
subcomponents, into the registry. It does NOT set or manipulate parent
selection states.
The current selection state is stored, and then the original state is
reset to the current state.
Arguments:
OcManager - supplies OC Manager context info.
Return Value:
Boolean value indicating outcome. If FALSE then some catastrophic
registry error occurred.
--*/
{
return(pOcPersistantInstallStatesWorker(OcManager,TRUE,-1));
}
BOOL
pOcSetOneInstallState(
IN POC_MANAGER OcManager,
IN LONG StringId
)
/*++
Routine Description:
This routine stores installation state for one single leaf child
subcomponent, into the registry.
The current selection state is stored. The original selection state
is not manipulated.
Arguments:
OcManager - supplies OC Manager context info.
Return Value:
Boolean value indicating outcome. If FALSE then some catastrophic
registry error occurred.
--*/
{
return(pOcPersistantInstallStatesWorker(OcManager,TRUE,StringId));
}
BOOL
pOcPersistantInstallStatesWorker(
IN POC_MANAGER OcManager,
IN BOOL Set,
IN LONG ComponentStringId
)
/*++
Routine Description:
Worker routine for fetching and remembering installation states.
If opens/creates the key used in the registry for persistent state info,
the enumerates the component string table to examine each subcomponent
and either fetch or set the install state.
Arguments:
OcManager - supplies OC Manager context info.
Set - if 0 then query state from the registry and store in the
OPTIONAL_COMPONENT structures. If non-0 then set state into registry.
If 0 then query. Component DLLs will be sent OC_DETECT_INITIAL_STATE
notifications.
Return Value:
Boolean value indicating outcome. If FALSE then some catastrophic
registry error occurred.
--*/
{
OPTIONAL_COMPONENT Oc;
LONG l;
DWORD Disposition;
I_S_PARAMS Params;
l = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
szSubcompList,
0,
NULL,
REG_OPTION_NON_VOLATILE,
(Set || (OcManager->InternalFlags & OCMFLAG_KILLSUBCOMPS)) ? KEY_SET_VALUE : KEY_QUERY_VALUE,
NULL,
&Params.hKey,
&Disposition
);
if(l != NO_ERROR) {
_LogError(
OcManager,
Set ? OcErrLevError : OcErrLevFatal,
MSG_OC_CREATE_KEY_FAILED,
szSubcompList,
l
);
return(FALSE);
}
Params.Set = Set;
Params.AnyError = FALSE;
Params.OcManager = OcManager;
if(ComponentStringId == -1) {
//
// Enumerate whole table and operate on each leaf node.
//
Params.Simple = FALSE;
pSetupStringTableEnum(
OcManager->ComponentStringTable,
&Oc,
sizeof(OPTIONAL_COMPONENT),
(PSTRTAB_ENUM_ROUTINE)pOcInitInstallStatesStringTableCB,
(LPARAM)&Params
);
} else {
//
// Operate on one single subcomponent.
//
Params.Simple = TRUE;
if (!pOcComponentWasRemoved(OcManager, ComponentStringId)) {
pSetupStringTableGetExtraData(
OcManager->ComponentStringTable,
ComponentStringId,
&Oc,
sizeof(OPTIONAL_COMPONENT)
);
pOcInitInstallStatesStringTableCB(
OcManager->ComponentStringTable,
ComponentStringId,
pSetupStringTableStringFromId(OcManager->ComponentStringTable,ComponentStringId),
&Oc,
sizeof(OPTIONAL_COMPONENT),
&Params
);
}
}
RegCloseKey(Params.hKey);
return(!Params.AnyError);
}
BOOL
pOcInitInstallStatesStringTableCB(
IN PVOID StringTable,
IN LONG StringId,
IN PCTSTR String,
IN POPTIONAL_COMPONENT Oc,
IN UINT OcStructSize,
IN PI_S_PARAMS Params
)
{
LONG l;
DWORD Type;
DWORD Data;
DWORD Size;
SubComponentState s;
//
// If this is not a leaf/child component, ignore it.
//
if(Oc->FirstChildStringId == -1) {
if(Params->Set) {
Data = (Oc->SelectionState == SELSTATE_NO) ? 0 : 1;
if( ((Params->OcManager)->SetupMode & SETUPMODE_PRIVATE_MASK) == SETUPMODE_REMOVEALL ) {
RegDeleteValue(Params->hKey,String);
} else {
l = RegSetValueEx(Params->hKey,String,0,REG_DWORD,(CONST BYTE *)&Data,sizeof(DWORD));
if(l != NO_ERROR) {
Params->AnyError = TRUE;
_LogError(
Params->OcManager,
OcErrLevError,
MSG_OC_CANT_REMEMBER_STATE,
Oc->Description,
l
);
}
}
} else {
// kill the entry from the registry before starting, if indicated
if (Params->OcManager->InternalFlags & OCMFLAG_KILLSUBCOMPS)
l = RegDeleteValue(Params->hKey,String);
// Check the registery and see if we have dealt with this component before
// Data should contain 0/1 depending on the current installed state
//
// If the entry does not exist the data type/size is not valid
// then we don't have Prior knowlege of component.
//
// also check the inf settting for installation state
Size = sizeof(DWORD);
l = RegQueryValueEx(Params->hKey,String,NULL,&Type,(LPBYTE)&Data,&Size);
switch (Oc->InstalledState)
{
case INSTSTATE_YES:
Data = 1;
break;
case INSTSTATE_NO:
Data = 0;
break;
}
if((l != NO_ERROR) || (Size != sizeof(DWORD)) || ((Type != REG_DWORD) && (Type != REG_BINARY))) {
// Nope, never seen it, Set Data to Uninstalled
// and flag this item as new
Data = 0;
Oc->InternalFlags |= OCFLAG_NEWITEM;
} else {
// have seen it before, Data contains it's current install state
// Flag this component that it had an initial install state
Oc->InternalFlags |= OCFLAG_ANYORIGINALLYON;
}
//
// Now call out to the component dll to ask whether it wants to
// override the value we decided on.
//
s = OcInterfaceQueryState(
Params->OcManager,
pOcGetTopLevelComponent(Params->OcManager,StringId),
String,
OCSELSTATETYPE_ORIGINAL
);
switch(s) {
case SubcompUseOcManagerDefault:
Oc->SelectionState = Data ? SELSTATE_YES : SELSTATE_NO;
break;
case SubcompOn:
Oc->SelectionState = SELSTATE_YES;
Oc->InternalFlags |= OCFLAG_ANYORIGINALLYON;
break;
case SubcompOff:
Oc->SelectionState = SELSTATE_NO;
Oc->InternalFlags |= OCFLAG_ANYORIGINALLYOFF;
break;
}
}
pSetupStringTableSetExtraData(StringTable,StringId,Oc,OcStructSize);
if(!Params->Simple) {
Oc->OriginalSelectionState = Oc->SelectionState;
pSetupStringTableSetExtraData(StringTable,StringId,Oc,OcStructSize);
pOcUpdateParentSelectionStates(Params->OcManager,NULL,StringId);
}
}
return(TRUE);
}
/*
* this function is exported to allow external code to
* access the installation states
*/
UINT
OcComponentState(
LPCTSTR component,
UINT operation,
DWORD *val
)
{
HKEY hkey;
LONG rc;
DWORD dw;
DWORD size;
sapiAssert(val);
rc = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
szSubcompList,
0,
NULL,
REG_OPTION_NON_VOLATILE,
(operation == infQuery) ? KEY_QUERY_VALUE : KEY_SET_VALUE,
NULL,
&hkey,
&dw
);
if (rc != ERROR_SUCCESS)
return rc;
switch (operation) {
case infQuery:
rc = RegQueryValueEx(hkey, component, NULL, &dw, (LPBYTE)val, &size);
if (rc == ERROR_FILE_NOT_FOUND) {
*val = 0;
rc = ERROR_SUCCESS;
}
break;
case infSet:
if (*val == SELSTATE_NO || *val == SELSTATE_YES) {
dw = (*val == SELSTATE_NO) ? 0 : 1;
rc = RegSetValueEx(hkey, component, 0, REG_DWORD, (CONST BYTE *)&dw, sizeof(DWORD));
break;
}
// pass through
default:
rc = ERROR_INVALID_PARAMETER;
break;
}
RegCloseKey(hkey);
*val = (*val == 0) ? SELSTATE_NO : SELSTATE_YES;
return rc;
}