簡體   English   中英

通過COM將自定義接口類型的SAFEARRAY返回到VB6

[英]Return SAFEARRAY of custom interface types to VB6 through COM

是否可以從C ++ COM函數(VC6)向VB6客戶端返回已定義接口對象的數組? 我已經在網上搜尋了內容,卻沒有發現任何描述我需要做的事情。 我已經看到了很多傳遞BSTR和VARIANT類型的方法,但是我需要一些方法來使客戶端實際利用我在數組內部返回的接口類型。

我認為我需要做的
-使用SAFEARRAY
-使用VT_UNKNOWN類型的SAFEARRAY,這又意味着我需要將這些對象作為IUnknown對象放入數組中。

從這里開始,我很困惑。 是否可以解釋VB6中的IUnknown類型,並以某種方式將其轉換為我需要的類型? 還是我以完全錯誤的方式來解決這個問題...

澄清:
放置在集合中的接口用於模仿結構。 我本質上需要傳回結構數組。

盡管提出的問題與我提出的目標不完全相同,但我已經提出了適合自己目的的解決方案。

我的解決方案是創建一個以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())

對這種方法有何評論?

當您將IUnknown分配給特定的接口類型時,VB將在后台執行QueryInterface,因此應該可以正常工作。

我不知道是否可以將用戶定義類型的數組傳遞給VB6,我可以在Web上找到的所有文檔都停留在VS2003,但是我希望這是可能的。

您可以將其包裝在一個變體中,然后起作用。

IDL:

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

cpp:

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM