2

so I've got this VBA code that calls DLL code. The DLL code works fine, the VBA code works fine UNTIL I go to call the DLL function from the VBA. For some reason it's not passing the 6th argument correctly. I tested by adding a 7th argument and passing the same value in the 6th and 7th arguments - the 7th passes fine, the 6th passes the same large (incorrect) value. I have no clue what is going on.

VBA:

Option Explicit

' Declare the LMM Function that's in the DLL
Declare PtrSafe Function GenCudaLMMPaths Lib "C:\Path to DLL\LMMExcel.dll" Alias "GenerateCUDALMMPaths" (xTimes#, xRates#, xVols#, xRData#, ByRef ArrLen As Long, ByRef NPaths As Long) As Long


' Generate LMM Paths on Click
Sub LMM_Click()

    Dim Times#(), Rates#(), Vols#()

    Dim x As Long
    Dim y As Long
    Dim rTimes As Range
    Dim rRates As Range
    Dim rVols As Range
    Dim cell As Range

    Dim sz As Long
    sz = 15

    ' Resize
    ReDim Times(sz), Rates(sz), Vols(sz)

    ' Fill in Data
    Set rTimes = Sheets("Market").Range("C2:Q2")

    x = 1
    For Each cell In rTimes
        Times(x) = cell.Value
        x = x + 1
    Next

    Set rRates = Sheets("Market").Range("C5:Q5")

    x = 1
    For Each cell In rRates
        Rates(x) = cell.Value
        x = x + 1
    Next

    Set rVols = Sheets("Market").Range("C4:Q4")

    x = 1
    For Each cell In rVols
        Vols(x) = cell.Value / 10000
        x = x + 1
    Next

    'Call the Function
    Dim np As Long

    np = Sheets("LMM").Range("C2").Value

    Dim useCuda As Boolean

    If Sheets("LMM").Range("C3").Value = "GPU" Then
        useCuda = True
    Else
        useCuda = False
    End If

    Dim rData#()
    Dim rValue

    ReDim rData(np * sz * (sz + 3))

    rValue = GenCudaLMMPaths(Times(1), Rates(1), Vols(1), rData(1), sz, np)

    If rValue = -1 Then
        'No CUDA Card
        MsgBox ("Your system doesn't have a CUDA Enabled GPU")
    ElseIf rValue = 1 Then
        'Error Occurred
        MsgBox ("An error occurred while trying to generate LMM paths")
    ElseIf rValue = 0 Then
        'Success
        ' Need to reformat return data
        Dim fmtData()

        ReDim fmtData(np * sz, sz)

        Dim i, j, k

        For i = 0 To np - 1
            For j = 0 To np - 1
                For k = 0 To np - 1
                    fmtData(((i * sz) + j) + 1, k + 1) = rData(((i * sz * sz) + (j * sz) + k) + 1)
                Next k
            Next j
        Next i

        'Fill in data
        Sheets("LMM").Range("A8:K" & (np * sz)) = fmtData
    Else
        'Too many requested paths for this CUDA card
        MsgBox ("In order to prevent GPU Lock-up, you cannot request more than " & rValue & " paths.")
        Sheets("LMM").Range("C2").Value = rValue
    End If

End Sub

DLL Function Declaration:

int __stdcall GenerateCUDALMMPaths(double* arrTimes, double* arrRates, double* arrVols, double* retData, int& ArrLength, int& NPaths);

DEF File:

LIBRARY "CUDAFinance"
EXPORTS
    CheckExcelArray = CheckExcelArray
    GenerateLMMPaths = GenerateLMMPaths
    GenerateCUDALMMPaths = GenerateCUDALMMPaths

Anyone have any idea here? I'm completely lost.

7
  • can you give examples of the values being passed? Commented Mar 27, 2014 at 15:52
  • 1
    Maybe this will work, np = CLng(Sheets("LMM").Range("C2").Value) Commented Mar 27, 2014 at 15:55
  • I believe you need to pass "ByVal" rather than "ByRef", so that could help, but I think you stated you already tried that in the previous question.... I'm looking up more. Also, where are you seeing the large incorrect value come up? Debugging the dll, or is that in the VBA somewhere? Commented Mar 27, 2014 at 18:25
  • When you say you added a 7th parameter and passed the same value as you have in the 6th, how did you do this? Did you create another variable in the VBA and set it equal to the value of the cell, or did you hard code it as you're doing with sz? I can't think of a single reason why, but I'm wondering if setting the variable for your NPaths parameter equal to a cell value is dragging something else along somehow. Commented Mar 27, 2014 at 18:42
  • 1
    Here's screenshots from the Debug in VS2012 with the 7th arg added. i59.tinypic.com/swajis.png and i60.tinypic.com/hs83rq.png Commented Mar 27, 2014 at 19:33

1 Answer 1

2

I just run into the same problem and got it solved as follows.

Since you already have a long variable in the six arguments function, import the NPaths together with Arrlen as an array without adding a 7th argument:

1) In VBA:

Declare a two elements array:

Dim NArrLenNPaths(1) as long

Then, assign values:

NArrLenNPaths(0) contains ArrLen and NArrLenNPaths(1) the NPaths value.

Keep the function delcaration in VBA but when calling it put NArrLenNPaths(0) as 6th argument. Do not put a 7th argument. The C++ will retreive both values as follows.

2) In C++ use a pointer instead:

Change the 6th argument to

int* NArrLenNPaths

then retreive the values by

int NArrLen = NArrLenNPaths[0];

int NPaths = NArrLenNPaths[1];

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.