如何在C++中创建和初始化一个存储双精度浮点数的SAFEARRAY以便传递给C#

12

我的C#方法需要从C++中调用

最初,我的C#方法需要一个double[]类型的参数,但是在从C++调用时,它变成了一个SAFEARRAY。

在C++中,我需要从一个double数组中获取数据,并填充一个SAFEARRAY。我还没有找到任何可用的示例代码。

非常感谢您的帮助。

3个回答

27
以下是在C++中创建safearray的代码。
#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);
    }
}

在你完成后,像下面的代码一样释放指针-
  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

如果你在C++中使用ATL,最好使用在"atlsafe.h"中声明的CComSafeArray。这是SAFEARRAY的包装器。CComSafeArray类

这篇文章对我非常有帮助,谢谢。但是使用这个函数后,我的saData指针为空了。 - Teetrinker
@Teetrinker - 在调用SafeArrayDestroy后,saData将为空。我已经在我的代码中添加了一些注释。 - Liton
谢谢,正是我所需。但是当一切都是32位或64位时,HUGEP和FAR宏现在只是噪音。 - Minthos

8

继续 @Liton 的回答,我想强调他的最后一句话,即 ATL 的 CComSafeArray。它真的可以节省你很多打字时间。 CComSafeArray 具有 C++ 构造函数、析构函数、运算符重载,包括一个用于 [ ] 的运算符重载,它给你一个读/写引用来访问 SAFEARRAY 中的任何元素。简而言之,你真的可以专注于你的业务逻辑,不必担心 SAFEARRAY 的实现细节:

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

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

至少,即使您不打算使用CComSafeArray,也值得拆解其源代码中的<atlsafe.h>,以便更好地了解SAFEARRAY函数的何时、为什么和如何使用。


2

不建议传递SAFEARRAYs。建议将SAFEARRAY放入VARIANT中。此外,SAFEARRAY应持有VARIANT数据。这样可以使传递包含VARIANT的SAFEARRAY到其他语言更加有用。例如,C++到VB / C#(注意,释放/销毁SAFEARRAY由调用方负责)

在之前的代码基础上构建

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接