/*++

Copyright (c) 1996  Microsoft Corporation

Module Name:

    enum.c

Abstract:

    Server side support for Cluster APIs dealing with enumeration

Author:

    John Vert (jvert) 9-Feb-1996

Revision History:

--*/
#include "apip.h"

#define ENUM_SIZE(Entries) ((Entries-1) * sizeof(ENUM_ENTRY) + sizeof(ENUM_LIST))

//
// Define structure passed to enumeration routine.
//
typedef struct _REFOBJECT {
    HDMKEY RootKey;
    LPCWSTR FriendlyName;
    DWORD NameLength;
    LPWSTR NameBuffer;
    OBJECT_TYPE Type;
} REFOBJECT, *PREFOBJECT;

BOOL
ApipRefObjectWorker(
    IN PREFOBJECT Target,
    IN PVOID *pObject,
    IN PVOID Object,
    IN LPCWSTR ObjectId
    );

BOOL
ApipEnumResourceWorker(
    IN PENUM_LIST *pEnum,
    IN PVOID Context2,
    IN PFM_RESOURCE Node,
    IN LPCWSTR Name
    );

BOOL
ApipEnumGroupResourceWorker(
    IN PENUM_LIST *pEnum,
    IN PVOID Context2,
    IN PFM_RESOURCE Node,
    IN LPCWSTR Name
    );

BOOL
ApipEnumNodeWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PNM_NODE Node,
    IN LPCWSTR Name
    );


BOOL
ApipEnumResTypeWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PFM_RESTYPE ResType,
    IN LPCWSTR Name
    );

BOOL
ApipEnumGroupWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PFM_GROUP Group,
    IN LPCWSTR Name
    );

BOOL
ApipEnumNetworkWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PVOID Object,
    IN LPCWSTR Name
    );

DWORD
ApipEnumInternalNetworks(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated
    );

BOOL
ApipEnumNetworkInterfaceWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PVOID Object,
    IN LPCWSTR Name
    );

VOID
ApipFreeEnum(
    IN PENUM_LIST Enum
    );



error_status_t
s_ApiCreateEnum(
    IN handle_t IDL_handle,
    IN DWORD dwType,
    OUT PENUM_LIST *ReturnEnum
    )

/*++

Routine Description:

    Enumerates all the specified objects and returns the
    list of objects to the caller. The client-side is
    responsible for freeing the allocated memory.

Arguments:

    IDL_handle - RPC binding handle, not used

    dwType - Supplies the type of objects to be enumerated

    ReturnEnum - Returns the requested objects.

Return Value:

    ERROR_SUCCESS if successful

    Win32 error code otherwise.

--*/

{
    DWORD Status;
    DWORD Allocated = 0;
    PENUM_LIST Enum = NULL;

    //initialize to NULL for failure cases
    *ReturnEnum = NULL;

    if (dwType != CLUSTER_ENUM_NODE) {
        API_CHECK_INIT();
    }

    if (dwType & CLUSTER_ENUM_INTERNAL_NETWORK) {
        if ((dwType & ~CLUSTER_ENUM_INTERNAL_NETWORK) != 0) {
            return(ERROR_INVALID_PARAMETER);
        }
    }
    else {
        if (dwType & ~CLUSTER_ENUM_ALL) {
            return(ERROR_INVALID_PARAMETER);
        }
    }

    Allocated = INITIAL_ENUM_LIST_ALLOCATION;
    Enum = MIDL_user_allocate(ENUM_SIZE(Allocated));
    if (Enum == NULL) {
        Status = ERROR_NOT_ENOUGH_MEMORY;
        goto ErrorExit;
    }
    Enum->EntryCount = 0;

    //
    // Enumerate all nodes
    //
    if (dwType & CLUSTER_ENUM_NODE) {
        OmEnumObjects(ObjectTypeNode,
                      ApipEnumNodeWorker,
                      &Enum,
                      &Allocated);

    }

    //
    // Enumerate all resource types
    //
    if (dwType & CLUSTER_ENUM_RESTYPE) {
        OmEnumObjects(ObjectTypeResType,
                      ApipEnumResTypeWorker,
                      &Enum,
                      &Allocated);
    }

    //
    // Enumerate all resources
    //
    if (dwType & CLUSTER_ENUM_RESOURCE) {
        OmEnumObjects(ObjectTypeResource,
                      ApipEnumResourceWorker,
                      &Enum,
                      &Allocated);

    }

    //
    // Enumerate all groups
    //
    if (dwType & CLUSTER_ENUM_GROUP) {
        OmEnumObjects(ObjectTypeGroup,
                      ApipEnumGroupWorker,
                      &Enum,
                      &Allocated);

    }

    //
    // Enumerate all networks
    //
    if (dwType & CLUSTER_ENUM_NETWORK) {
        OmEnumObjects(ObjectTypeNetwork,
                      ApipEnumNetworkWorker,
                      &Enum,
                      &Allocated);
    }

    //
    // Enumerate internal networks in highest to lowest priority order.
    //
    if (dwType & CLUSTER_ENUM_INTERNAL_NETWORK) {
        Status = ApipEnumInternalNetworks(&Enum, &Allocated);

        if (Status != ERROR_SUCCESS) {
            goto ErrorExit;
        }
    }

    //
    // Enumerate all network interfaces
    //
    if (dwType & CLUSTER_ENUM_NETINTERFACE) {
        OmEnumObjects(ObjectTypeNetInterface,
                      ApipEnumNetworkInterfaceWorker,
                      &Enum,
                      &Allocated);
    }

    *ReturnEnum = Enum;
    return(ERROR_SUCCESS);

ErrorExit:

    if (Enum != NULL) {
        ApipFreeEnum(Enum);
    }

    return(Status);

}


