454 lines
11 KiB
C
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;
|
||
|
}
|
||
|
|
||
|
|