将 SAFEARRAY 变体从 c++ dll 传递到 vba

Passing a SAFEARRAY variant to vba from a c++ dll

我在 DLL 中有以下代码,它应该从用 VBA 编写的例程中获取一些输入,用它做一些事情,然后 return 两个2D-arrays back(所以一个函数不是真正可行的,此外,如果我想 return 一个包含其他两个的数组,我将不得不面对 [=54 中的代码优化问题=]),可以从 VBA 访问。 事不宜迟,代码如下所示:

void _stdcall MySub(VARIANT RealCo, VARIANT ImagCo, VARIANT RealCr, VARIANT ImagCr, ULONG PointsTheta, ULONG PointsPhi, double Res, VARIANT CoPol, VARIANT CrPol)
{

/* Do my stuff here, and at the end produces the following arrays */

CoPol.vt = VT_ARRAY | VT_VARIANT;
CrPol.vt = VT_ARRAY | VT_VARIANT;
sab2[1].lLbound = 0; sab2[1].cElements = 360;
sab2[0].lLbound = 0; sab2[0].cElements = 360;
CoPol.parray = SafeArrayCreate(VT_VARIANT, 2, sab2);
CrPol.parray = SafeArrayCreate(VT_VARIANT, 2, sab2);

/* Those arrays are then stuffed with data */

}

我从 VBA 调用如下:

Private Declare Sub MySub Lib "Mypath/MyFile.dll" ( _
        ByVal RealCo As Variant, _
        ByVal ImagCo As Variant, _
        ByVal RealCr As Variant, _
        ByVal ImagCr As Variant, _
        ByVal PointsTheta As Long, _
        ByVal PointsPhi As Long, _
        ByVal Res As Double, _
        ByVal CoPol As Variant, _
        ByVal CrPol As Variant)

Dim CoPol As Variant, CrPol As Variant

' [...]

MySub CVar(RealCo), CVar(ImagCo), CVar(RealCr), CVar(ImagCr), PointsTheta, PointsPhi, Resolution, CoPol, CrPol

CVar是因为输入数组RealCoRealCrImagCoImagCr实际上是Single输入VBA.

有效,但我的问题如下:当我从 C++ 中的最后一个 } 移动到 VBA 时,CoPolCrPol 的内容(这是我想在 VBA 代码中进一步使用的两个矩阵)消失了。

请注意,我实际上可以调试代码并检查 CoPolCrPol 确实包含数据。我试图将它们传递给 C++ 中的另一个子例程,但由于效果不佳,我提出了通过 reference:

传递它们的解决方案
void _stdcall MySub(VARIANT RealCo, VARIANT ImagCo, VARIANT RealCr, VARIANT ImagCr, ULONG PointsTheta, ULONG PointsPhi, double Res, VARIANT &CoPol, VARIANT &CrPol)

这解决了我的问题 在 C++ 内部 但不是在 C++ 和 VBA 之间。我还尝试返回指向 VARIANTS 的指针,并调用所需的数组 ByRefAs Long,但它不起作用(CoPolCrPol 然后在 VBA 只是一个 Long 数字,我无法使用它。

我应该写什么才能使 VBA 能够访问用 C++ 构建的矩阵中的值?

编辑:如果你想投反对票,至少要解释原因。

如果内存是通过 C++ 中的单个函数调用分配的,之后如何释放内存?

否则我会这样做;在 VBA 中声明并调暗数组,然后将指向数组数据的指针传递给您的 C++ 函数,然后用值填充它。

(顺便说一句,我认为它的 __stdcall 带有两个下划线。)

void __stdcall fillarray(const int n, double *out) {
    for (int i = 0; i < n; ++i) {
        out[i] = i;
    }
}

然后

Public Declare PtrSafe Sub fillarray Lib "Mypath/MyFile.dll" (ByVal n As Long, ByRef out As Double)

Dim A() as Double
Redim A(1 to 100)
fillarray 100, A(1)   'A(1) first element pointing to data