如何创建可在其他计算机上运行的可再发行 DLL
Posted
技术标签:
【中文标题】如何创建可在其他计算机上运行的可再发行 DLL【英文标题】:How to create a redistributable DLL that will work on other computers 【发布时间】:2013-08-20 09:48:57 【问题描述】:我正在尝试创建一个 GUI,该 GUI 将尝试与连接到计算机的 CAN 外围设备进行交互,并允许计算机与微控制器之间进行通信。大部分工作是用 Java 完成的,但 CAN 代码是用 C++ 编写的,并使用 JNI 从 Java 调用。我正在使用 C++ 的 Visual Studio 2013 和 Java 的 Eclipse。
该程序在开发计算机上运行良好,但我没有创建 DLL 的经验,我无法让该程序在另一台计算机上运行。我已经使用 Dependency Walker 来了解我应该与应用程序捆绑什么 DLL,此时我已经包含了它说丢失的所有 DLL(它说有一些仍然丢失,但它说开发计算机上也缺少这些,我相信这只是 Dependency Walker 的问题。
应用程序文件夹包含 GUI 的可运行 jar 文件、我创建的 DLL 和相关 DLL。我尝试使用“java -jar application.jar”从命令行运行应用程序。我收到以下错误:
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: C:\Users\David\Dropbox\ATPBoardInterface\CANMessager7.dll: A dynamic link library (DLL) initialization routine failed
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary1(ClassLoader.java:1939)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1864)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1854)
at java.lang.Runtime.loadLibrary0(Runtime.java:845)
at java.lang.System.loadLibrary(System.java:1084)
at model.CANController.<clinit>(CANController.java:34)
at main.Main$1.run(Main.java:70)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:721)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:682)
at java.awt.EventQueue$3.run(EventQueue.java:680)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:691)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)
我正在寻找有关如何解决此问题的建议。我可以与任何其他 Windows 计算机共享的东西,最终用户可以轻松安装和运行。
编辑:如果有任何区别,该程序依赖于使用 National Instruments 的 CAN 软件。我在 Dependency Walker 列出的与此相关的应用程序文件夹中包含了许多 DLL,但我不确定这是否足够。也许目标计算机需要已经安装了某些 National Instruments 软件才能工作,如果缺少它,可能会导致 DLL 初始化失败?不过,我对这类领域还不够熟悉,无法确定。
编辑 2:这是我捆绑在我的应用程序文件夹中的内容:
20/08/2013 10:56 <DIR> .
20/08/2013 10:56 <DIR> ..
20/08/2013 08:26 427,170 ATPBoardInterface.jar
20/08/2013 09:28 182,928 CANMessager.lib
20/08/2013 08:52 201,728 CANMessager7.dll
15/08/2013 16:28 30,720 CANMessagerXP.dll
16/06/2013 21:11 966,224 msvcr120.dll
11/07/2006 18:35 348,160 msvcr71.dll
13/10/2012 11:00 655,872 msvcr90.dll
01/06/2011 17:59 45,192 Nican.dll
06/04/2010 17:44 72,224 NicanCfq.dll
06/04/2010 17:44 125,472 nicanDBA.dll
01/06/2011 17:59 197,784 NIcanFrm.dll
01/06/2011 17:59 18,080 NIcanpu.dll
01/06/2011 17:59 61,568 NicanTsk.dll
26/01/2012 15:54 19,632 nipal32.dll
26/01/2012 16:11 309,920 nipalu.dll
26/01/2012 15:53 12,968 nipalut.dll
19/08/2013 16:18 772 README.txt
20/08/2013 08:34 <DIR> res
20/08/2013 10:56 0 temp.txt
20/08/2013 09:43 6,494,784 vcredist_x86.exe
19 File(s) 10,171,198 bytes
3 Dir(s) 416,406,867,968 bytes free
我不确定哪些是必要的。
【问题讨论】:
您是否尝试过编写一个小型的本地 c++ 程序来加载库? 大多数人使用称为 installer 的工具来处理依赖项。我建议你也这样做。另请注意,捆绑 MSVC 可再发行安装程序实际上并没有任何好处,这些 DLL 必须安装到用户的机器上。安装程序可以为您完成。 @Tobias Langner,我没有,但是尝试一下会有好处吗?我知道代码本身可以工作,因为当我在开发机器上从 Java(使用 JNI)调用它时它运行良好。 @CodyGray 我明白了 - 如果有必要,最终用户将能够执行它并将 DLL 安装到他们的系统上。我在目标计算机上尝试过,但没有解决问题。如果我确实使用了它,我可以创建一个“设置”批处理文件来执行它并处理任何其他设置。 你不能像那样部署 msvcr90.dll。它必须安装在 Windows 并行缓存中。使用 Microsoft redist 安装程序将其安装到那里并将其从您的目录中删除。如果您需要更多帮助,请向您正在使用的 DLL 的所有者询问正确的部署说明。 【参考方案1】:一个问题可能是 32 位/64 位问题。
如果您的 CAN 接口 DLL 是 32 位 DLL 并且您正在运行 64 位 Java,这将不起作用。用 32 位 Java 运行 64 位 DLL 也不起作用。
唯一的解决方案是将 DLL 编译为 32 位和 64 位版本并提供这两个 DLL 版本。
如果 32/64 位不是问题,您可以使用 SysInternals ProcessExplorer 工具查看所有文件访问尝试。在这种情况下,您会看到 Java 是否尝试访问任何不存在的 DLL 文件。
解决 32 位/64 位问题的方法是使用命令行 EXE 文件而不是 DLL 文件。使用标准输出和输入(在 C++ 端)以及在 Java 端使用 java.lang.Process 类的 InputStream 和 OutputStream 传输数据。这将始终适用于 32 位 EXE 文件。
【讨论】:
我只使用 32 位 Java。我会试试 SysInternals ProcessExplorer,谢谢。 我运行了两个版本的 GUI,一个尝试加载我的 DLL,一个不尝试加载。我使用 Process Explorer 生成在每种情况下加载的 DLL 列表,将它们保存到文件中并创建一个脚本以仅显示出现在一种情况下而不是另一种情况下的那些 DLL。我将该列表中的所有 DLL 添加到我的应用程序目录中,这些目录中还没有。不过还是没有运气。公平地说,它并没有抱怨缺少 DLL,它只是说“DLL 初始化例程失败”。有没有办法找出目前已经加载了哪些 DLL,现在正在尝试加载哪些?以上是关于如何创建可在其他计算机上运行的可再发行 DLL的主要内容,如果未能解决你的问题,请参考以下文章
如何创建可在 Apple 自研芯片和基于 Intel 的 Mac 机上运行的应用程序
在 Windows 7 中使用 cx_freeze 创建的可执行文件在其他计算机上运行时崩溃并出现有关 PyQt5 的错误