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.
979 lines
24 KiB
979 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
components.c
|
|
|
|
Abstract:
|
|
|
|
Implements a set of APIs for the purposes of allowing the application layer to select
|
|
module functionality.
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 07-Aug-2000
|
|
|
|
Revision History:
|
|
|
|
<alias> <date> <comments>
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include "pch.h"
|
|
#include "ism.h"
|
|
#include "ismp.h"
|
|
|
|
#define DBG_COMP "Comp"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
#define S_COMPONENT_ROOT TEXT("Components")
|
|
#define S_USER_SUPPLIED TEXT("User")
|
|
#define S_MODULE_SUPPLIED TEXT("Module")
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
#define MAX_COMPONENT_SPEC 127
|
|
#define MAX_COMPONENT_SPEC_PLUS_NUL (MAX_COMPONENT_SPEC+1)
|
|
|
|
#define MAX_CONTROLLED_NODE_SIZE (MAX_COMPONENT_SPEC_PLUS_NUL + \
|
|
ARRAYSIZE(S_COMPONENT_ROOT) + \
|
|
ARRAYSIZE(S_MODULE_SUPPLIED) + 16)
|
|
|
|
#define MEMDB_FLAG_PREFERRED 1
|
|
#define MEMDB_FLAG_SELECTED 1
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// none
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
typedef enum {
|
|
CES_DONE = 0,
|
|
CES_FIRST_COMPONENT,
|
|
CES_NEXT_COMPONENT,
|
|
CES_FIRST_ALIAS,
|
|
CES_NEXT_ALIAS,
|
|
CES_CHECK_ALIAS_FLAGS
|
|
} COMPONENTENUMSTATE;
|
|
|
|
typedef struct {
|
|
MEMDB_ENUM ComponentEnumStruct;
|
|
MEMDB_ENUM AliasEnumStruct;
|
|
BOOL EnumAliases;
|
|
UINT GroupIdFilter;
|
|
BOOL EnumEnabled;
|
|
BOOL EnumDisabled;
|
|
BOOL EnumPreferredOnly;
|
|
BOOL EnumNonPreferredOnly;
|
|
COMPONENTENUMSTATE State;
|
|
} COMPONENTENUM_HANDLE, *PCOMPONENTENUM_HANDLE;
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
// none
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
// none
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
// none
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
// none
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
|
|
BOOL
|
|
pCheckCompChar (
|
|
IN CHARTYPE Char,
|
|
IN BOOL CheckDecoration
|
|
)
|
|
{
|
|
//
|
|
// Process decoration chars
|
|
//
|
|
|
|
if (Char == TEXT('$') || Char == TEXT('@') || Char == TEXT('~') || Char == TEXT('#')) {
|
|
return CheckDecoration;
|
|
}
|
|
|
|
if (CheckDecoration) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Block illegal chars
|
|
//
|
|
|
|
if (Char == TEXT('\"') || Char == TEXT('*') || Char == TEXT('?') || Char== TEXT('\\') ||
|
|
Char == TEXT('%') || Char == TEXT(';')
|
|
) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Make sure char is printable
|
|
//
|
|
|
|
if (Char < 33 || Char > 126) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pCheckComponentName (
|
|
IN PCTSTR ComponentString
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
PCTSTR end;
|
|
PCTSTR begin;
|
|
|
|
//
|
|
// Check for a non-empty spec
|
|
//
|
|
|
|
if (ComponentString && ComponentString[0]) {
|
|
|
|
//
|
|
// Allow for decoration
|
|
//
|
|
|
|
end = ComponentString;
|
|
|
|
while (pCheckCompChar ((CHARTYPE) _tcsnextc (end), TRUE)) {
|
|
end = _tcsinc (end);
|
|
}
|
|
|
|
//
|
|
// Now enforce the name character set: non-decorated characters and no
|
|
// more than MAX_COMPONENT_SPEC characters. Allow spaces in the middle.
|
|
//
|
|
|
|
begin = end;
|
|
|
|
while (*end) {
|
|
if (!pCheckCompChar ((CHARTYPE) _tcsnextc (end), FALSE)) {
|
|
if (_tcsnextc (end) == TEXT(' ')) {
|
|
if (!end[1] || end == begin) {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
end = _tcsinc (end);
|
|
}
|
|
|
|
if (!(*end) && *begin) {
|
|
if (end - ComponentString <= MAX_COMPONENT_SPEC) {
|
|
result = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!result) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
DEBUGMSG ((DBG_ERROR, "%s is not a valid component name", ComponentString));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
pFindComponent (
|
|
IN PCTSTR LocalizedAlias,
|
|
IN UINT ComponentGroupId,
|
|
OUT PCTSTR *ComponentKey, OPTIONAL
|
|
OUT PCTSTR *AliasKey OPTIONAL
|
|
)
|
|
{
|
|
MEMDB_ENUM component;
|
|
PCTSTR memdbNode = NULL;
|
|
PCTSTR encodedUserAlias;
|
|
PCTSTR encodedModuleAlias;
|
|
TCHAR number[32];
|
|
BOOL result = FALSE;
|
|
|
|
//
|
|
// Find the component based on the localized alias
|
|
//
|
|
|
|
wsprintf (number, TEXT("\\%s\\%04u"), S_USER_SUPPLIED, ComponentGroupId);
|
|
encodedUserAlias = JoinPaths (number, LocalizedAlias);
|
|
|
|
wsprintf (number, TEXT("\\%s\\%04u"), S_MODULE_SUPPLIED, ComponentGroupId);
|
|
encodedModuleAlias = JoinPaths (number, LocalizedAlias);
|
|
|
|
if (MemDbEnumFirst (
|
|
&component,
|
|
S_COMPONENT_ROOT TEXT("\\*"),
|
|
ENUMFLAG_ALL,
|
|
1,
|
|
1
|
|
)) {
|
|
|
|
do {
|
|
memdbNode = JoinText (component.FullKeyName, encodedModuleAlias);
|
|
|
|
if (MemDbTestKey (memdbNode)) {
|
|
break;
|
|
}
|
|
|
|
FreeText (memdbNode);
|
|
memdbNode = NULL;
|
|
|
|
memdbNode = JoinText (component.FullKeyName, encodedUserAlias);
|
|
|
|
if (MemDbTestKey (memdbNode)) {
|
|
break;
|
|
}
|
|
|
|
FreeText (memdbNode);
|
|
memdbNode = NULL;
|
|
|
|
} while (MemDbEnumNext (&component));
|
|
}
|
|
|
|
if (memdbNode) {
|
|
|
|
if (ComponentKey) {
|
|
*ComponentKey = DuplicateText (component.FullKeyName);
|
|
}
|
|
|
|
if (AliasKey) {
|
|
*AliasKey = memdbNode;
|
|
memdbNode = NULL;
|
|
}
|
|
|
|
MemDbAbortEnum (&component);
|
|
result = TRUE;
|
|
}
|
|
|
|
FreeText (memdbNode);
|
|
INVALID_POINTER (memdbNode);
|
|
|
|
FreePathString (encodedUserAlias);
|
|
INVALID_POINTER (encodedUserAlias);
|
|
|
|
FreePathString (encodedModuleAlias);
|
|
INVALID_POINTER (encodedModuleAlias);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
IsmSelectPreferredAlias (
|
|
IN PCTSTR ComponentString,
|
|
IN PCTSTR LocalizedAlias, OPTIONAL
|
|
IN UINT ComponentGroupId OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IsmSelectPreferredAlias marks a specific alias as the "preferred" one, so
|
|
that the UI knows what to display. If LocalizedAlias is not specified, none
|
|
of the aliases are preferred.
|
|
|
|
A component can have only one preferred localized alias. If another alias is
|
|
selected as preferred, it will be deselected automatically.
|
|
|
|
Arguments:
|
|
|
|
ComponentString - Specifies the non-displayed component identifier
|
|
LocalizedAlias - Specifies the displayable string to mark as "preferred,"
|
|
or NULL to remove the preferred flag from the component.
|
|
ComponentGroupId - Specifies the group ID for LocalizedAlias. Required if
|
|
LocalizedAlias is not NULL.
|
|
|
|
Return Value:
|
|
|
|
TRUE if selection (or deselection) succeeded, FALSE if LocalizedAlias does
|
|
not exist.
|
|
|
|
--*/
|
|
|
|
{
|
|
MEMDB_ENUM e;
|
|
TCHAR number[32];
|
|
PCTSTR memdbNode = NULL;
|
|
PCTSTR baseOfPattern;
|
|
PCTSTR enumPattern;
|
|
PCTSTR groupedAlias;
|
|
BOOL result;
|
|
|
|
if (!ComponentString || (LocalizedAlias && !ComponentGroupId)) {
|
|
MYASSERT (FALSE);
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
result = (LocalizedAlias == NULL);
|
|
|
|
//
|
|
// Build enumeration string Components\<component>\*
|
|
//
|
|
|
|
baseOfPattern = JoinPaths (S_COMPONENT_ROOT, ComponentString);
|
|
enumPattern = JoinPaths (baseOfPattern, TEXT("*"));
|
|
FreePathString (baseOfPattern);
|
|
INVALID_POINTER (baseOfPattern);
|
|
|
|
if (LocalizedAlias) {
|
|
wsprintf (number, TEXT("%04u"), ComponentGroupId);
|
|
groupedAlias = JoinPaths (number, LocalizedAlias);
|
|
} else {
|
|
groupedAlias = NULL;
|
|
}
|
|
|
|
if (MemDbEnumFirst (
|
|
&e,
|
|
enumPattern,
|
|
ENUMFLAG_NORMAL,
|
|
3,
|
|
ENUMLEVEL_ALLLEVELS
|
|
)) {
|
|
do {
|
|
if (groupedAlias && StringIMatch (e.KeyName, groupedAlias)) {
|
|
MemDbSetFlags (e.FullKeyName, MEMDB_FLAG_PREFERRED, MEMDB_FLAG_PREFERRED);
|
|
result = TRUE;
|
|
} else {
|
|
MemDbSetFlags (e.FullKeyName, 0, MEMDB_FLAG_PREFERRED);
|
|
}
|
|
} while (MemDbEnumNext (&e));
|
|
}
|
|
|
|
FreePathString (enumPattern);
|
|
INVALID_POINTER (enumPattern);
|
|
|
|
FreePathString (groupedAlias);
|
|
INVALID_POINTER (groupedAlias);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
IsmAddComponentAlias (
|
|
IN PCTSTR ComponentString, OPTIONAL
|
|
IN UINT MasterGroup,
|
|
IN PCTSTR LocalizedAlias,
|
|
IN UINT ComponentGroupId,
|
|
IN BOOL UserSupplied
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
IsmAddComponentAlias associates a display string (LocalizedAlias) with a
|
|
logical component tag (ComponentString).
|
|
|
|
Arguments:
|
|
|
|
ComponentString - Specifies the identifier of the component. This
|
|
identifier is not used for display purposes.
|
|
MasterGroup - Specifies a MASTERGROUP_xxx constant, which organizes
|
|
the components into major groups such as system settings
|
|
and app settings (to simplify selection).
|
|
LocalizedAliais - The displayable text. It is a localized component name,
|
|
a path, a file, etc.
|
|
ComponentGroupId - An arbitrary numeric ID defined outside of the ISM. This
|
|
ID is used to implement requirements specific to the app
|
|
layer. It allows for arbitrary idenfication and grouping.
|
|
UserSupplied - Specifies TRUE if the end-user supplied this info, FALSE
|
|
if it is built into the migration package.
|
|
|
|
Return Value:
|
|
|
|
A flag indicating success or failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCTSTR memdbNode;
|
|
TCHAR workNode[MAX_CONTROLLED_NODE_SIZE];
|
|
static UINT sequencer = 0;
|
|
TCHAR madeUpComponent[MAX_COMPONENT_SPEC_PLUS_NUL];
|
|
BOOL b;
|
|
BOOL newComponent = FALSE;
|
|
|
|
//
|
|
// Components are kept in memdb in the form of
|
|
//
|
|
// Component\<Module|User>\<GroupId>\<LocalizedAlias> = <preferred flag>
|
|
//
|
|
// <GroupId> is stored as a 4 digit number (such as 0001)
|
|
//
|
|
// Component\<Module|User> = <enable/disable>,<master group>
|
|
//
|
|
|
|
//
|
|
// Validate arguments
|
|
//
|
|
|
|
if (ComponentGroupId > 9999) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ComponentString || !ComponentString[0]) {
|
|
|
|
wsprintf (madeUpComponent, TEXT("Component %u"), ++sequencer);
|
|
ComponentString = madeUpComponent;
|
|
|
|
} else if (!pCheckComponentName (ComponentString)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!MasterGroup || MasterGroup >= MASTERGROUP_ALL) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
DEBUGMSG ((DBG_ERROR, "MasterGroup is invalid"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// See if the component already exists
|
|
//
|
|
|
|
// This is safe since ComponentString was already checked for length by pCheckComponentName
|
|
wsprintf (workNode, TEXT("%s\\%s"), S_COMPONENT_ROOT, ComponentString);
|
|
|
|
if (pFindComponent (LocalizedAlias, ComponentGroupId, &memdbNode, NULL)) {
|
|
|
|
if (StringIMatch (workNode, memdbNode)) {
|
|
DEBUGMSG ((DBG_VERBOSE, "Alias %s already exists; not adding it again", LocalizedAlias));
|
|
} else {
|
|
DEBUGMSG ((
|
|
DBG_WARNING,
|
|
"Alias %s is in use by component %s; not adding it again",
|
|
LocalizedAlias,
|
|
_tcschr (memdbNode, TEXT('\\')) + 1
|
|
));
|
|
}
|
|
|
|
FreeText (memdbNode);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create the component if it doesn't exist, and then add the alias
|
|
//
|
|
|
|
if (!MemDbTestKey (workNode)) {
|
|
if (!MemDbSetValueAndFlags (workNode, MasterGroup, MEMDB_FLAG_SELECTED, MEMDB_FLAG_SELECTED)) {
|
|
EngineError ();
|
|
return FALSE;
|
|
}
|
|
|
|
newComponent = TRUE;
|
|
}
|
|
|
|
// This is safe since ComponentString was already checked for length by pCheckComponentName
|
|
wsprintf (
|
|
workNode,
|
|
TEXT("%s\\%s\\%s\\%04u"),
|
|
S_COMPONENT_ROOT,
|
|
ComponentString,
|
|
UserSupplied ? S_USER_SUPPLIED : S_MODULE_SUPPLIED,
|
|
ComponentGroupId
|
|
);
|
|
|
|
memdbNode = JoinPaths (workNode, LocalizedAlias);
|
|
|
|
if (newComponent) {
|
|
b = MemDbSetFlags (memdbNode, MEMDB_FLAG_PREFERRED, MEMDB_FLAG_PREFERRED);
|
|
} else {
|
|
b = MemDbSetKey (memdbNode);
|
|
}
|
|
|
|
FreePathString (memdbNode);
|
|
|
|
if (!b) {
|
|
EngineError ();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
IsmSelectComponent (
|
|
IN PCTSTR ComponentOrAlias,
|
|
IN UINT ComponentGroupId, OPTIONAL
|
|
IN BOOL Enable
|
|
)
|
|
{
|
|
PCTSTR memdbNode = NULL;
|
|
UINT flags;
|
|
BOOL b;
|
|
|
|
if (ComponentGroupId > 9999) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
DEBUGMSG ((DBG_ERROR, "Invalid component group"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ComponentOrAlias || !ComponentOrAlias[0]) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
DEBUGMSG ((DBG_ERROR, "Invalid localized alias"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ComponentGroupId) {
|
|
if (!pCheckComponentName (ComponentOrAlias)) {
|
|
return FALSE;
|
|
}
|
|
|
|
memdbNode = JoinText (S_COMPONENT_ROOT TEXT("\\"), ComponentOrAlias);
|
|
if (!MemDbTestKey (memdbNode)) {
|
|
FreeText (memdbNode);
|
|
return FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!pFindComponent (ComponentOrAlias, ComponentGroupId, &memdbNode, NULL)) {
|
|
SetLastError (ERROR_NO_SUCH_ALIAS);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
flags = Enable ? MEMDB_FLAG_SELECTED : 0;
|
|
b = MemDbSetFlags (memdbNode, flags, MEMDB_FLAG_SELECTED);
|
|
FreeText (memdbNode);
|
|
|
|
if (!b) {
|
|
EngineError ();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pEnumWorker (
|
|
IN OUT PMIG_COMPONENT_ENUM EnumPtr,
|
|
IN OUT PCOMPONENTENUM_HANDLE Handle
|
|
)
|
|
{
|
|
BOOL result = FALSE;
|
|
PCTSTR pattern;
|
|
PCTSTR p;
|
|
BOOL enabled;
|
|
|
|
while (Handle->State != CES_DONE) {
|
|
|
|
switch (Handle->State) {
|
|
|
|
case CES_FIRST_COMPONENT:
|
|
|
|
if (!MemDbEnumFirst (
|
|
&Handle->ComponentEnumStruct,
|
|
S_COMPONENT_ROOT TEXT("\\*"),
|
|
ENUMFLAG_ALL,
|
|
1,
|
|
1
|
|
)) {
|
|
Handle->State = CES_DONE;
|
|
} else {
|
|
if (Handle->EnumAliases) {
|
|
Handle->State = CES_FIRST_ALIAS;
|
|
} else {
|
|
Handle->State = CES_NEXT_COMPONENT;
|
|
result = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CES_FIRST_ALIAS:
|
|
|
|
enabled = ((Handle->ComponentEnumStruct.Flags & MEMDB_FLAG_SELECTED) != 0);
|
|
|
|
if ((!Handle->EnumEnabled && enabled) ||
|
|
(!Handle->EnumDisabled && !enabled)
|
|
) {
|
|
Handle->State = CES_NEXT_COMPONENT;
|
|
continue;
|
|
}
|
|
|
|
EnumPtr->Instance = 0;
|
|
|
|
pattern = JoinPaths (Handle->ComponentEnumStruct.FullKeyName, TEXT("*"));
|
|
|
|
if (!MemDbEnumFirst (
|
|
&Handle->AliasEnumStruct,
|
|
pattern,
|
|
ENUMFLAG_NORMAL,
|
|
4,
|
|
ENUMLEVEL_ALLLEVELS
|
|
)) {
|
|
Handle->State = CES_NEXT_COMPONENT;
|
|
} else {
|
|
Handle->State = CES_CHECK_ALIAS_FLAGS;
|
|
}
|
|
|
|
FreePathString (pattern);
|
|
break;
|
|
|
|
case CES_NEXT_ALIAS:
|
|
if (EnumPtr->SkipToNextComponent) {
|
|
MemDbAbortEnum (&Handle->AliasEnumStruct);
|
|
Handle->State = CES_NEXT_COMPONENT;
|
|
EnumPtr->SkipToNextComponent = FALSE;
|
|
break;
|
|
}
|
|
|
|
if (!MemDbEnumNext (&Handle->AliasEnumStruct)) {
|
|
Handle->State = CES_NEXT_COMPONENT;
|
|
} else {
|
|
Handle->State = CES_CHECK_ALIAS_FLAGS;
|
|
}
|
|
break;
|
|
|
|
case CES_CHECK_ALIAS_FLAGS:
|
|
EnumPtr->Preferred = ((Handle->AliasEnumStruct.Flags & MEMDB_FLAG_PREFERRED) != 0);
|
|
Handle->State = CES_NEXT_ALIAS;
|
|
|
|
if (Handle->EnumPreferredOnly) {
|
|
result = EnumPtr->Preferred;
|
|
} else if (Handle->EnumNonPreferredOnly) {
|
|
result = !EnumPtr->Preferred;
|
|
} else {
|
|
result = TRUE;
|
|
}
|
|
|
|
break;
|
|
|
|
case CES_NEXT_COMPONENT:
|
|
if (!MemDbEnumNext (&Handle->ComponentEnumStruct)) {
|
|
Handle->State = CES_DONE;
|
|
} else {
|
|
if (Handle->EnumAliases) {
|
|
Handle->State = CES_FIRST_ALIAS;
|
|
} else {
|
|
Handle->State = CES_NEXT_COMPONENT;
|
|
result = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Handle->State = CES_DONE;
|
|
break;
|
|
}
|
|
|
|
if (result) {
|
|
|
|
//
|
|
// Fill in all of the caller enum struct fields
|
|
//
|
|
|
|
EnumPtr->SkipToNextComponent = FALSE;
|
|
EnumPtr->ComponentString = Handle->ComponentEnumStruct.KeyName;
|
|
EnumPtr->Enabled = ((Handle->ComponentEnumStruct.Flags & MEMDB_FLAG_SELECTED) != 0);
|
|
EnumPtr->MasterGroup = Handle->ComponentEnumStruct.Value;
|
|
|
|
if (Handle->EnumAliases) {
|
|
p = _tcschr (Handle->AliasEnumStruct.FullKeyName, TEXT('\\'));
|
|
MYASSERT (p);
|
|
|
|
if (p) {
|
|
p = _tcschr (p + 1, TEXT('\\'));
|
|
MYASSERT (p);
|
|
}
|
|
|
|
if (p) {
|
|
p++;
|
|
if (_totlower (p[0]) == TEXT('u')) {
|
|
EnumPtr->UserSupplied = TRUE;
|
|
} else {
|
|
EnumPtr->UserSupplied = FALSE;
|
|
}
|
|
|
|
p = _tcschr (p, TEXT('\\'));
|
|
MYASSERT (p);
|
|
}
|
|
|
|
if (p) {
|
|
p++;
|
|
EnumPtr->GroupId = _tcstoul (p, (PTSTR *) (&p), 10);
|
|
MYASSERT (p && p[0] == TEXT('\\'));
|
|
}
|
|
|
|
if (p) {
|
|
EnumPtr->LocalizedAlias = p + 1;
|
|
}
|
|
|
|
//
|
|
// If group ID filter was specified, loop until a match is found
|
|
//
|
|
|
|
if (Handle->GroupIdFilter && Handle->GroupIdFilter != EnumPtr->GroupId) {
|
|
result = FALSE;
|
|
continue;
|
|
}
|
|
|
|
} else {
|
|
EnumPtr->Preferred = FALSE;
|
|
EnumPtr->UserSupplied = FALSE;
|
|
EnumPtr->GroupId = 0;
|
|
EnumPtr->LocalizedAlias = NULL;
|
|
}
|
|
|
|
EnumPtr->Instance++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!result) {
|
|
IsmAbortComponentEnum (EnumPtr);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
IsmEnumFirstComponent (
|
|
OUT PMIG_COMPONENT_ENUM EnumPtr,
|
|
IN DWORD Flags,
|
|
IN UINT GroupIdFilter OPTIONAL
|
|
)
|
|
{
|
|
PCOMPONENTENUM_HANDLE handle;
|
|
|
|
ZeroMemory (EnumPtr, sizeof (MIG_COMPONENT_ENUM));
|
|
|
|
if (Flags & (COMPONENTENUM_PREFERRED_ONLY|COMPONENTENUM_NON_PREFERRED_ONLY)) {
|
|
if (!(Flags & COMPONENTENUM_ALIASES)) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if ((Flags & (COMPONENTENUM_PREFERRED_ONLY|COMPONENTENUM_NON_PREFERRED_ONLY)) ==
|
|
(COMPONENTENUM_PREFERRED_ONLY|COMPONENTENUM_NON_PREFERRED_ONLY)
|
|
) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
EnumPtr->Handle = MemAllocUninit (sizeof (COMPONENTENUM_HANDLE));
|
|
handle = (PCOMPONENTENUM_HANDLE) EnumPtr->Handle;
|
|
handle->EnumAliases = Flags & COMPONENTENUM_ALIASES ? TRUE : FALSE;
|
|
handle->EnumEnabled = Flags & COMPONENTENUM_ENABLED ? TRUE : FALSE;
|
|
handle->EnumDisabled = Flags & COMPONENTENUM_DISABLED ? TRUE : FALSE;
|
|
handle->GroupIdFilter = GroupIdFilter;
|
|
handle->EnumPreferredOnly = Flags & COMPONENTENUM_PREFERRED_ONLY;
|
|
handle->EnumNonPreferredOnly = Flags & COMPONENTENUM_NON_PREFERRED_ONLY;
|
|
|
|
handle->State = CES_FIRST_COMPONENT;
|
|
|
|
return pEnumWorker (EnumPtr, handle);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
IsmEnumNextComponent (
|
|
IN OUT PMIG_COMPONENT_ENUM EnumPtr
|
|
)
|
|
{
|
|
PCOMPONENTENUM_HANDLE handle;
|
|
|
|
handle = (PCOMPONENTENUM_HANDLE) EnumPtr->Handle;
|
|
return pEnumWorker (EnumPtr, handle);
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
IsmAbortComponentEnum (
|
|
IN PMIG_COMPONENT_ENUM EnumPtr ZEROED
|
|
)
|
|
{
|
|
PCOMPONENTENUM_HANDLE handle;
|
|
|
|
handle = (PCOMPONENTENUM_HANDLE) EnumPtr->Handle;
|
|
if (handle) {
|
|
if (handle->State == CES_NEXT_COMPONENT) {
|
|
MemDbAbortEnum (&handle->ComponentEnumStruct);
|
|
}
|
|
|
|
if (handle->EnumAliases) {
|
|
if (handle->State == CES_NEXT_ALIAS) {
|
|
MemDbAbortEnum (&handle->AliasEnumStruct);
|
|
}
|
|
}
|
|
|
|
FreeAlloc (handle);
|
|
}
|
|
|
|
ZeroMemory (EnumPtr, sizeof (MIG_COMPONENT_ENUM));
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
IsmRemoveAllUserSuppliedComponents (
|
|
VOID
|
|
)
|
|
{
|
|
MEMDB_ENUM e;
|
|
MULTISZ_ENUM listEnum;
|
|
GROWBUFFER list = INIT_GROWBUFFER;
|
|
|
|
//
|
|
// Collect all the components that have user-supplied aliases. Then after
|
|
// enum completes, delete them. We don't delete during the enum because it
|
|
// is never a good idea to delete the item just enumerated, and then try
|
|
// to continue enumerating.
|
|
//
|
|
|
|
if (MemDbEnumFirst (
|
|
&e,
|
|
S_COMPONENT_ROOT TEXT("\\*\\") S_USER_SUPPLIED TEXT("\\*"),
|
|
ENUMFLAG_ALL,
|
|
2,
|
|
2
|
|
)) {
|
|
|
|
do {
|
|
GbMultiSzAppend (&list, e.FullKeyName);
|
|
} while (MemDbEnumNext (&e));
|
|
}
|
|
|
|
if (EnumFirstMultiSz (&listEnum, (PCTSTR) list.Buf)) {
|
|
do {
|
|
MemDbDeleteTree (listEnum.CurrentString);
|
|
} while (EnumNextMultiSz (&listEnum));
|
|
}
|
|
|
|
GbFree (&list);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
IsmSelectMasterGroup (
|
|
IN UINT MasterGroup,
|
|
IN BOOL Enable
|
|
)
|
|
{
|
|
MEMDB_ENUM e;
|
|
UINT flags;
|
|
|
|
if (MasterGroup > MASTERGROUP_ALL) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
DEBUGMSG ((DBG_ERROR, "Can't select invalid MasterGroup"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Enumerate all components and mark them enabled or disabled
|
|
// depending on the master group
|
|
//
|
|
|
|
if (MemDbEnumFirst (
|
|
&e,
|
|
S_COMPONENT_ROOT TEXT("\\*"),
|
|
ENUMFLAG_NORMAL,
|
|
1,
|
|
1
|
|
)) {
|
|
|
|
do {
|
|
if (MasterGroup == MASTERGROUP_ALL ||
|
|
MasterGroup == e.Value
|
|
) {
|
|
flags = Enable ? MEMDB_FLAG_SELECTED : 0;
|
|
} else {
|
|
flags = 0;
|
|
}
|
|
|
|
if (!MemDbSetFlags (e.FullKeyName, flags, MEMDB_FLAG_SELECTED)) {
|
|
EngineError ();
|
|
MemDbAbortEnum (&e);
|
|
return FALSE;
|
|
}
|
|
|
|
} while (MemDbEnumNext (&e));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
IsmIsComponentSelected (
|
|
IN PCTSTR ComponentOrAlias,
|
|
IN UINT ComponentGroupId OPTIONAL
|
|
)
|
|
{
|
|
UINT flags = 0;
|
|
TCHAR memdbNode[MAX_CONTROLLED_NODE_SIZE];
|
|
PCTSTR componentNode;
|
|
|
|
if (!ComponentGroupId) {
|
|
if (!pCheckComponentName (ComponentOrAlias)) {
|
|
return FALSE;
|
|
}
|
|
// This is safe since ComponentOrAlias was already checked for length by pCheckComponentName
|
|
wsprintf (memdbNode, TEXT("%s\\%s"), S_COMPONENT_ROOT, ComponentOrAlias);
|
|
MemDbGetFlags (memdbNode, &flags);
|
|
} else {
|
|
if (pFindComponent (ComponentOrAlias, ComponentGroupId, &componentNode, NULL)) {
|
|
MemDbGetFlags (componentNode, &flags);
|
|
FreeText (componentNode);
|
|
}
|
|
}
|
|
|
|
return (flags & MEMDB_FLAG_SELECTED) != 0;
|
|
}
|
|
|
|
|