将 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
是因为输入数组RealCo
、RealCr
、ImagCo
、ImagCr
实际上是Single
输入VBA.
有效,但我的问题如下:当我从 C++ 中的最后一个 }
移动到 VBA 时,CoPol
和 CrPol
的内容(这是我想在 VBA 代码中进一步使用的两个矩阵)消失了。
请注意,我实际上可以调试代码并检查 CoPol
和 CrPol
确实包含数据。我试图将它们传递给 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 的指针,并调用所需的数组 ByRef
和 As Long
,但它不起作用(CoPol
和 CrPol
然后在 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
我在 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
是因为输入数组RealCo
、RealCr
、ImagCo
、ImagCr
实际上是Single
输入VBA.
有效,但我的问题如下:当我从 C++ 中的最后一个 }
移动到 VBA 时,CoPol
和 CrPol
的内容(这是我想在 VBA 代码中进一步使用的两个矩阵)消失了。
请注意,我实际上可以调试代码并检查 CoPol
和 CrPol
确实包含数据。我试图将它们传递给 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 的指针,并调用所需的数组 ByRef
和 As Long
,但它不起作用(CoPol
和 CrPol
然后在 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