通过代码在typelib文件中查找依赖的类型库

Find dependent type libraries in typelib file through code

正在寻找一种方法来查找类型库的依赖类型库。比如在IDL中声明依赖库时,一个普通的依赖是stdole2.tlb,声明为:

导入库("stdole2.tlb");

我可以使用 OleView.exe 来查看这些依赖项,但我正在尝试找出如何在代码中执行此操作。 ITypeLib 或 ITypeLib2 接口中似乎没有任何成员可以获取这些依赖项。我搜索了 OLE 自动化参考,但没有找到获取接口的方法。

它们是否以某种方式采用类型库的二进制资源格式?

有人能给我指出正确的方向吗?

这是类型库的 GetDependencies 函数的完整实现。

这将 return 一个 unordered_set of ITypeLibPtr smart pointers. Note the hashing function, which enables these smart pointers to be used in unordered_set 和其他哈希容器。

这只是return一级依赖。如果那些类型库有额外的依赖关系,您可以以某种递归方式使用此方法来获得一组完整的依赖关系(第一级和更高级别)。

循环引用(例如,IInterfaceA 有一个 属性,return 是一个 IInterfaceB 指针,而 IInterfaceB 有一个 属性,它returns 一个 IInterfaceA 指针)通过在类型库中爬行时存储所访问 ITypeInfos 的 unordered_set 来支持。

此代码旨在抛出 _com_error 异常(除了使用 unordered_set 时可能发生的任何 STL 异常)。酌情处理这些。如果您不想处理 _com_error 异常,请将 _com_util::CheckError 调用替换为您自己的 HRESULT 值的错误处理逻辑。

#include <windows.h>
#include <comdef.h>
#include <unordered_set>

// gets dependencies of a type library
std::unordered_set<ITypeLibPtr> GetDependencies(ITypeLib* pTypeLib);

// gathers dependencies of a type library
void GetDependenciesHelper(ITypeLib* pTypeLib, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput);

// gathers dependencies of a type
void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput);

// gathers dependencies of a reference
void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, HREFTYPE hRefType, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput);

// gathers dependencies of a reference
void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, TYPEDESC& referencedTypeDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput);

// gathers dependencies of a function declaration
void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, FUNCDESC& functionDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput);

// gathers dependencies of a variable declaration
void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, VARDESC& variableDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput);

// gathers dependencies of an array declaration
void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, ARRAYDESC& arrayDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput);

// gathers dependencies of an array element declaration
void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, ELEMDESC& elementDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput);

namespace std
{
    // provides a function for hashing ITypeLibPtr instances by their raw address
    template<> struct hash<ITypeLibPtr>
    {
        size_t operator()(ITypeLibPtr const& pTypeLib) const { return pTypeLib; }
    };
    // provides a function for hashing ITypeInfo instances by their raw address
    template<> struct hash<ITypeInfoPtr>
    {
        size_t operator()(ITypeInfoPtr const& pTypeInfo) const { return pTypeInfo; }
    };
}

std::unordered_set<ITypeLibPtr> GetDependencies(ITypeLib* pTypeLib)
{
    // get dependencies
    std::unordered_set<ITypeLibPtr> output;
    std::unordered_set<ITypeInfoPtr> history;
    GetDependenciesHelper(pTypeLib, &history, &output);
    return output;
}

void GetDependenciesHelper(ITypeLib* pTypeLib, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput)
{
    // iterate over type infos
    auto typeInfoCount = pTypeLib->GetTypeInfoCount();
    for (UINT typeInfoIndex = 0; typeInfoIndex < typeInfoCount; ++typeInfoIndex)
    {
        // get type info
        ITypeInfoPtr pTypeInfo;
        _com_util::CheckError(pTypeLib->GetTypeInfo(typeInfoIndex, &pTypeInfo));

        // get dependencies for type info
        GetDependenciesHelper(pTypeLib, pTypeInfo, pHistory, pOutput);
    }
}