VOID
ApipFreeEnum(
    IN PENUM_LIST Enum
    )
/*++

Routine Description:

    Frees an ENUM_LIST and all of its strings.

Arguments:

    Enum - Supplies the Enum to free.

Return Value:

    None.

--*/

{
    DWORD i;

    //
    // Walk through enumeration freeing all the names
    //
    for (i=0; i<Enum->EntryCount; i++) {
        MIDL_user_free(Enum->Entry[i].Name);
    }
    MIDL_user_free(Enum);
}


VOID
ApipAddToEnum(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN LPCWSTR Name,
    IN DWORD Type
    )

/*++

Routine Description:

    Common worker callback routine for enumerating objects.
    Adds the specified resource to the list that is being
    built up.

Arguments:

    pEnum - Supplies a pointer to the current enumeration list.

    pAllocated - Supplies a pointer to a dword specifying the current
        allocation size of the ENUM_LIST.

    Name - Supplies the name of the object to be added to the ENUM_LIST.

           A copy of this name will be created by using MIDL_user_allocate.

    Type - Supplies the object's type

Return Value:

    None


--*/

{
    PENUM_LIST Enum;
    PENUM_LIST NewEnum;
    DWORD NewAllocated;
    DWORD Index;
    LPWSTR NewName;

    NewName = MIDL_user_allocate((lstrlenW(Name)+1)*sizeof(WCHAR));
    if (NewName == NULL) {
        CL_UNEXPECTED_ERROR( ERROR_NOT_ENOUGH_MEMORY );
        return;
    }
    lstrcpyW(NewName, Name);
    Enum = *pEnum;
    if (Enum->EntryCount >= *pAllocated) {
        //
        // Need to grow the ENUM_LIST
        //
        NewAllocated = *pAllocated + 8;
        NewEnum = MIDL_user_allocate(ENUM_SIZE(NewAllocated));
        if (NewEnum == NULL) {
            MIDL_user_free(NewName);
            return;
        }
        CopyMemory(NewEnum, Enum, ENUM_SIZE(*pAllocated));
        CL_ASSERT( Enum->EntryCount == NewEnum->EntryCount );
        *pAllocated = NewAllocated;
        *pEnum = NewEnum;
        MIDL_user_free(Enum);
        Enum = NewEnum;
    }

    //
    // Initialize new entry field.
    //
    Enum->Entry[Enum->EntryCount].Name = NewName;
    Enum->Entry[Enum->EntryCount].Type = Type;
    ++Enum->EntryCount;

    return;
}



BOOL
ApipEnumResourceWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PFM_RESOURCE Resource,
    IN LPCWSTR Name
    )

/*++

Routine Description:

    Worker callback routine for the enumeration of resources.
    Adds the specified resource to the list that is being
    built up.

Arguments:

    pEnum - Supplies a pointer to the current enumeration list.

    pAllocated - Supplies a pointer to a dword specifying the current
        allocation size of the ENUM_LIST.

    Resource - Supplies the resource to be added to the ENUM_LIST

    Name - Supplies the resource's name

Return Value:

    TRUE to indicate that enumeration should continue.


--*/
{
    LPWSTR RealName;

    RealName = ApipGetObjectName(Resource);
    if (RealName != NULL) {
        ApipAddToEnum(pEnum,
                      pAllocated,
                      RealName,
                      CLUSTER_ENUM_RESOURCE);
        MIDL_user_free( RealName);
    }
    return(TRUE);
}


