2008-11-17 18 views
6

Soy un objeto COM escrito en ATL que se utiliza desde una aplicación C++, y quiero pasar una matriz de BYTE entre los dos. Mi experiencia de COM/IDL hasta ahora está limitada a pasar tipos simples (BSTR, LONGs, etc.).¿Pasar una matriz usando COM?

¿Hay una manera relativamente fácil de hacer que el objeto COM pase una matriz a la persona que llama? Por ejemplo, quiero pasar una imagen sin formato (TIFF) en lugar de jugar con archivos temporales.

+10

Qué divertido debe ser ser un objeto COM. :-) – Danra

Respuesta

11

Intente pasar una variante de safearray al objeto COM. Algo como esto para poner una matriz de bytes en el interior de una variante safearray ....

bool ArrayToVariant(CArray<BYTE, BYTE>& array, VARIANT& vtResult) 
{ 
SAFEARRAY FAR* psarray; 
SAFEARRAYBOUND sabounds[1]; 

sabounds[0].lLbound=0; 
sabounds[0].cElements = (ULONG)array.GetSize(); 

long nLbound; 

psarray = SafeArrayCreate(VT_UI1, 1, sabounds); 
if(psarray == NULL) 
    return false; 

for(nLbound = 0; nLbound < (long)sabounds[0].cElements ; nLbound++){ 
    if(FAILED(SafeArrayPutElement(psarray, &nLbound, &array[nLbound]))){ 
     SafeArrayDestroy(psarray); 
     return false; 
    } 
} 

VariantFree(vtResult); 
vtResult.vt = VT_ARRAY|VT_UI1; 
vtResult.parray = psarray; 
return true; 
} 
+0

Gracias - Encontré una clase ATL muy útil llamada CComSafeArray que hace esto muy fácil (las versiones anteriores de MFC pueden usar COleSafeArray). – Rob

0

Echa un vistazo usando safearrays. Aquí hay un código de ejemplo:

El safearray se devuelve como un puntero a una variante

[id(1), helpstring("LogCache")] HRESULT LogCache([out,retval] VARIANT* logCache); 

Safearrays son bastante fáciles de usar. Aquí hay un código de ejemplo que es una memoria caché de los últimos 1000 mensajes de registro de alguna aplicación:

safearray_t<bstr_t> m_logCache; 
    ... 
    if (m_logCache.size() > 1000) 
    { 
     m_logCache.pop_back(); 
    } 

    m_logCache.push_front(Msg.str(), 0); 


    variant_t LogCache() 
    { 
     if (!m_logCache.is_empty()) 
     { 
      variant_t cache(m_logCache); 
      return cache; 
     } 
    } 

Tenga en cuenta que la sintaxis en su caso es casi seguro que va a ser diferente ya que estoy usando el comet COM library, pero las ideas/conceptos son lo mismo.

-1

Puede utilizar BSTR para pasar una matriz de bytes.

BYTE array[buffer_size]; 
... 
BSTR toBePassed = SysAllocStringByteLen((OLECHAR*)array,length); 
YourCOMMethod(toBePassed); 
SysFreeString(toBePassed); 

En su método:

BYTE* pData = (BYTE*)bstrPassed; 
DWORD dataLength = SysStringByteLen(bstrPassed); 
+4

NO LO HAGAS. Los contenidos de la matriz pueden ser traducidos de su página de códigos ANSI a Unicode o viceversa, causando que los valores binarios cambien. Es posible que las aplicaciones cliente no siempre sepan cuándo sucede esto y que encontrarán dañados sus datos. –

+2

Para aclarar: aunque el programador tiene la intención de que la matriz contenga datos binarios, varias rutinas del sistema no conocen la intención del programador. Los BSTR están diseñados para contener cadenas Unicode, y las rutinas del sistema harán esa suposición. –

2

SAFEARRAY son el camino a seguir si desea que el cumplimiento de OLE-Automation, y tal vez utilizar la interfaz COM de otros lenguajes como Visual Basic 6. Pero hay una alternativa en IDL, por ejemplo: -

void Fx([in] long cItems, [in, size_is(cItems)] BYTE aItems[]); 

Esta describe un método en el que el código de clasificación puede inferir el número de bytes a ser transferido mediante la inspección del valor del primer parámetro.

Esto está bien si sus clientes están escritos en C/C++, pero yo pensar que un interfaz que contiene esta no sería la automatización compatible, por lo que no se puede utilizar desde VB6, y posiblemente el contador de referencias estándar no lo hará ser capaz de realizar la clasificación, por lo que necesitaría generar su propia DLL proxy/stub desde IDL. No es difícil de hacer, pero es un poco más difícil que usar SAFEARRAY.

Cuestiones relacionadas