void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput)
{
    // short-circuit if we've already processed this type info
    if (!pHistory->insert(pTypeInfo).second)
        return;

    // get type attributes
    TYPEATTR* typeAttributes;
    _com_util::CheckError(pTypeInfo->GetTypeAttr(&typeAttributes));
    try
    {
        // special handling for aliases
        if (typeAttributes->typekind == TKIND_ALIAS)
        {
            // get dependencies of the alias
            GetDependenciesHelper(pTypeLib, pTypeInfo, typeAttributes->tdescAlias, pHistory, pOutput);
        }
        else
        {
            // iterate over implemented types
            auto implementedTypeCount = typeAttributes->cImplTypes;
            for (WORD implementedTypeIndex = 0; implementedTypeIndex < implementedTypeCount; ++implementedTypeIndex)
            {
                // get type reference
                HREFTYPE hRefType;
                _com_util::CheckError(pTypeInfo->GetRefTypeOfImplType(implementedTypeIndex, &hRefType));

                // get dependencies of the implementation
                GetDependenciesHelper(pTypeLib, pTypeInfo, hRefType, pHistory, pOutput);
            }

            // iterate over functions
            auto functionCount = typeAttributes->cFuncs;
            for (WORD functionIndex = 0; functionIndex < functionCount; ++functionIndex)
            {
                // get function description
                FUNCDESC* functionDescription;
                _com_util::CheckError(pTypeInfo->GetFuncDesc(functionIndex, &functionDescription));
                try
                {
                    // get dependencies of the function declaration
                    GetDependenciesHelper(pTypeLib, pTypeInfo, *functionDescription, pHistory, pOutput);
                }
                catch (...)
                {
                    // release function description
                    pTypeInfo->ReleaseFuncDesc(functionDescription);
                    throw;
                }

                // release function description
                pTypeInfo->ReleaseFuncDesc(functionDescription);
            }

            // iterate over variables
            auto variableCount = typeAttributes->cVars;
            for (WORD variableIndex = 0; variableIndex < variableCount; ++variableIndex)
            {
                // get variable description
                VARDESC* variableDescription;
                _com_util::CheckError(pTypeInfo->GetVarDesc(variableIndex, &variableDescription));
                try
                {
                    // get dependencies of the variable declaration
                    GetDependenciesHelper(pTypeLib, pTypeInfo, *variableDescription, pHistory, pOutput);
                }
                catch (...)
                {
                    // release variable description
                    pTypeInfo->ReleaseVarDesc(variableDescription);
                    throw;
                }

                // release variable description
                pTypeInfo->ReleaseVarDesc(variableDescription);
            }
        }
    }
    catch (...)
    {
        // release type attributes
        pTypeInfo->ReleaseTypeAttr(typeAttributes);
        throw;
    }

    // release type attributes
    pTypeInfo->ReleaseTypeAttr(typeAttributes);
}

void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, HREFTYPE hRefType, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput)
{
    // get referenced type info
    ITypeInfoPtr referencedTypeInfo;
    _com_util::CheckError(pTypeInfo->GetRefTypeInfo(hRefType, &referencedTypeInfo));

    // get referenced type lib
    ITypeLibPtr referencedTypeLibrary;
    UINT referencedTypeInfoIndex;
    _com_util::CheckError(referencedTypeInfo->GetContainingTypeLib(&referencedTypeLibrary, &referencedTypeInfoIndex));

    // store dependency
    if (referencedTypeLibrary != pTypeLib)
        pOutput->insert(referencedTypeLibrary);
}

void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, TYPEDESC& referencedTypeDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput)
{
    switch (referencedTypeDescription.vt)
    {
        case VT_PTR:
        {
            // get dependencies of the pointer declaration
            GetDependenciesHelper(pTypeLib, pTypeInfo, *referencedTypeDescription.lptdesc, pHistory, pOutput);
            break;
        }
        case VT_CARRAY:
        {
            // get dependencies of the array declaration
            GetDependenciesHelper(pTypeLib, pTypeInfo, *referencedTypeDescription.lpadesc, pHistory, pOutput);
            break;
        }
        case VT_USERDEFINED:
        {
            // get dependencies of the UDT reference
            GetDependenciesHelper(pTypeLib, pTypeInfo, referencedTypeDescription.hreftype, pHistory, pOutput);
            break;
        }
    }
}

void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, FUNCDESC& functionDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput)
{
    // get dependencies of the function return value
    GetDependenciesHelper(pTypeLib, pTypeInfo, functionDescription.elemdescFunc, pHistory, pOutput);

    // iterate over parameters
    auto parameterCount = functionDescription.cParams;
    for (SHORT parameterIndex = 0; parameterIndex < parameterCount; ++parameterIndex)
    {
        // get parameter description
        auto& parameterDescription = functionDescription.lprgelemdescParam[parameterIndex];

        // get dependencies of the parameter declaration
        GetDependenciesHelper(pTypeLib, pTypeInfo, parameterDescription, pHistory, pOutput);
    }
}

void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, VARDESC& variableDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput)
{
    // get dependencies of the variable declaration
    GetDependenciesHelper(pTypeLib, pTypeInfo, variableDescription.elemdescVar, pHistory, pOutput);
}

void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, ARRAYDESC& arrayDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput)
{
    // get dependencies of the array declaration
    GetDependenciesHelper(pTypeLib, pTypeInfo, arrayDescription.tdescElem, pHistory, pOutput);
}

void GetDependenciesHelper(ITypeLib* pTypeLib, ITypeInfo* pTypeInfo, ELEMDESC& elementDescription, std::unordered_set<ITypeInfoPtr>* pHistory, std::unordered_set<ITypeLibPtr>* pOutput)
{
    // get dependencies of the array element declaration
    GetDependenciesHelper(pTypeLib, pTypeInfo, elementDescription.tdesc, pHistory, pOutput);
}