BOOL
ApipEnumGroupResourceWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PFM_RESOURCE Resource,
    IN LPCWSTR Name
    )

/*++

Routine Description:

    Worker callback routine for the enumeration of resources.
    Adds the specified resource to the list that is being
    built up.

Arguments:

    pEnum - Supplies a pointer to the current enumeration list.

    pAllocated - Supplies a pointer to a dword specifying the current
        allocation size of the ENUM_LIST.

    Resource - Supplies the resource to be added to the ENUM_LIST

    Name - Supplies the resource's name

Return Value:

    TRUE to indicate that enumeration should continue.


--*/
{
    LPWSTR RealName;

    RealName = ApipGetObjectName(Resource);
    if (RealName != NULL) {
        ApipAddToEnum(pEnum,
                      pAllocated,
                      RealName,
                      CLUSTER_GROUP_ENUM_CONTAINS);
        MIDL_user_free( RealName );
    }
    return(TRUE);
}


BOOL
ApipEnumNodeWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PNM_NODE Node,
    IN LPCWSTR Name
    )

/*++

Routine Description:

    Worker callback routine for the enumeration of nodes.
    Adds the specified node to the list that is being
    built up.

Arguments:

    pEnum - Supplies a pointer to the current enumeration list.

    pAllocated - Supplies a pointer to a dword specifying the current
        allocation size of the ENUM_LIST.

    Node - Supplies the node to be added to the ENUM_LIST

    Name - Supplies the node's name

Return Value:

    TRUE to indicate that enumeration should continue.


--*/
{
    LPCWSTR RealName;

    RealName = OmObjectName(Node);
    if (RealName != NULL) {
        ApipAddToEnum(pEnum,
                      pAllocated,
                      RealName,
                      CLUSTER_ENUM_NODE);
    }
    return(TRUE);
}


BOOL
ApipEnumResTypeWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PFM_RESTYPE ResType,
    IN LPCWSTR Name
    )

/*++

Routine Description:

    Worker callback routine for the enumeration of resource types.
    Adds the specified resource type to the list that is being
    built up.

Arguments:

    pEnum - Supplies a pointer to the current enumeration list.

    pAllocated - Supplies a pointer to a dword specifying the current
        allocation size of the ENUM_LIST.

    Node - Supplies the resource type to be added to the ENUM_LIST

    Name - Supplies the resource type's name

Return Value:

    TRUE to indicate that enumeration should continue.


--*/
{
    ApipAddToEnum(pEnum,
                  pAllocated,
                  Name,
                  CLUSTER_ENUM_RESTYPE);
    return(TRUE);
}


BOOL
ApipEnumGroupWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PFM_GROUP Group,
    IN LPCWSTR Name
    )

/*++

Routine Description:

    Worker callback routine for the enumeration of groups.
    Adds the specified group to the list that is being
    built up.

Arguments:

    pEnum - Supplies a pointer to the current enumeration list.

    pAllocated - Supplies a pointer to a dword specifying the current
        allocation size of the ENUM_LIST.

    Group - Supplies the group to be added to the ENUM_LIST

    Name - Supplies the group's name

Return Value:

    TRUE to indicate that enumeration should continue.


--*/
{
    LPCWSTR RealName;

    RealName = OmObjectName(Group);
    if (RealName != NULL) {
        ApipAddToEnum(pEnum,
                      pAllocated,
                      RealName,
                      CLUSTER_ENUM_GROUP);
    }
    return(TRUE);
}



BOOL
ApipEnumNetworkWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PVOID Object,
    IN LPCWSTR Name
    )

/*++

Routine Description:

    Worker callback routine for the enumeration of networks.
    Adds the specified network to the list that is being
    built up.

Arguments:

    pEnum - Supplies a pointer to the current enumeration list.

    pAllocated - Supplies a pointer to a dword specifying the current
        allocation size of the ENUM_LIST.

    Object - Supplies the object to be added to the ENUM_LIST

    Name - Supplies the network's name

Return Value:

    TRUE to indicate that enumeration should continue.


--*/
{
    LPWSTR RealName;

    RealName = ApipGetObjectName(Object);
    if (RealName != NULL) {
        ApipAddToEnum(pEnum,
                      pAllocated,
                      RealName,
                      CLUSTER_ENUM_NETWORK);
        MIDL_user_free( RealName );
    }
    return(TRUE);
}


