Заставить мое приложение с пользовательским собственным кодом JNI работать в среде 32 бит Windows 10, но получить сообщение "unsatisfiedlinkerror не может найти зависимые библиотеки" - PullRequest
0 голосов
/ 21 января 2020

В настоящее время я сталкиваюсь с проблемой, заставляющей мое приложение App (написанное и построенное в Eclipse RCP) работать в 32-битной среде Windows 10.

Вот предыстория, я недавно реализовал возможность Windows Shutdown Blocker, используя JNI, встраивая эту возможность в собственный код c ++. В результате я сгенерировал 2 версии dll (используя возможности Cygwin - mingw32 - https://www3.ntu.edu.sg/home/ehchua/programming/howto/Cygwin_HowTo.html) - одну для 64-битных (так же, как у моего dev p c) и одну для 32-битных. Затем соберите их в OSGi Bundle. Затем приложение упаковывается и встраивается в .exe-файл, который можно развернуть на клиентских компьютерах. Некоторые клиенты используют 32-битную Windows, поэтому я должен обслужить ее.

Чтобы проверить это, я настроил виртуальную машину с помощью функции Hyper-V моего компьютера с установленной 32-битной ОС Windows 10 (a * 1134). * оценочная лицензия). Там развернуло мое приложение и попытался инициировать действия, которые запускают возможности Windows Shutdown Blocker, которые я произвел.

Затем я получаю следующую ошибку в журналах (я не получить эту проблему в моей 64-битной Windows среде хоста, и она отлично работает):

!SESSION 2020-01-21 16:48:42.604 -----------------------------------------------
eclipse.buildId=unknown
java.version=1.8.0_60
java.vendor=Oracle Corporation
BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en   _AU
Framework arguments:  --startup plugins/org.eclipse.equinox.launcher_1.4.0.v20161219-1356.jar
Command-line arguments:  -os win32 -ws win32 -arch x86 --startup plugins/org.eclipse.equinox.launcher_1.4.0.v20161219-1356.jar -user @user.home -data @user.home/App/202001201633

!ENTRY org.eclipse.ui 2 0 2020-01-21 16:50:10.579
!MESSAGE Save All Failed
!STACK 0
java.lang.UnsatisfiedLinkError: C:\Users\Dale\App\202001201633\configuration\org.eclipse.osgi\11\0\.cp\lib\shutdown\windows-i686\ShutdownBlocker.dll: Can't find dependent libraries
    at java.lang.ClassLoader$NativeLibrary.load(Native Method)
    at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1938)
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1834)
    at java.lang.Runtime.loadLibrary0(Runtime.java:870)
    at java.lang.System.loadLibrary(System.java:1122)
    …

Сквозной процесс создания файла .dll выглядит следующим образом :

  1. Скачать и установить Cygwin, включая компиляторы g ++ (32-разрядные и 64-разрядные)
  2. Открыть Windows командная строка
  3. Создать файл .h из класса JNI:
javac -h . ShutdownBlocker.java

Это 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
Создайте файл. cpp, т.е. ShutdownBlocker. cpp
#include <jni.h>

#include <iostream>
#include "com_app_service_util_shutdown_ShutdownBlocker.h"
#include <windows.h>

#include <commctrl.h>

using namespace std;

namespace {
    LPCWSTR SHUTDOWN_REASON = L"Application is still saving ...";

    LRESULT CALLBACK AppWndProc(
        _In_ HWND hWnd,
        _In_ UINT message,
        _In_ WPARAM wParam,
        _In_ LPARAM lParam,
        _In_ UINT_PTR uIdSubclass,
        _In_ DWORD_PTR dwRefData
    ) {

        // Callback function required to process some of the key OS messages in order to stall shutdown
        switch (message) {
            case WM_QUERYENDSESSION:
                PostMessage(hWnd, WM_CLOSE, 0, 0);
                return 0;
            case WM_ENDSESSION:
                PostMessage(hWnd, WM_CLOSE, 0, 0);
                return 0;
            case WM_NCDESTROY:
                RemoveWindowSubclass(hWnd, AppWndProc, uIdSubclass);
                break;
        }

        return DefSubclassProc(hWnd, message, wParam, lParam);
    }
}


JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonCreate(JNIEnv *env, jclass cls, jstring title, jstring reasonText) {

    SHUTDOWN_REASON = (LPCWSTR) env->GetStringChars(reasonText, NULL);
    // Parse reasonText string passed in from Java code and retrieve handle to the App window with it
    const jchar *str = env->GetStringChars(title, NULL);
    HWND hWnd = FindWindowW(NULL, (LPCWSTR)str);
    env->ReleaseStringChars(title, str);
    if (hWnd == NULL) {
        return;
    }

    ShutdownBlockReasonCreate(hWnd, SHUTDOWN_REASON);

    // Obtain control of the window by subclassing its procedure
    SetWindowSubclass(hWnd, &AppWndProc, 1, 0);

    return;
}

JNIEXPORT void JNICALL Java_com_app_service_util_shutdown_ShutdownBlocker_shutdownBlockReasonDestroy(JNIEnv *env, jclass cls, jstring title) {
    // Parse reasonText string passed in from Java code and retrieve handle to the App window with it
    const jchar *str = env->GetStringChars(title, NULL);
    HWND hWnd = FindWindowW(NULL, (LPCWSTR)str);
    env->ReleaseStringChars(title, str);
    if (hWnd == NULL) {
        return;
    }

    // Release control of the window procedure
    RemoveWindowSubclass(hWnd, &AppWndProc, 1);

    ShutdownBlockReasonDestroy(hWnd);

    return;
}
Открыть Cygwin Выполнить следующую команду, чтобы сгенерировать файл ShutdownBlocker.dll для каждой Windows архитектуры ОС

Для 64-битных windows

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

Для 32 бит windows

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. Вставка соответствующего раздела здесь:
Bundle-NativeCode: lib/shutdown/windows-amd64/ShutdownBlocker.dll;
  processor=x86_64,
 lib/shutdown/windows-i686/ShutdownBlocker.dll;
  processor=x86, *
Сохранить -> Refre sh -> Очистить -> зафиксировать изменение Использование инструментов сборки для создания исполняемого файла setup.exe (который включает Java время выполнения) для каждой архитектуры ОС Разверните и запустите setup32bit.exe на моей 32-битной Windows ВМ (как упомянуто выше) Запустите приложение, чтобы запустить функцию блокирования выключения Тогда я получу выше ошибка, препятствующая запуску функции блокирования выключения

Мой подход к ее исправлению (напрасно) :

  1. Я пытался использовать DLL-зависимость Ходок, как рекомендовано в этом посте JNI-зависимые библиотеки . Запустил его и обнаружил, что он вызывает много ошибок на зависимостях (что я не считаю очень полезным, потому что я сделал то же самое на случайном файле c: \ windows \ system32 dll, который дает мне аналогичный результат)

enter image description here

Или, может быть, я не правильно использую этот инструмент, вот как я его запускаю:

C:\Users\Dale >depends.exe ShutdownBlocker.dll
Затем я нашел другой пост, в котором предлагается использовать функцию Cygwin под названием «objdump» (https://linux-tips.com/t/how-can-i-find-library-dependencies-of-a-windows-dll/328). Я запустил его и получил следующее:
$ 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
Кажется многообещающим, и я обнаружил, что «libstdc ++ - 6.dll» - единственная DLL, отсутствующая на новом 32-битном виртуальном компьютере. Поэтому я скопировал этот DLL-файл в каталог и обновил переменную PATH. Повторный запуск приложения, но изменения не изменились (та же ошибка)

В каком случае, как узнать, в какой библиотеке возникли проблемы с поиском? Или что-то я здесь не так сделал?

Заранее спасибо всем, кто может пролить свет на эту проблему. И очень ценю ваше время на этом!

Обновленный DLL-файл Изображение зависимости

enter image description here

Обновлено DLL Walker Dependency Image

enter image description here

Думаю, я нашел решение проблемы поиска зависимостей dll для моего ShutdownBlocker.dll. Как вы можете видеть на изображении выше, теперь все выглядит хорошо. Это позволило переместить все зависимые библиотеки, такие как libstdc ++ - 6.dll, libgcc_s_sjlj-1.dll и libwinpthread-1.dll в тот же каталог, что и ShutdownBlocker.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

(не уверен, смогу ли я еще обсудить эту проблему здесь или мне нужно создать новый вопрос?)

...