【问题标题】:Excel-VBA with C++ DLL sometimes crashes带有 C++ DLL 的 Excel-VBA 有时会崩溃
【发布时间】:2017-11-30 14:21:16
【问题描述】:

我用一个函数制作了非常简单的 c++ dll:

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

我正在尝试这样使用它:

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

它通常可以工作,但有时它会崩溃(Excel 死了)。

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

我已经在 Windows 10 上的 Excel 2016 和 Windows 8 上的 Excel 2013 上进行了测试 请告诉我有什么问题吗?您是否有任何使用 C++ DLL 处理数组的非崩溃用法示例?

解决方法: 替换

Do Until FreeLibrary(library_address) = 0
Loop

FreeLibrary library_address

我把它放在循环中是因为有时 FreeLibrary 不起作用,但我不再关心了。相关问题here

【问题讨论】:

  • "但有时它会崩溃(Excel 死掉)。"请更具体。
  • 我不能更具体... Excel 尝试“解决问题”,放弃并重新打开。它随机崩溃。有时在第二次运行后,有时在第 200 次运行后。

标签: c++ vba excel dll


【解决方案1】:

VBA 中的整数是从 -32768 到 32767。在 C++ 中它更大,相当于 VBA Long。因此,尝试这样声明:

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


让我展示一下我到目前为止所做的事情,这对我有用(如果这是你想要的方式)。反正我改了一些东西,还是用一些文本比较器看看比较好)。


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

*.def 看起来像这样:

LIBRARY "SomeLibrary"
EXPORTS
SimpleSlowMath

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

如您所见,不同之处在于我在这里用() 声明数组-ByRef arr() As Double,但还有其他一些。试一试,对我来说它适用于 2000 个样本。

【讨论】:

  • @ingwarus - 振作起来,今天是星期五! :)
  • 那一点点变化(从整数到长)没有帮助。 :-(
  • @ingwarus - 查看编辑后的答案,我认为问题出在arr() 的括号中。
  • 您的代码运行正常,我发现了问题所在。谢谢! :-)
  • @ingwarus - 是arr() 和括号吗?
猜你喜欢
  • 2021-06-28
  • 2021-09-07
  • 1970-01-01
  • 1970-01-01
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
  • 2018-07-16
  • 1970-01-01
相关资源
最近更新 更多