DWORD
ApipEnumInternalNetworks(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated
    )

/*++

Routine Description:

    Enumerates all networks used for internal communication.

Arguments:

    pEnum - Supplies a pointer to the current enumeration list.

    pAllocated - Supplies a pointer to a dword specifying the current
        allocation size of the ENUM_LIST.

Return Value:

    ERROR_SUCCESS if successful

    Win32 error code otherwise.

--*/

{
    DWORD         Status;
    DWORD         NetworkCount;
    PNM_NETWORK  *NetworkList;
    DWORD         i;
    LPWSTR        RealName;


    Status = NmEnumInternalNetworks(&NetworkCount, &NetworkList);

    if (Status != ERROR_SUCCESS) {
        return(Status);
    }

    for (i=0; i<NetworkCount; i++) {
        RealName = ApipGetObjectName(NetworkList[i]);

        if (RealName != NULL) {
            ApipAddToEnum(pEnum,
                          pAllocated,
                          RealName,
                          (DWORD) CLUSTER_ENUM_INTERNAL_NETWORK);
            MIDL_user_free( RealName );
        }

        OmDereferenceObject(NetworkList[i]);
    }

    if (NetworkList != NULL) {
        LocalFree(NetworkList);
    }

    return(ERROR_SUCCESS);

}


BOOL
ApipEnumNetworkInterfaceWorker(
    IN PENUM_LIST *pEnum,
    IN DWORD *pAllocated,
    IN PVOID Object,
    IN LPCWSTR Name
    )

/*++

Routine Description:

    Worker callback routine for the enumeration of network interfaces.
    Adds the specified network interface to the list that is being
    built up.

Arguments:

    pEnum - Supplies a pointer to the current enumeration list.

    pAllocated - Supplies a pointer to a dword specifying the current
        allocation size of the ENUM_LIST.

    Object - Supplies the object to be added to the ENUM_LIST

    Name - Supplies the network interface's name

Return Value:

    TRUE to indicate that enumeration should continue.


--*/
{
    LPWSTR RealName;

    RealName = ApipGetObjectName(Object);
    if (RealName != NULL) {
        ApipAddToEnum(pEnum,
                      pAllocated,
                      RealName,
                      CLUSTER_ENUM_NETINTERFACE);
        MIDL_user_free( RealName );
    }
    return(TRUE);
}


error_status_t
s_ApiCreateNodeEnum(
    IN HNODE_RPC hNode,
    IN DWORD dwType,
    OUT PENUM_LIST *ReturnEnum
    )

/*++

Routine Description:

    Enumerates all the resource objects contained in the specified
    node and returns them to the caller. The client-side is
    responsible for freeing the allocated memory.

Arguments:

    hNode - Supplies the node to be enumerated

    dwType - Supplies a bitmask of the type of properties to be
            enumerated.

    ReturnEnum - Returns the requested objects.

Return Value:

    ERROR_SUCCESS if successful

    Win32 error code otherwise.

--*/

{
    DWORD Status;
    DWORD Allocated = 0;
    PENUM_LIST Enum = NULL;
    PNM_INTERFACE * InterfaceList;
    DWORD InterfaceCount;
    PNM_NODE Node;
    DWORD i;


    API_CHECK_INIT();

    VALIDATE_NODE_EXISTS(Node, hNode);

    Allocated = INITIAL_ENUM_LIST_ALLOCATION;
    Enum = MIDL_user_allocate(ENUM_SIZE(Allocated));

    if (Enum == NULL) {
        Status = ERROR_NOT_ENOUGH_MEMORY;
        goto ErrorExit;
    }

    Enum->EntryCount = 0;

    if (dwType & CLUSTER_NODE_ENUM_NETINTERFACES) {
        Status = NmEnumNodeInterfaces(
                     Node,
                     &InterfaceCount,
                     &InterfaceList
                     );

        if (Status != ERROR_SUCCESS) {
            goto ErrorExit;
        }

        for (i=0; i<InterfaceCount; i++) {
            ApipAddToEnum(&Enum,
                          &Allocated,
                          OmObjectName(InterfaceList[i]),
                          CLUSTER_NODE_ENUM_NETINTERFACES);
            OmDereferenceObject(InterfaceList[i]);
        }

        if (InterfaceList != NULL) {
            LocalFree(InterfaceList);
        }
    }

    *ReturnEnum = Enum;

    return(ERROR_SUCCESS);

ErrorExit:
    if (Enum != NULL) {
        ApipFreeEnum(Enum);
    }

    *ReturnEnum = NULL;
    return(Status);

}


