Я пытаюсь загрузить пользовательскую c++ dll (используя jni) в java, но у меня есть проблема: моя dll с использованием библиотеки cryptopp, и когда java пытается загрузить в зависимости (включая криптопп), приложение завершает работу с сообщением:
Java Результат: -1073741571
Что это, я могу исправить это, не удаляя криптопп?
Обновить:
Если я прокомментировал файлы zCypto.h и zCypro.cpp и удалил все использование библиотеки cryptopp, он работает без каких-либо ошибок, возникла ошибка при загрузке криптоппа. Код Java:
public static void main(String[] args){
System.loadLibrary("cryptopp");
System.loadLibrary("ZCPP_Code64");
}
CPP Source (я делаю dll в Visual Studio 2012):
#include "zCrypto.h"
JNIEXPORT void JNICALL Java_ru_zontwelg_Loader_loadCache
(JNIEnv *env, jobject jobj)
{
std::fstream stream;
stream.open("C:\\testing_capturing\\enc.zwac", ios_base::binary | ios_base::in);
// Other decode & read stuff here ...
stream.close();
}
Заголовок:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class ru_zontwelg_Loader */
#ifndef _Included_ru_zontwelg_Loader
#define _Included_ru_zontwelg_Loader
extern "C" {
/*
* Class: ru_zontwelg_Loader
* Method: loadCache
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_ru_zontwelg_Loader_loadCache
(JNIEnv *, jobject);
}
#endif
zCrypto.h:
#ifndef ZontWelg_zCrypto
#define ZontWelg_zCrypto
#include <dll.h>
#include <cstdio>
#include <Windows.h>
#include <iostream>
#include "cryptlib.h"
using CryptoPP::Exception;
#include "hex.h"
using CryptoPP::HexEncoder;
using CryptoPP::HexDecoder;
#include "base64.h"
using CryptoPP::Base64Encoder;
using CryptoPP::Base64Decoder;
#include "filters.h"
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::StreamTransformationFilter;
#include "sha.h"
#include "rsa.h"
#include "hex.h"
#include "osrng.h"
#include "secblock.h"
#include "modes.h"
#include "aes.h"
using CryptoPP::AES;
//#include "ccm.h"
using CryptoPP::CBC_Mode;
#pragma comment(lib, "cryptlib.lib")
//#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "cryptopp.lib")
using namespace std;
class zCrypto {
public:
static string base64(string in);
static string from_base64(string in);
static string decrypt(const std::string& str_in);
};
#endif
Это выглядит странно для меня, но я не эксперт JNI на любом участке:
public static void main(String[] args){
System.loadLibrary("cryptopp");
System.loadLibrary("ZCPP_Code64");
}
Я бы ожидал увидеть что-то вроде (от одного из моих проектов Crypto++/Android/JNI):
public class PRNG {
static {
System.loadLibrary("stlport_shared");
System.loadLibrary("cryptopp");
System.loadLibrary("prng");
}
private static native int CryptoPP_Reseed(byte[] bytes);
private static native int CryptoPP_GetBytes(byte[] bytes);
private static Object lock = new Object();
// Returns the number of bytes consumed.
public static int Reseed(byte[] seed) {
synchronized (lock) {
return CryptoPP_Reseed(seed);
}
}
// Returns the number of bytes generated.
public static int GetBytes(byte[] bytes) {
synchronized (lock) {
return CryptoPP_GetBytes(bytes);
}
}
}
Не беспокойтесь о stlport_shared
потому что это Android-приложение.
Это также выглядит странно:
#pragma comment(lib, "cryptlib.lib")
//#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "cryptopp.lib")
Поскольку вы вызываете System.loadLibrary("cryptopp")
, это означает, что вы используете DLL Crypto++. Это также означает, что это не нужно: #pragma comment(lib, "cryptlib.lib")
. Выберите статическое связывание или динамическое связывание, но не оба.
Вероятно, было бы проще, если бы вы (1) построили вашу DLL ZCPP_Code64
и (2) статически связаны с Crypto++. Тогда ваш статический загрузчик будет выглядеть так:
static {
System.loadLibrary("ZCPP_Code64");
}
Если вы выберете статическое соединение с Crypto++, вам, вероятно, придется перестроить статический lib. Это потому, что вы попадете в эту конфигурацию:
Your DLL -> dynamic linking against the C Runtime
Crypto++ LIB -> static linking against the C Runtime
Это вызовет кучу повторяющихся символов (C Runtime symbols). Вы хотите:
Your DLL -> dynamic linking against the C Runtime
Crypto++ LIB -> dynamic linking against the C Runtime
Чтобы исправить это, вы открываете проект Cryptlib и изменяете объект привязки Runtime от статического до динамического. См. "Статическое сравнение с динамическим связыванием" при компиляции и интеграции Crypto++ в среду Microsoft Visual C++.
Это выглядит хорошо для меня:
JNIEXPORT void JNICALL Java_ru_zontwelg_Loader_loadCache
(JNIEnv *env, jobject jobj)
{
...
}
Что я не уверен... где родные библиотеки должны быть расположены в Windows. Для этого взгляните на Java JNI и зависимые библиотеки в Windows.
Вам также придется выполнять блокировку, если несколько потоков обращаются к одному и тому же базовому объекту Crypto++. В моем случае основным объектом был AutoSeededRandomPool
:
public class PRNG {
...
// Returns the number of bytes consumed.
public static int Reseed(byte[] seed) {
synchronized (lock) {
return CryptoPP_Reseed(seed);
}
}
// Returns the number of bytes generated.
public static int GetBytes(byte[] bytes) {
synchronized (lock) {
return CryptoPP_GetBytes(bytes);
}
}
}
В вашем случае это может быть Base64Encoder
или Base64Decoder
.
Помните, что все объекты класса Crypto++ являются потокобезопасными, потому что они не имеют доступа к глобальным или общим данным. Но они небезопасны, когда несколько потоков (mis) используют один и тот же объект.
Книга, в которой я консультируюсь по вопросам JNI, - это интерфейс Java Native Interface: Руководство программиста и спецификация.
Наконец, жаль насчет "ответа". Это не ответ. Скорее, это большой комментарий, который не вписывался бы в блок комментариев.
Java Result: -1073741571
), когда загрузка Java скомпилирована 64x crypto ++ System.load("<full path here>\\cryptopp.dll");
или System.loadLibrary("cryptopp");