C++ 使用JNI自定义本机代码使我的应用程序在32位Windows 10环境下工作,但获得;不满意的链接错误可能';“找不到依赖库”;

C++ 使用JNI自定义本机代码使我的应用程序在32位Windows 10环境下工作,但获得;不满意的链接错误可能';“找不到依赖库”;,c++,dll,java-native-interface,32-bit,unsatisfiedlinkerror,C++,Dll,Java Native Interface,32 Bit,Unsatisfiedlinkerror,我目前遇到一个问题,就是如何让我的应用程序App(在EclipseRCP下编写和构建)在32位Windows10环境下工作 下面是背景,我最近通过在C++本地代码中嵌入这种能力,实现了一个使用JNI的Windows关机阻断器功能。因此,我生成了两个版本的dll(使用Cygwin–mingw32功能),一个用于64位(与我的开发人员pc相同),另一个用于32位。然后将它们绑定到OSGi绑定本机代码中。最后,应用程序被打包并构建到一个可以部署到客户端机器的.exe中。有些客户使用32位Windows

我目前遇到一个问题,就是如何让我的应用程序App(在EclipseRCP下编写和构建)在32位Windows10环境下工作

下面是背景,我最近通过在C++本地代码中嵌入这种能力,实现了一个使用JNI的Windows关机阻断器功能。因此,我生成了两个版本的dll(使用Cygwin–mingw32功能),一个用于64位(与我的开发人员pc相同),另一个用于32位。然后将它们绑定到OSGi绑定本机代码中。最后,应用程序被打包并构建到一个可以部署到客户端机器的.exe中。有些客户使用32位Windows,所以我必须满足它

为了测试这一点,我在安装了Windows 10 32位操作系统(Windows评估许可证)的情况下,使用pc的Hyper-V功能设置了一个vm。在那里部署了我的应用程序,并尝试启动启动Windows关机阻止程序功能的活动

然后我在日志中发现以下错误(在我的64位Windows主机环境中,我没有发现这个问题,它工作得很好):

