问:每当加载我的插件时,Excel 都会抛出以下错误(运行时错误 49,错误的 DLL 调用约定)
尽管绝对没有外部 DLL 引用,但每次都开始弹出对话框,但没有指示错误在哪里。
或者
问:每次我保存特定的代码行时,Excel 都会崩溃。
如何解决这个问题?
此错误可能是由于编译器错误而发生的。最简单的解决方案是进行小的代码更改并重新编译。我通常做的是,
1 -> 将Private Enum
类型添加到插件中任何模块的顶部
Private Enum Something
member = 1
End Enum
2 ->编译插件
3 - >重新启动excel
4 -> 删除所做的代码更改。不再需要了。
即使此错误涉及外部 (DLL) 函数调用,它也可能由 VBA 定义的函数或子例程的参数或返回值类型不匹配触发。此外,当它被这些原因触发时,调试器有时会将错误点显示为不同的函数调用,通常在调用堆栈中更高,包括在创建问题情况之前一直工作且稳定的调用。通常,问题是由固定类型的参数参数或返回值与 Variant 之间的不匹配触发的,反之亦然。
示例:Variant-valued 函数在运行时返回一个 Long 值,该值分配给 Integer 变量。
分辨率:
一种对象方法(例如 AutoFit)应用于该方法不可用的错误对象变体(例如 AutoFit 应用于既不是整行也不是整列范围的范围)。与上述情况类似,错误可能会在存在问题语句的例程的返回点引发,而不是在语句本身。
解决方案:从修复语法问题开始。不幸的是,应该有效的修复有时会继续抛出错误,直到 VBE 编辑器被重置。我还没有推断出解决该问题的最小步骤集,但这样的事情通常有效:
如果对外部库函数的调用被确定为罪魁祸首,请参阅 Microsoft 的错误文档:
错误的 DLL 调用约定
*传递给动态链接库 (DLL) 的参数必须与例程所期望的完全匹配。调用约定处理参数的数量、类型和顺序。您的程序可能正在调用 DLL 中的例程,而该例程被传递了错误类型或数量的参数。
要更正此错误,请确保所有参数类型都与您正在调用的例程声明中指定的类型一致。
确保您传递的参数数量与您正在调用的例程的声明中指示的数量相同。
如果 DLL 例程需要按值的参数,请确保在例程的声明中为这些参数指定 ByVal。
返回参数:在谈论过程参数时很容易忽略的一件事是返回参数。确保它的类型正确,或者它没有丢失。Excel/VBA 用户习惯于这样一个事实,即如果您省略函数的返回类型,系统会隐式地将返回类型设置为 Variant,并且它适用于任何返回的数据。外部声明的函数不是这样!返回类型必须在 DECLARE 语句中声明。*
损坏的库引用:检查模块代码的库引用是否有效。在 VBA IDE 中,选择 Tools=>References以查看引用库的列表,并确保所有选中的项目都没有标记为“ Missing ”。如果是这样,请解决这些问题。
或者,有史以来最好的选择:
- 重写例程的名称。
- 然后重新编译!
你现在可以走了!
有关信息,我还在运行良好的 Excel VBA 代码中遇到了“运行时错误 49,错误的 DLL 调用约定”。
该错误指向一个内部函数调用,对我来说,解决方法是将参数从 ByVal 更改为 ByRef。存在对另一个函数的调用,其中该值已通过 ByRef 传递,因此这可能是一个因素。
另一种代替“更改/添加某些内容并重新编译”的方法是/反编译您的项目。特别是。在可以解决很多问题的大型访问/excel项目中。
只是为了添加另一个可能的原因,我使用Application.OnTime方法来调用带有参数的公共子。该参数意味着很长(当前行),但我猜它实际上是作为字符串值传递的。
这是 OnTime 调用的示例:
Application.OnTime Now + TimeValue("00:00:01"), "'UpdateEditedPref " & curRow & "'"
我尝试对代码执行任意更新并重新编译,但这并没有解决问题。修复它的原因是将被调用子中的参数类型从 long 更改为 string:
Public Sub UpdateEditedPref(ByVal inRowStr As String)
然后,您只需要将字符串转换为 sub 中的值。谢天谢地,没有更多的错误。
更新:使用Application.OnTime传递参数似乎导致了另一个错误,“无法运行宏”。当工作表被锁定时,我收到了这个错误。我仍在使用Application.OnTime,但不是传递参数,而是将值保存在全局变量中并在被调用的子中使用该值。这现在似乎工作正常。
OnTime 调用现在看起来像这样:
' Set global variable
gCurRow = curRow
Application.OnTime Now + TimeValue("00:00:01"), "UpdateEditedPref"
我有一个类似的问题,在我的开发 PC 上它工作得很好。有趣的是,我对同一个例程进行了两次单独的调用,一个有效,另一个无效。在生产 PC 上,不断收到错误消息。尝试重命名例程,更改参数,参数类型无济于事。
对我有用的是将失败的调用例程移动到与被调用子例程相同的模块中。
以前工作的例程已经在同一个模块中。
在我的情况下,这是由于在单个 if 条件下过度使用 continue 字符 _ 造成的
我已经重新编译,检查了所有返回码,移动了模块,重新启动了 excel,重新启动了我的电脑,将代码复制到了一个全新的 Excel 电子表格中,我读了这篇文章,关于返回码的一点让我想到了多少次返回可以在 if 语句中
我有这个
If CompressIntoOneLineON(rg1, rgstart, rgend) or _
CompressIntoOneLineOS(rg1, rgstart, rgend) or _
CompressIntoOneLineOGN(rg1, rgstart, rgend) or _
CompressIntoOneLineOGS(rg1, rgstart, rgend) or _
CompressIntoOneLineGO(rg1, rgstart, rgend) Then
<code>
End If
退出包含此代码的子例程时出现错误所以我更改为
matched = True
If CompressIntoOneLineON(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineOS(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineOGN(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineOGS(rg1, rgstart, rgend) Then
ElseIf CompressIntoOneLineGO(rg1, rgstart, rgend) Then
Else
matched = False
End If
if matched then
<code>
错误消失了
我的实验表明:当我替换声明时,错误:“运行时错误 49,错误的 DLL 调用约定”消失了:
Dim coll as new Collection
在
Dim coll as Collection
Set coll = New Collection
对象必须在创建失败时显式变为 Nothing(如果它本身不是),以便可以追踪其存在。
谢谢, RubberDuck VBA