DISPID_VALUE和varargs奇怪的行为

时间:2014-04-24 08:48:41

标签: c++ vba com idl variant

我在IDL / C ++ / VBA中混合DISPID_VALUE和varargs的行为非常奇怪。

我的IDL文件中有以下定义

[
    uuid(78fc63e0-fdb5-11e1-a21f-0800200c9a66),
    dual
]
interface IPyObj : IDispatch
{
    // ...

    [propget, id(DISPID_VALUE)]
    HRESULT Item(
        [in] VARIANT* Key,
        [out, retval] VARIANT* Result
    );

    // ...
};

// ...

[entry("PyTuple"), helpstring("Builds a Python tuple object"), vararg]
HRESULT __stdcall PyTuple(
    [in] SAFEARRAY(VARIANT)* Elements,
    [out, retval] VARIANT* Result
);

IPyObj::get_Item函数存储一个IDispatch指针,类型为VT_DISPATCH,在VBA的即时窗口中通过检查确认:

?VarType(myPyObj(1))
 9 
?VarType(myPyObj.Item(1))
 9 
?VarType(myPyObj(1)) = vbObject
True

当我按如下方式调用PyTuple函数时

PyTuple(myPyObj.Item(1))

在函数内部我按预期找到了VT_DISPATCH,但是当我这样称呼它时:

PyTuple(myPyObj(1))
调试器中的

我发现SAFEARRAY包含VT_I4

发生了什么事?

我注意到vararg函数似乎只发生这种行为,而不是VARIANT*参数的函数。


在回应ben的评论时,这是由PyTuple调用的函数,它读取SAFEARRAY。在下面的行中放置断点,我可以看到pData[k]包含VT_I4。我再说一遍,“bug”只发生在使用默认属性和vararg函数的特定组合中。

PyObject* SafeArrayToTuple(SAFEARRAY* pSA)
{
    if(pSA->cDims != 1)
        throw Exception() << "Array is not one-dimensional while converting to Python tuple.";

    int len = (int) pSA->rgsabound->cElements;
    PyNewRef ret(PyTuple_New(len));
    VARIANT* pData;
    {
        AutoSafeArrayAccessData ad(pSA, (void**) &pData);

        for(int k=0; k<len; k++)
            // breakpoint here
            PyTuple_SET_ITEM(ret.ptr, k, VariantToPy(&pData[k]));
    }

    return ret.detach();
}

请注意,使用SafeArrayGetElement代替SafeArrayAccessData不会改变任何内容。

0 个答案:

没有答案