6

是否可以将一组已定义的接口对象从 C++ COM 函数 (VC6) 返回到 VB6 客户端?我已经在网上搜索过,但无法找到任何描述我需要做的事情。我见过很多传递 BSTR 和 VARIANT 类型,但我需要一些方法让客户端真正使用我在数组中返回的接口类型。

我假设我需要做
的 - 使用 SAFEARRAY
- 将 SAFEARRAY 与 VT_UNKNOWN 类型一起使用,这反过来意味着我需要将对象作为 IUnknown 对象放入数组中。

从这里开始,我被难住了。是否可以在 VB6 中解释 IUnknown 类型,并以某种方式将其转换为我需要的类型?或者我是以完全错误的方式来解决这个问题......

澄清:
放置在集合中的接口用于模拟结构。我基本上需要传回一个结构数组。

4

3 回答 3

3

我提出了一个适合我的目的的解决方案,尽管不是我在问题中提出的。

我的解决方案是创建一个将 SAFEARRAY 作为参数并对其进行修改的 COM 函数,而不是返回创建的数组。VB6 客户端实例化数组,并将其传递给 C++ 进行填充。我设想未来的使用将包括一个前体函数,VB6 调用该函数来确定所需的数组大小。作为参考,以下是代码片段:

接口功能:

[id(4), helpstring("method PopulateWithStruct")] HRESULT PopulateWithStruct([in,out]SAFEARRAY (IReturnStruct*)*ppArray, [out,retval] long*plResult);

其中 IReturnStruct 是一个包含属性值的接口,充当结构:

interface IReturnStruct : IDispatch
{
    [propget, id(1), helpstring("property num1")] HRESULT num1([out, retval] long *pVal);
    [propget, id(2), helpstring("property str1")] HRESULT str1([out, retval] BSTR *pVal);
};

并由 ReturnStruct 实现

[
    uuid(843870D0-E3B3-4123-82B4-74DE514C33C9),
    helpstring("ReturnStruct Class")
]
coclass ReturnStruct
{
    [default] interface IReturnStruct;
};

PopulateWithStruct 具有以下定义:

STDMETHODIMP CCTestInterface::PopulateWithStruct(SAFEARRAY **ppArray, long *plResult)
{
    long lLowerBound = -1;
    long lUpperBound = -1;
    SafeArrayGetLBound(*ppArray, 1, &lLowerBound);
    SafeArrayGetUBound(*ppArray, 1, &lUpperBound);

    long lArraySize = lUpperBound - lLowerBound;

    VARTYPE type;
    SafeArrayGetVartype(*ppArray, &type);

    if (lArraySize > 0)
    {
        for ( int i = lLowerBound; i < lUpperBound; ++i)
        {
            CComPtr<CReturnStruct> pRetStruct;
            HRESULT hr = CoCreateInstance(__uuidof(ReturnStruct), NULL, CLSCTX_ALL, __uuidof(IUnknown), reinterpret_cast<void **>(&pRetStruct));
            if (SUCCEEDED(hr))
            {
                pRetStruct->Initialise();
                hr = SafeArrayPutElement(*ppArray, (long*)&i, pRetStruct);
                if (FAILED(hr))
                {
                    return hr;
                }
                pRetStruct.Release();
            }
        }
        SafeArrayUnaccessData(*ppArray);
    }

    *plResult = 1;

    return S_OK;
}

在 VB 方面:

Dim obj As ATL_SERVICETESTLib.CTestInterface
Set obj = New CTestInterface

Dim Result As Long
Dim RetStructs(3) As ReturnStruct

Result = obj.PopulateWithStruct(RetStructs())

对此方法有何评论?

于 2011-04-14T07:42:37.093 回答
2

当您将 IUnknown 分配给特定的接口类型时,VB 将在幕后执行 QueryInterface,因此应该可以正常工作。

我不知道您是否可以将用户定义类型的数组传递给 VB6,我可以在网上找到的所有文档都停在 VS2003,但我希望这是可能的。

于 2011-04-12T09:53:17.133 回答
1

您可以将事物包装在一个变体中,然后它就可以工作了。

空闲:

[propget, id(10), helpstring("blabla")]
HRESULT MyListProp([out, retval] VARIANT *ppsaList); 

cp:

STDMETHODIMP CAnyClass::get_MyListProp(/*[out, retval]*/ VARIANT* ppsaList)
{
HRESULT hr = S_OK;

if (ppsaList== NULL)
{
    return E_INVALIDARG;
}

CComSafeArray <IDispatch*> saVars;

// I have my objects in a list m_List that I am copying to saVars
for (std::list<IMyObj*>::iterator it = m_List.begin();
     it != m_List.end();
     ++it)
{
    IDispatch* pUnk = NULL;
    if ((*it)->QueryInterface(IID_IDispatch, (void**)&pUnk) == S_OK)
    {
        saVars.Add(pUnk);
    }
}

CComVariant varReturn (saVars.Detach());
varReturn.Detach(ppsaList);
return S_OK;
} 

VB:

Dim arr
arr = obj.MyListProp

' these will all work
ub = UBound(arr)
lb = LBound(arr)
于 2012-06-19T14:21:59.363 回答