是否可以将已定义的接口对象数组从C ++ COM函数(VC6)返回到VB6客户端?我已经浏览过网络,但却未能找到描述我需要做什么的任何事情。我已经看到很多传递BSTR和VARIANT类型,但我需要一些方法来实际让客户端利用我在数组中返回的接口类型。
我认为我需要做什么
- 使用SAFEARRAY
- 使用带有VT_UNKNOWN类型的SAFEARRAY,这意味着我需要将对象作为IUnknown对象放入数组中。
从此开始,我很难过。是否有可能在VB6中解释IUnknown类型,并以某种方式将其转换为我需要的类型?或者我是以完全错误的方式解决这个问题......
澄清:
放置在集合中的接口用于模拟结构。我基本上需要传回一个结构数组。
答案 0 :(得分:3)
我想出了一个适合我目的的解决方案,尽管不完全是我在问题中提出的。
我的解决方案是创建一个COM函数,它将SAFEARRAY作为参数并修改它,而不是返回创建的数组。 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())
对此方法有何评论?
答案 1 :(得分:2)
我不知道你是否可以将用户定义类型的数组传递给VB6,我在网上找到的所有文档都停在VS2003上,但我希望它是可能的。
答案 2 :(得分:1)
您可以将该事物包装在一个变体中然后它可以正常工作。
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)