我如何生成.dll文件的端到端过程如下所示:

  • 下载并安装Cygwin,包括g++编译器(32位和64位)
  • 打开Windows命令提示符
  • 从JNI类生成.h文件:
  • 这是Java文件

    public class ShutdownBlocker {
    
        private static boolean nativeLibLoaded;
    
        public static void loadLibrary() {
            if(!nativeLibLoaded) {
                System.loadLibrary("ShutdownBlocker");
                nativeLibLoaded=true;
            }
        }
    
        public static native void shutdownBlockReasonCreate(String title, String reasonText);
    
        public static native void shutdownBlockReasonDestroy(String title);
    }
    
    这是.h文件

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_app_service_util_shutdown_ShutdownBlocker */
    
    #ifndef _Included_com_app_service_util_shutdown_ShutdownBlocker
    #define _Included_com_app_service_util_shutdown_ShutdownBlocker
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_app_service_util_shutdown_ShutdownBlocker
     * Method:    shutdownBlockReasonCreate
     * Signature: (Ljava/lang/String;Ljava/lang/String;)V
     */
    JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonCreate
      (JNIEnv *, jclass, jstring, jstring);
    
    /*
     * Class:     com_app_service_util_shutdown_ShutdownBlocker
     * Method:    shutdownBlockReasonDestroy
     * Signature: (Ljava/lang/String;)V
     */
    JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonDestroy
      (JNIEnv *, jclass, jstring);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    对于32位窗口

    x86_64-w64-mingw32-g++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" -Wl,"C:\Windows\System32\comctl32.dll" -shared -o ShutdownBlocker.dll /cygdrive/c/dale/eclipse-rcp-workspace/App/development/shutdown/ShutdownBlocker.cpp
    
    i686-w64-mingw32-g++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" -Wl,--enable-stdcall-fixup "C:\Windows\SysWOW64\comctl32.dll" -shared -o ShutdownBlocker.dll /cygdrive/c/dale/eclipse-rcp-workspace/App/development/shutdown/ShutdownBlocker.cpp
    
  • 将dll文件复制到适当的位置,以便OSGi Bundle引用
  • 更新OSGi参考
    • 更新build.properties
    • 更新MANIFEST.MF。在此处粘贴相关部分:
  • 保存->刷新->清理->提交更改
  • 使用构建工具为每个操作系统体系结构生成setup.exe可执行文件(与Java运行时绑定)
  • 在我的32位Windows虚拟机中部署并运行
    setup32bit.exe
    (如上所述)
  • 运行应用程序启动关机阻止功能
  • 然后我得到了上面的错误,它阻止了关闭阻止功能的启动
  • 我的修复方法(徒劳)

  • 我试着使用本文推荐的DLL依赖项遍历器。运行它,发现它在依赖项上抛出了很多错误(我觉得这不是很有帮助,因为我在随机的c:\windows\system32 dll文件上也做了同样的操作,这给了我类似的结果)
  • 或者可能我没有正确使用此工具,下面是我运行它的方式:

    C:\Users\Dale >depends.exe ShutdownBlocker.dll
    
  • 然后我发现另一篇帖子建议使用一个名为“objdump”(objdump)的Cygwin功能,我运行了它,得到了以下结果:
  • 看起来很有希望,我发现“libstdc++-6.dll”是新的32位虚拟机上唯一缺少的dll。所以我将这个.dll文件复制到一个目录中,并更新了PATH变量
  • 再次运行应用程序,但更改没有影响(相同错误)
  • 在这种情况下,我如何知道它找不到哪个库?或者我做错了什么

    提前感谢任何能对这个问题有所帮助的人。真的很感谢你花时间在这件事上

    更新的DLL依赖项图像

    更新的DLL依赖项图像

    我想我找到了为我的ShutdownBlocker.dll查找依赖项dll的解决方案。正如你在上图中看到的,现在一切看起来都很好。事实证明,通过将所有相关库(如libstdc++-6.dll、libgcc__sjlj-1.dll和libwinpthread-1.dll)移动到与ShutdownBlocker.dll相同的目录,可以解决此问题。将这些DLL添加到PATH中似乎可以修复我的错误。但是现在我又遇到了一个不同的错误:

    !ENTRY org.eclipse.ui 4 0 2020-01-22 16:57:22.218
    !MESSAGE Unhandled event loop exception
    !STACK 0
    java.lang.UnsatisfiedLinkError: com.app.service.util.shutdown.ShutdownBlocker.shutdownBlockReasonCreate(Ljava/lang/String;Ljava/lang/String;)V
    

    (不确定我是否仍然可以在这里讨论这个问题,或者我需要创建一个新问题?

    不确定实际问题,将DLL置于PATH中应该可以工作。为了确保这一点,请检查它们是否都是32位dll,尤其是msvcrt.dll。一些观察结果:A)您可以忽略Dependency Walker中的“API-MS-WIN-CORE”错误条目,它们在您的情况下并不重要。b) 为了使屏幕截图更有用,您应该折叠除第一级树之外的所有树(c)一旦解决此问题,您将得到更多不满意的链接错误,因为您导出的函数缺少前导下划线(cygin gcc中有一个编译器选项可以获得它们),谢谢@user2543253,根据你的评论,我进一步研究了依赖项遍历程序,发现我的32位ShutdownBlocker.dll不知何故依赖于64位libstdc++-6.dll(有点奇怪)。我一开始不知道我是怎么做到的。因此,我再次将64位libstdc++-6.dll复制到路径位置,得到了另一个错误“未满足的链接错误:…ShutdownBlocker.dll:%1不是有效的Win32应用程序”,这是意料之中的。看来我需要重温一下我是如何编译32位dll的。我在文章中附上了一个依赖性行者的截图。你如何编译你的32/64位库没有问题。如果Dependency Walker显示一个64位DLL,这并不意味着lib需要一个64位DLL,但Dependency Walker找到了一个64位DLL,它不适用于32位应用程序,而不是正确的32位DLL。您必须确保您确实复制了32位DLL(为了安全起见,请从路径中删除libstdc++.DLL的所有64位副本)。好的,忘了这一点,您同时解决了它,我并没有阅读您更新的问题。您的新问题就是我前面提到的带下划线的问题。我想我解决了上一个问题(未满足的链接错误),基本上是通过在我的g++编译中包含“-Wl,--add stdcall alias”标志来删除此错误。这个解决方案可以在JNI教程()的“(Windows)32位JDK[过时?]”部分找到。非常感谢@user2543253的建议!我要做几件事
    i686-w64-mingw32-g++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/win32" -Wl,--enable-stdcall-fixup "C:\Windows\SysWOW64\comctl32.dll" -shared -o ShutdownBlocker.dll /cygdrive/c/dale/eclipse-rcp-workspace/App/development/shutdown/ShutdownBlocker.cpp
    
    Bundle-NativeCode: lib/shutdown/windows-amd64/ShutdownBlocker.dll;
      processor=x86_64,
     lib/shutdown/windows-i686/ShutdownBlocker.dll;
      processor=x86, *
    
    C:\Users\Dale >depends.exe ShutdownBlocker.dll
    
    $ objdump -p ShutdownBlocker.dll | grep DLL
            DLL
     vma:            Hint    Time      Forward  DLL       First
            DLL Name: KERNEL32.dll
            DLL Name: msvcrt.dll
            DLL Name: USER32.dll
            DLL Name: libstdc++-6.dll
            DLL Name: COMCTL32.dll
    
    !ENTRY org.eclipse.ui 4 0 2020-01-22 16:57:22.218
    !MESSAGE Unhandled event loop exception
    !STACK 0
    java.lang.UnsatisfiedLinkError: com.app.service.util.shutdown.ShutdownBlocker.shutdownBlockReasonCreate(Ljava/lang/String;Ljava/lang/String;)V