2011-04-12 17 views
5

¿Es posible devolver una matriz de objetos de interfaz definidos desde una función COM de C++ (VC6) a un cliente VB6? Recorrí la red y no he podido encontrar nada que describa lo que debo hacer. He visto muchos tipos de BSTR y VARIANT que pasan, pero necesito que el cliente utilice el tipo de interfaz que devuelvo dentro de la matriz.Devolver SAFEARRAY de tipos de interfaz personalizados a VB6 a través de COM

lo que supongo que voy a tener que hacer
- Utilice un SAFEARRAY
- Utilice el SAFEARRAY con el tipo VT_UNKNOWN, que a su vez significa que tengo que colocar los objetos en la matriz como objetos IUnknown.

De aquí en adelante estoy perplejo. ¿Es posible interpretar un tipo IUnknown en VB6, y de alguna manera convertirlo en el tipo que necesito? O estoy haciendo esto de la manera incorrecta completa ...

Aclaración:
Las interfaces que se colocan en la colección se utilizan para imitar una estructura. Esencialmente necesito devolver una serie de estructuras.

Respuesta

3

He encontrado una solución que es adecuada para mis propósitos, a pesar de no ser exactamente lo que establecí en la pregunta.

Mi solución fue crear una función COM que toma un SAFEARRAY como parámetro y lo modifica, en lugar de devolver una matriz creada. El cliente VB6 crea una instancia de la matriz y la pasa a C++ para que se complete. Imagino que el uso futuro incluirá una función de precursor que VB6 llama para determinar el tamaño requerido de la matriz. Como referencia, aquí están los fragmentos de código: función

Interfaz:

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

Dónde IReturnStruct es una interfaz que contiene los valores de propiedad, que actúa como una estructura:

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); 
}; 

Y es implementado por ReturnStruct

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

PopulateWithStruct tiene la siguiente definición:

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; 
} 

En el lado VB:

Dim obj As ATL_SERVICETESTLib.CTestInterface 
Set obj = New CTestInterface 

Dim Result As Long 
Dim RetStructs(3) As ReturnStruct 

Result = obj.PopulateWithStruct(RetStructs()) 

Cualquier comentario sobre este enfoque?

2

VB hará una QueryInterface entre bastidores cuando asigna IUnknown a un tipo de interfaz particular, por lo que debería funcionar.

No sé si puede pasar una serie de tipos definidos por el usuario a VB6, toda la documentación que puedo encontrar en la web se detiene en VS2003, pero esperaría que fuera posible.

1

Puede envolver la cosa en una variante y luego funciona.

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) 
Cuestiones relacionadas