Excel-VBA with C++ DLL sometimes crashes

2

I made really simple c++ dll with only one function:

int DLL_EXPORT __stdcall foo(double *source){return 0;}

and I'm trying to use it like that:

Option Explicit

Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Private Declare PtrSafe Function FreeLibrary Lib "kernel32" (ByVal hLibModule As LongPtr) As Long

Private Declare PtrSafe Function foo Lib "MyLibrary.dll" (ByRef arr As Double) As Long

Sub test_foo(n As Long)
Dim i As Long
Dim library_address As LongPtr
Dim library_path As String
library_path = "global_path\MyLibrary.dll"
library_address = LoadLibrary(library_path)

Dim arr() As Double
ReDim arr(1 To n) As Double

For i = 1 To n
arr(i) = CDbl(Cells(i, 1).Value)
Next

foo arr(1)

Do Until FreeLibrary(library_address) = 0
Loop

End Sub

and it usually works, but sometimes it crashes (Excel dies).

Faulting application name: EXCEL.EXE, version: 16.0.8625.2139, time stamp: 0x5a162a41
Faulting module name: MyLibrary.dll_unloaded, version: 0.0.0.0, time stamp: 0x000000e2
Exception code: 0xc0000005
Fault offset: 0x00001230
Faulting process id: 0x1828

I've tested on Excel 2016 on Windows 10 and Excel 2013 on Windows 8 Please tell me what is wrong? Do you have any example of non-crashing usage of C++ DLL working on arrays?

WORKAROUND: Replace

Do Until FreeLibrary(library_address) = 0
Loop

with

FreeLibrary library_address

I've put that in the loop because sometimes FreeLibrary doesn't work, but i don't care anymore. Related question here

c++
vba
excel
dll
asked on Stack Overflow Nov 30, 2017 by ingwarus • edited Dec 5, 2017 by ingwarus

1 Answer

0

Integer in VBA is from -32768 to 32767. In C++ it is a way bigger, equivalent to the VBA Long. Thus, try declaring like this:

Private Declare PtrSafe Function foo Lib "MyLibrary.dll" (ByRef arr As Double) As Long


Let me show what I did so far, which worked for me (if this was the way you wanted it). Anyhow, I have changed a few things, it will be better to use some text comparer to see a bit).


int __stdcall SimpleSlowMath(double *source)
{
    return 0;
}

The *.def looks like this:

LIBRARY "SomeLibrary"
EXPORTS
SimpleSlowMath

The VBA:

Option Explicit

Public Const myPathDll = "C:\Users\your-own-path\Debug\vityata051217.dll"

Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" _
    (ByVal lpLibFileName As String) As Long
Private Declare PtrSafe Function FreeLibrary Lib "kernel32" _
    (ByVal hLibModule As LongPtr) As Long
Private Declare PtrSafe Function SimpleSlowMath Lib "vityata051217.dll" _
    (ByRef arr() As Double) As Long

Sub Try(n As Long)

    Dim i                   As Long
    Dim library_address     As Long
    Dim library_path        As String
    library_path = myPathDll
    library_address = LoadLibrary(library_path)

    Dim arr() As Double
    ReDim arr(1 To n) As Double

    For i = 1 To n
        arr(i) = CDbl(Cells(i, 1).Value)
    Next

    Debug.Print SimpleSlowMath(arr)

End Sub

Public Sub TestMe()        
    Dim n As Long        
    For n = 1 To 50
        Try n
        Debug.Print n
    Next n        
End Sub

As you see, the difference is that I declare the array with () here - ByRef arr() As Double, but there are some other as well. Give it a try, for me it was working for 2000 samples.

answered on Stack Overflow Nov 30, 2017 by Vityata • edited Jul 12, 2018 by Vityata

User contributions licensed under CC BY-SA 3.0