2010-09-16 8 views
10

Mi método C# tiene que ser invocada desde C++Cómo crear e inicializar SAFEARRAY de dobles en C++ para pasar a C#

Originalmente mi C# método toma un parámetro de tipo double [], pero cuando se llama desde C++ se convierte a SAFEARRAY

En C++ necesito tomar datos de una matriz de dobles y completar un SAFEARRAY. No he encontrado ningún código de muestra para hacer esto.

Cualquier ayuda se agradece

Respuesta

23

siguiente es el código para crear un safearray en C++.

#include<oaidl.h> 

void CreateSafeArray(SAFEARRAY** saData)   
{ 
    double data[10]; // some sample data to write into the created safearray 
    SAFEARRAYBOUND Bound; 
    Bound.lLbound = 0; 
    Bound.cElements = 10; 

    *saData = SafeArrayCreate(VT_R8, 1, &Bound); 

    double HUGEP *pdFreq; 
    HRESULT hr = SafeArrayAccessData(*saData, (void HUGEP* FAR*)&pdFreq); 
    if (SUCCEEDED(hr)) 
    { 
      // copy sample values from data[] to this safearray 
     for (DWORD i = 0; i < 10; i++) 
     { 
      *pdFreq++ = data[i]; 
     } 
     SafeArrayUnaccessData(*saData); 
    } 
} 

libre el puntero cuando haya terminado como el siguiente código-

SAFEARRAY* saData; 
    CreateSafeArray(&saData); // Create the safe array 
    // use the safearray 
    ... 
    ... 

    // Call the SafeArrayDestroy to destroy the safearray 
    SafeArrayDestroy(saData); 
    saData = NULL; // set the pointer to NULL 

Si utiliza ATL para C++, a continuación, un mejor uso CComSafeArray declaró en "atlsafe.h". Esto es envoltorio para SAFEARRAY. link text

+0

gran código, bien dicho. – Contango

+0

Este artículo me ayudó mucho. Gracias. Pero usar la función de esta manera me dejó con un saData-Pointer vacío. – Teetrinker

+0

@Teetrinker - saData estará vacío después de llamar a SafeArrayDestroy. He agregado algunos comentarios a mi código. – Liton

6

Continuando con la respuesta de @Liton, quiero enfatizar su última oración, es decir, CComSafeArray de ATL. Realmente puede ahorrarle mucho tipeo. CComSafeArray tiene constructores C++, destructores, sobrecargas del operador, incluyendo uno para [] que le da una referencia de lectura/escritura a cualquier elemento en el SAFEARRAY. En resumen, realmente puede centrarse en su lógica de negocio y no necesita preocuparse por la SAFEARRAY plomería:

#include <atlbase.h> 
#include <atlsafe.h> 
// ... 

    CComSafeArray<double> arr(10); 
    arr[0] = 2.0; 
    arr[1] = 3.0; 
    arr[2] = 5.0; 
    // ... 

Por lo menos, incluso si no va a utilizar CComSafeArray vale la pena deconstruir su código fuente en <atlsafe.h> que le da una mejor idea sobre qué, cuándo, por qué y cómo en las funciones SAFEARRAY.

2

No se recomienda pasar SAFEARRAYs. Se recomienda colocar el SAFEARRAY en una VARIANTE. Además, SAFEARRAY debe contener datos VARIANTE. Esto ofrece lo mejor de todos los mundos y hace que el paso de VARIANT SAFEARRAY de VARIANTES sea más útil para otros idiomas. P.ej. C++ para VB/C# (Nota que depende de la persona que llama para liberar/destruir el SAFEARRAY)

Basándose en el código anterior

// A VARIANT holding a SAFEARRAY of VARIANTs 
VARIANT vRet; 

SAFEARRAYBOUND Bound; 
Bound.lLbound = 0; 
Bound.cElements = 10; 

SAFEARRAY * psaData = SafeArrayCreate(VT_VARIANT, 1, &Bound); 

VARIANT HUGEP * pData = NULL; 
HRESULT hr = SafeArrayAccessData(psaData, (void HUGEP * FAR *)&pData); 
if (SUCCEEDED(hr)) 
{ 
    for (short i = 0; i < 10; ++i,++pData) 
    { 
     ::VariantInit(pData); 
     pData->vt = VT_I2; 
     pData->iVal = i; 
    } 

    SafeArrayUnaccessData(psaData); 
} 

vRet.vt = VT_ARRAY | VT_VARIANT; 
vRet.parray = psaData; 
Cuestiones relacionadas