HRESULT ObjectReferences(    ObjectID objectId,    ClassID classId,    ULONG    cObjectRefs,    ObjectID objectRefIds[]  );  

struct ObjectNode
{
public:
    ObjectNode(ObjectID objectId);
 
public:
    ObjectID instance;
    std::vector<ObjectNode*> rootRefs;
};
 
bool DumpNode(ObjectNode* node, std::vector<ObjectID>& referenceStack)
{
    // end of recursion: the node is a root
    if (node->rootRefs.size() == 0)
    {
        //  dump the root
        std::cout << std::endl;
        std::cout << std::hex << node->instance << std::dec;
        COR_PRF_GC_ROOT_KIND kind;
        COR_PRF_GC_ROOT_FLAGS flags;
        if (FindRoot(_roots, node->instance, kind, flags))
        {
            std::cout << " | ";
            DumpKind(kind);
            std::cout << " - ";
            DumpFlags(flags);
        }
        else
        {
            std::cout << " | ?";
        }
        std::cout << " = ";
 
        DumpObjectType(node->instance, _pCorProfilerInfo, _pFrameStore);
        std::cout << std::endl;
 
        // dump the references from the root
        for (int16_t i = referenceStack.size()-1; i >= 0; i--)
        {
            ObjectID reference = referenceStack[i];
            std::cout << " --> ";
            std::cout << std::hex << reference << std::dec;
            std::cout << " = ";
            DumpObjectType(reference, _pCorProfilerInfo, _pFrameStore);
            std::cout << std::endl;
        }
 
        return true;
    }
 
    // detect cycles
    if (Find(referenceStack, node->instance))
    {
        return false;
    }
 
    // go up into the reference chain
    referenceStack.push_back(node->instance);
    for (auto& parentNode : node->rootRefs)
    {
        if (DumpNode(parentNode, referenceStack))
        {
            return true;
        }
    }
    referenceStack.pop_back();
 
    return false;
}

 
struct ObjectRoot
{
public:
    ObjectID instance;
    COR_PRF_GC_ROOT_KIND kind;
    COR_PRF_GC_ROOT_FLAGS flags;
};