Noldor130884
Noldor130884

Reputation: 994

Return a dynamically allocated array from C++ dll to VBA

DISCLAIMER: I know how to allocate memory in VBA, fill an array within a C++ DLL and return its pointer, but sadly I might find a couple of cases in which I cannot know the size of an array, therefore I won't be able to Dim or ReDim it in VBA, before passing it to the DLL.

Suppose I have a C++ subroutine inside my DLL, that would "return" two things as output: one is an integer and the other is an array:

void _stdcall mySub(int inOption, int outXPR, double* outWeight_Coeff)

// Do Stuff 

WindowThetaHalf = [insert random value here];
WindowPhiHalf = [insert random value here];
outXPR = value;

outWeight_Coeff = new double[(WindowThetaHalf + 1) * (WindowPhiHalf + 1)];

for (int i = -WindowThetaHalf; i <= WindowThetaHalf; i++)
{
    for (int j = -WindowPhiHalf; j <= WindowPhiHalf; j++)
    {
        outWeight_Coeff[i + WindowThetaHalf + j * (WindowThetaHalf + 1) * 2 + WindowPhiHalf] = i + j;
    }
}

Now, I know that I have to give to the DLL the first element of an array as a pointer to make this work:

Private Declare Sub mySub Lib "[dll path here]" (ByVal inOption As Long, ByVal XPR As Long, ByRef outWeight_Coeff As Double)

Sub main()

Dim XPR As Long
Dim a() As Double

ReDim a(0, 0)
LoadChannelType 1, XPR, a(0, 0)

Debug.Print XPR
For i = 0 To UBound(a, 1)
    For j = 0 To UBound(a, 2)
        Debug.Print a(i, j)
    Next
Next

End Sub

This doesn't work though. I feel it might have something to do with the dimensions I'm specifying in VBA, but again, it is very possible that I will have to deal with a situation in which I'd basically have to "ReDim" the outWeight_Coeff array in C++ . Is there any possibility to do that?

EDIT: Other ways I tried and failed:

Instead of using new, I tried the following as well:

Upvotes: 0

Views: 1013

Answers (1)

Soonts
Soonts

Reputation: 21936

C++ prototype:

void __stdcall mySub(int inOption, int outXPR, VARIANT *outWeight_Coeff)

VBA prototype:

Private Declare Sub mySub Lib "[dll path here]" (ByVal inOption As Long, ByVal XPR As Long, ByRef outWeight_Coeff As Variant)

This approach allows you to resize the array in C++ (SafeArrayRedim), and/or create a new array and replace whatever array was passed in the argument.

The simplest way to implement that is by using ATL classes CComVariant and CComSafeArray<double>. Don’t forget to use Attach/Detach for the CComVariant, otherwise you might leak memory.

Unfortunately, if you don’t have experience with COM automation in C++, you’ll spend some time implementing that even with ATL utility classes: Attach/Detach, VT_BYREF, different lower bounds, etc., it’s relatively cumbersome for a 2D array.

Upvotes: 1

Related Questions