How to create and initialize SAFEARRAY of doubles in C++ to pass to C#

前端 未结 3 2006
别跟我提以往
别跟我提以往 2020-12-08 17:19

My C# method needs to be invoked from C++

Originally my C# method takes a parameter of type double[], but when calling from C++ it becomes a SAFEARRAY

In C++

相关标签:
3条回答
  • 2020-12-08 17:38

    Continuing on @Liton's answer, I want to stress his last sentence, i.e. ATL's CComSafeArray. It really can save you a lot of typing. CComSafeArray has C++ constructors, destructors, operator overloads including one for [ ] that gives you an read / write reference to any element in the SAFEARRAY. In short, you can really focus on your business logic and needn't worry about the SAFEARRAY plumbing:

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

    At the very least, even if you're not going to use CComSafeArray it's worthwhile to deconstruct its source code in <atlsafe.h> giving you better insight on the what, when, why and how on SAFEARRAY functions.

    0 讨论(0)
  • 2020-12-08 17:53

    Following is the code to create a safearray in 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);
        }
    }
    

    Free the pointer when you are finished like the following code-

      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
    

    If you use ATL for C++, then better use CComSafeArray declared in "atlsafe.h". This is wrapper for SAFEARRAY. link text

    0 讨论(0)
  • 2020-12-08 17:53

    Passing SAFEARRAYs is not recommended. It is recommended to place the SAFEARRAY into a VARIANT. Further, the SAFEARRAY should hold VARIANT data. This gives the best of all worlds and makes passing VARIANT SAFEARRAY of VARIANTs more useful to other languages. E.g. C++ to VB / C# (Note it is up to the caller to free/destroy the SAFEARRAY)

    Building on the previous code

    // 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;
    
    0 讨论(0)
提交回复
热议问题