解决方案
LabVIEW在调用 DLL 函数时可能会崩溃,原因有很多种。本文档以下各节将讨论防止此类崩溃的方法:
如果“调用库函数节点”中指定的调用规范与 DLL 的调用规范不匹配,则可能导致崩溃。调用规范在“调用库函数”节点配置窗口的右下角指定,如下图所示。
使用 C 调用规范时,调用者负责清理堆栈。使用标准调用规范时,被调用函数负责清理堆栈。如果调用者(LabVIEW)和被调用的 DLL 函数不使用相同的调用规范,那么它们要么都会从堆栈中取出数据,要么都不会。这两种情况都可能导致LabVIEW在被调用函数返回时崩溃。
如果应用程序在LabVIEW开发环境中运行正常,但在作为已编译的可执行文件运行时崩溃,请尝试以管理员身份运行该可执行文件。
- 双击“调用库函数节点”以访问其配置窗口。
- 将要调用的库或对象的绝对文件路径更改为相对文件路径或仅使用库名称。
- 例如,如果您需要调用 User32.dll,您可以使用绝对文件路径 C:\Windows\System32\user32.dll,等效的相对文件路径 %windir%\System32\user32.dll,或 user32.dll”。后两种方法中的任何一种都可以防止崩溃。
如果使用相对路径或库名称仍然无法避免崩溃,您还可以在配置窗口中选择在程序框图中指定路径,如下所示:
在这种情况下,在路径输入中,您需要指定库名称而不是库的路径:
如果未连接“调用库函数节点”的所有输入和输出,DLL 函数将覆盖未分配的内存,导致LabVIEW崩溃。
如果未连接输入,DLL 函数将覆盖未分配的内存。如果您不连接输出, LabVIEW会假定 DLL 函数不需要输入端传递的已分配内存,并将其用于其他用途。
注意: 如果您的第二个输入是指向第一个输入的指针,则第一个输入不需要输出。
如果分配的内存不足,或者 DLL 函数写入的内存超过已分配的内存,则 DLL 将覆盖LabVIEW保留的内存空间,导致LabVIEW崩溃。在从 DLL 中传入和传出数组、字符串或波形之前,请确保已正确分配内存。
许多 DLL 函数会接收通过指针或值传递的已分配内存,写入该内存,然后返回该内存。如果内存分配不正确,可能会导致崩溃。 例如,考虑以下函数:
double *Waveform (double *waveform, uInt32 size);
在这种情况下,分配内存的正确方法是使用 size 参数指定的元素数量初始化数组,而不是传入一个空数组。下图展示了正确的方法。
最可能的问题是,被调用的 DLL 函数损坏了内存。如果将数组或字符串传递给 DLL,则 DLL 函数无法动态调整数组大小。写入超出数组或字符串最后一个元素之外的内容可能会损坏内存,而且在LabVIEW关闭之前,这种损坏可能并不明显。
尝试在“调用库函数”节点中使用不同的错误检查等级,因为如果共享库或 DLL 中被调用的函数写入超出为指定字符串或数组参数分配的空间,则最大值等级可能会返回警告。更多信息请查看调用库函数节点对话框中的“错误检查”部分。
从LabVIEW调用 DLL 函数时,如果参数数据类型不正确(值、引用、句柄等),可能会导致函数无意中指向错误的内存位置,从而导致数据错误,甚至导致LabVIEW或 Windows 崩溃。
如果一个函数本身执行了非法操作,可能会导致LabVIEW崩溃。
如果您在LabVIEW中构建了DLL,并且想要显示 DLL VI 的前面板,则必须遵循两个要求,否则可能会遇到异常 0xC0000005。
- 必须让DLL在任何线程中都允许被调用。这是通过将 线程 单选按钮从 在 UI 线程中运行 更改为 在任意线程中运行 来设置的。所有对LabVIEW构建的共享库的调用都应该指定为 在任意线程中运行。如果您使用LabVIEW构建的共享库配置“调用库函数节点”并指定“在 UI 线程中运行”, LabVIEW可能会挂起并需要重新启动。有关更多信息,请参阅调用库函数对话框。
- 调用 VI 不得在用户界面线程中运行。可以通过从下拉菜单中选择“文件»VI 属性”,从“类别”列表中选择“执行”,并确保“首选执行系统”为“标准”、“仪器 I/O”、 “数据采集”、“其他 1”或“其他 2”来检查这一点。不应选择“与调用方相同”选项,因为父 VI 可能正在用户界面线程中运行。