#c #com #vb6 #visual-c -6 #safearray
#c #com #vb6 #visual-c -6 #safearray
Вопрос:
Возможно ли вернуть массив определенных объектов интерфейса из COM-функции C (VC6) клиенту VB6? Я прочесал веб-страницы и не смог найти ничего, что описывало бы, что мне нужно сделать. Я видел много передаваемых типов BSTR и VARIANT, но мне нужен какой-то способ, чтобы клиентская сторона действительно использовала тип интерфейса, который я возвращаю внутри массива.
Что, я предполагаю, мне нужно будет сделать
— Использовать SAFEARRAY
— Использовать SAFEARRAY с типом VT_UNKNOWN, что, в свою очередь, означает, что мне нужно поместить объекты в массив как объекты IUnknown.
С этого момента я в тупике. Возможно ли интерпретировать неизвестный тип в VB6 и каким-то образом преобразовать его в тип, который мне требуется? Или я делаю это совершенно неправильно…
Уточнение:
Интерфейсы, размещаемые в коллекции, используются для имитации структуры. По сути, мне нужно передать обратно массив структур.
Ответ №1:
Я придумал решение, которое подходит для моих целей, несмотря на то, что оно не совсем то, что я изложил в вопросе.
Моим решением было создать COM-функцию, которая принимает SAFEARRAY в качестве параметра и изменяет его, вместо того, чтобы возвращать созданный массив. Клиент VB6 создает экземпляр массива и передает его C для заполнения. Я предполагаю, что будущее использование будет включать функцию-предшественник, которую VB6 вызывает для определения требуемого размера массива. Для справки, вот фрагменты кода:
Функция интерфейса:
[id(4), helpstring("method PopulateWithStruct")] HRESULT PopulateWithStruct([in,out]SAFEARRAY (IReturnStruct*)*ppArray, [out,retval] long*plResult);
Где IReturnStruct — это интерфейс, содержащий значения свойств, действующий как struct:
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, amp;lLowerBound);
SafeArrayGetUBound(*ppArray, 1, amp;lUpperBound);
long lArraySize = lUpperBound - lLowerBound;
VARTYPE type;
SafeArrayGetVartype(*ppArray, amp;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 **>(amp;pRetStruct));
if (SUCCEEDED(hr))
{
pRetStruct->Initialise();
hr = SafeArrayPutElement(*ppArray, (long*)amp;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())
Есть комментарии по этому подходу?
Ответ №2:
VB выполнит QueryInterface за кулисами, когда вы присвоите IUnknown определенному типу интерфейса, так что это должно просто сработать.
Я не знаю, можете ли вы передать массив пользовательского типа в VB6, вся документация, которую я могу найти в Интернете, заканчивается на VS2003, но я ожидаю, что это будет возможно.
Ответ №3:
Вы можете обернуть это в вариант, и тогда это сработает.
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**)amp;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)