/*++ 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; }