error_status_t
s_ApiCreateGroupResourceEnum(
    IN HGROUP_RPC hGroup,
    IN DWORD dwType,
    OUT PENUM_LIST *ReturnEnum
    )

/*++

Routine Description:

    Enumerates all the resource objects contained in the specified
    group and returns them to the caller. The client-side is
    responsible for freeing the allocated memory.

Arguments:

    hGroup - Supplies the group to be enumerated

    dwType - Supplies a bitmask of the type of properties to be
            enumerated. Currently defined types include

            CLUSTER_GROUP_ENUM_CONTAINS  - All resources contained in the specified
                                           group

            CLUSTER_GROUP_ENUM_NODES     - All nodes in the specified group's preferred
                                           owner list.

    ReturnEnum - Returns the requested objects.

Return Value:

    ERROR_SUCCESS if successful

    Win32 error code otherwise.

--*/

{
    DWORD Status;
    DWORD Allocated = 0;
    PENUM_LIST Enum = NULL;
    PFM_GROUP Group;

    API_CHECK_INIT();

    VALIDATE_GROUP_EXISTS(Group, hGroup);

    Allocated = INITIAL_ENUM_LIST_ALLOCATION;
    Enum = MIDL_user_allocate(ENUM_SIZE(Allocated));
    if (Enum == NULL) {
        Status = ERROR_NOT_ENOUGH_MEMORY;
        goto ErrorExit;
    }
    Enum->EntryCount = 0;

    //
    // Enumerate all contained resources
    //
    if (dwType & CLUSTER_GROUP_ENUM_CONTAINS) {
        //
        // Enumerate all resources for the Group.
        //
        Status = FmEnumerateGroupResources(Group,
                                  ApipEnumGroupResourceWorker,
                                  &Enum,
                                  &Allocated);
        if ( Status != ERROR_SUCCESS ) {
            goto ErrorExit;
        }
    }

    if (dwType & CLUSTER_GROUP_ENUM_NODES) {
        LPWSTR Buffer=NULL;
        DWORD BufferSize=0;
        DWORD DataSize=0;
        DWORD i;
        HDMKEY GroupKey;
        LPCWSTR Next;
        PNM_NODE Node;

        //
        // Enumerate all preferred nodes for the group.
        // Just get this data right out of the registry.
        //
        GroupKey = DmOpenKey(DmGroupsKey,
                             OmObjectId(Group),
                             KEY_READ);
        if (GroupKey == NULL) {
            Status = GetLastError();
            goto ErrorExit;
        }
        Status = DmQueryMultiSz(GroupKey,
                                CLUSREG_NAME_GRP_PREFERRED_OWNERS,
                                &Buffer,
                                &BufferSize,
                                &DataSize);
        DmCloseKey(GroupKey);
        if (Status != ERROR_FILE_NOT_FOUND) {
            if (Status != ERROR_SUCCESS) {
                //
                //  Chittur Subbaraman (chitturs) - 10/05/98
                //  Fix memory leak
                //
                LocalFree(Buffer);
                goto ErrorExit;
            }
            for (i=0; ; i++) {
                Next = ClRtlMultiSzEnum(Buffer, DataSize/sizeof(WCHAR), i);
                if (Next == NULL) {
                    Status = ERROR_SUCCESS;
                    break;
                }
                Node = OmReferenceObjectById(ObjectTypeNode, Next);
                if (Node != NULL) {
                    ApipAddToEnum(&Enum,
                                  &Allocated,
                                  OmObjectName(Node),
                                  CLUSTER_GROUP_ENUM_NODES);
                    OmDereferenceObject(Node);
                }

            }
        }
        //
        //  Chittur Subbaraman (chitturs) - 10/05/98
        //  Fix memory leak
        //
        LocalFree(Buffer);
    }

    *ReturnEnum = Enum;
    return(ERROR_SUCCESS);

ErrorExit:
    if (Enum != NULL) {
        ApipFreeEnum(Enum);
    }

    *ReturnEnum = NULL;
    return(Status);

}


error_status_t
s_ApiCreateNetworkEnum(
    IN HNETWORK_RPC hNetwork,
    IN DWORD dwType,
    OUT PENUM_LIST *ReturnEnum
    )

