C++ (ATL) ITypeInfo.GetContainingTypeLib fails whe

2019-08-15 06:21发布

问题:

So I asked this question in a C# context and I have set bounty over there.

I have written an equivalent fragment of C++ code (to be housed within an ATL DLL project) to tap C++ developers experience as well.

IDispatch has a method called GetTypeInfo() with which one can acquire a pointer to ITypeInfo. ITypeInfo itself has a method called GetContainingTypeLib which gets the containing ITypeLib (as it says). This is useful when given a CoClass instance once can get to all the other CoClasses in a given DLL, very useful for reflection.

I had wondered if Excel VBA would co-operate in a similar fashion and return a ITypeLib for the containing VBA project and equally allow me to iterate over all the types found therein. So I wrote some test C# code and that is linked. Here I give equivalent C++ code to tap C++ experience.

The IDL...

[
    object,
    uuid(ddc4e135-49d6-49f8-ad57-ded4180095fd),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface ICoClassGetContainingTypeLib : IDispatch
{
    HRESULT GetContainingTypeLib(IDispatch* vbaClass, IUnknown** iunkTypeLib);
};

[
    uuid(bc8410a6-802a-4f91-a73b-c03179bb402b)
]
coclass CoClassGetContainingTypeLib
{
    [default] interface ICoClassGetContainingTypeLib;
};

The cpp method implementation

STDMETHODIMP CCoClassGetContainingTypeLib::GetContainingTypeLib(IDispatch* vbaClass, IUnknown** iunkTypeLib)
{
    CComPtr<IDispatch> itfDispatch(vbaClass);
    CComPtr<ITypeInfo> pITypeInfo;

    HRESULT hr = S_OK;
    HRESULT hr2 = S_OK;
    try
    {

        hr = itfDispatch->GetTypeInfo(0, 0, &pITypeInfo);
        if (SUCCEEDED(hr)) 
        {
            UINT* idx(0);
            CComQIPtr<ITypeLib> pTLib;
            HRESULT hr2 = pITypeInfo->GetContainingTypeLib(&pTLib, idx);
            return hr2; // throws exception Exception 0x800A88C1 
            // which ends u[p at 35009

            //TODO If successful copy to ByRef param  iunkTypeLib
        }
    }
    catch (std::exception ex)
    {
        return E_FAIL;
    }
    return S_OK;
}

And the header declaration

STDMETHOD(GetContainingTypeLib)(IDispatch* vbaClass, IUnknown** iunkTypeLib);

And some client VBA

Sub TestGetContainingTypeLib()

    Dim oTR As ToolsReferences  '* could be ANY VBA class
    Set oTR = New ToolsReferences   '* could be ANY VBA class

    '* instantiate my ATL project
    Dim oTest As GetContainingTypeLibTestLib.CoClassGetContainingTypeLib
    Set oTest = New GetContainingTypeLibTestLib.CoClassGetContainingTypeLib

    Dim iunkTypeLib As IUnknown
    Set iunkTypeLib = Nothing   '* not strictly required
    Call oTest.GetContainingTypeLib(oTR, iunkTypeLib)

End Sub

There is very little on the Internet to explain the exception number of 0x800A88C1 . I think this the Excel team saying no.