/*++

Routine Description:

    Enumerates all the interface objects contained in the specified
    network and returns them to the caller. The client-side is
    responsible for freeing the allocated memory.

Arguments:

    hNetwork - Supplies the network to be enumerated

    dwType - Supplies a bitmask of the type of properties to be
            enumerated.

    ReturnEnum - Returns the requested objects.

Return Value:

    ERROR_SUCCESS if successful

    Win32 error code otherwise.

--*/

{
    DWORD Status;
    DWORD Allocated = 0;
    PENUM_LIST Enum = NULL;
    PNM_INTERFACE * InterfaceList;
    DWORD InterfaceCount;
    PNM_NETWORK Network;
    DWORD i;


    API_CHECK_INIT();

    VALIDATE_NETWORK_EXISTS(Network, hNetwork);

    Allocated = INITIAL_ENUM_LIST_ALLOCATION;
    Enum = MIDL_user_allocate(ENUM_SIZE(Allocated));

    if (Enum == NULL) {
        Status = ERROR_NOT_ENOUGH_MEMORY;
        goto ErrorExit;
    }

    Enum->EntryCount = 0;

    if (dwType & CLUSTER_NETWORK_ENUM_NETINTERFACES) {
        Status = NmEnumNetworkInterfaces(
                     Network,
                     &InterfaceCount,
                     &InterfaceList
                     );

        if (Status != ERROR_SUCCESS) {
            goto ErrorExit;
        }

        for (i=0; i<InterfaceCount; i++) {
            ApipAddToEnum(&Enum,
                          &Allocated,
                          OmObjectName(InterfaceList[i]),
                          CLUSTER_NETWORK_ENUM_NETINTERFACES);
            OmDereferenceObject(InterfaceList[i]);
        }

        if (InterfaceList != NULL) {
            LocalFree(InterfaceList);
        }
    }

    *ReturnEnum = Enum;

    return(ERROR_SUCCESS);

ErrorExit:
    if (Enum != NULL) {
        ApipFreeEnum(Enum);
    }

    *ReturnEnum = NULL;
    return(Status);

}


BOOL
ApipRefObjectWorker(
    IN PREFOBJECT Target,
    IN PVOID *pObject,
    IN PVOID Object,
    IN LPCWSTR ObjectId
    )

/*++

Routine Description:

    Enumeration worker for ApipReferenceObjectByName.

Arguments:

    Target - Supplies the friendly name that is to be referenced.

    pObject - Returns the object found, if any.

    Object - Supplies the current object being enumerated.

    ObjectId - Supplies the identifier (GUID) of the current object being
            enumerated.

Return Value:

    TRUE - Object did not match. Enumeration should continue.

    FALSE - Object match was found. Enumeration should stop.

--*/

{
    HDMKEY Key;
    DWORD Size;
    DWORD Status;
    DWORD Type;

    Key = DmOpenKey(Target->RootKey,
                    ObjectId,
                    KEY_READ);
    if (Key == NULL) {
        CL_UNEXPECTED_ERROR(GetLastError());
        return(TRUE);
    }

    Size = Target->NameLength;
    Status = DmQueryValue(Key,
                          L"Name",
                          &Type,
                          (UCHAR *)Target->NameBuffer,
                          &Size);
    DmCloseKey(Key);
    if ((Status == ERROR_SUCCESS) &&
        (lstrcmpiW(Target->NameBuffer, Target->FriendlyName)==0)) {
        //
        // Found a match. Reference it and return it.
        //
        OmReferenceObject(Object);
        *pObject = Object;
        return(FALSE);
    }
    //
    // Mismatch.
    //
    return(TRUE);

}


LPWSTR
ApipGetObjectName(
    IN PVOID Object
    )

/*++

Routine Description:

    Allocates a string and fills in the object's name.

Arguments:

    Object - A pointer to the object to get its name.

Return Value:

    A pointer to a WSTR that contains the user-friendly name of the object.
    NULL on failure - use GetLastError to get the Win32 error code.

--*/

{
    LPWSTR  Name;
    DWORD   NameSize;

    if ( OmObjectName(Object) == NULL ) {
        Name = MIDL_user_allocate(1 * sizeof(WCHAR));
        if ( Name != NULL ) {
            *Name = (WCHAR)0;
        } else {
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        }
    } else {
        NameSize = lstrlenW(OmObjectName(Object));
        Name = MIDL_user_allocate((NameSize + 1) * sizeof(WCHAR));
        if ( Name != NULL ) {
            lstrcpyW( Name, OmObjectName(Object) );
        } else {
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        }
    }

    return(Name);

} // ApipGetObjectName