Эксперт С++
 Аватар для ITcrusader
179 / 165 / 21
Регистрация: 12.02.2013
Сообщений: 410

Executing Java-code from C++-code via JNI

18.09.2014, 11:29. Показов 6996. Ответов 24
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем привет! Убежден, что ошибся с выбором раздела для публикации вопроса, но честно говоря, не знаю, куда его лучше поместить.

В общем, в чем суть. Вызов нативных методов из Java много где описан. Обратный же порядок взаимодействия - мало где. Моя проблема в том, что по существующим статьям мне не удается собрать и запустить всю эту беду.

Если у кого-то есть соответствующий опыт, хотел бы просить что-нибудь типа пошаговой инструкции по написанию и процессу сборки простейшего приложения, которое просто вызывает из плюсового кода что-то тривиальное, написанное на Java.

Надеюсь, такие мастера имеются)
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
18.09.2014, 11:29
Ответы с готовыми решениями:

Ошибка The thread 0x390 has exited with code 0 (0x0). The program 'D:AlexVVCPr1DebugPr1.exe' has exited with code 0 (0x0).
Loaded 'D:WINNTSystem32 tdll.dll', no matching symbolic information found. Loaded 'D:WINNTsystem32kernel32.dll', no matching symbolic...

Неуправляемый код (unmanaged code) в управляемом коде (managed code)
Товарищи! Прошу Вашей профессиональной помощи. 1. Что происходит в блоке выделенным красным шрифтом (после static class NativeMethods),...

коды (например [code]�[/code]) русских символов
В литовском языке буквы можна закодировать в виде ę - ę и они будук корректно отображаться при любой кодировке страницы. Какие коды...

24
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
22.10.2014, 15:33
Студворк — интернет-сервис помощи студентам
JVM после успешного создания перемещается в отдельный поток, поэтому плюсовый код будет работать с JVM из другого потока.

Добавлено через 33 минуты
Да и код JNI вроде тоже в своем потоке выполняется, сейчас некогда разбираться.
1
Эксперт С++
 Аватар для ITcrusader
179 / 165 / 21
Регистрация: 12.02.2013
Сообщений: 410
23.10.2014, 15:33  [ТС]
Ребят, если у кого есть совет, буду благодарен!

Сейчас у меня имеется приложение на Java, которое в один прекрасный момент подгружает плюсовую динамическую библиотеку и запускает оттуда посредством JNI функцию, которая в свою очередь посредством JNI обращается к Java-библиотеке, т.е. получается так: Java -> C++ -> Java.

Если убрать главное приложение на Java, то все уже протестировано и работает. Если же Выстраиваю цепочку, проиллюстрированную выше, то, как и ожидалось, плюсовая библиотека, подгруженная уже работающей JVM, не может сама создать новую JVM для себя. Т.е. JNI_CreateJavaVM - становится бесполезной в этом контексте функцией.

Переворачивая интернеты с ног на голову, я наткнулся на такую же проблему, что и у меня, вот ссылка на stackoverflow:

http://stackoverflow.com/quest... 7#26522377

Там так и не предложена альтернатива, а может и предложена вот в этом комментарии:
You cannot create a JVM inside of an application already running in a JVM. You can only attach to it. In other words, only one instance of the JVM may run at anytime for a single instance of any application. Secondly, the calling conventions aren't there.. Since you cannot create the JVM inside of an already running Java app (which has its own JVM), env and jvm will be NULL.

Но я тут конкретики не вижу и сам не смог найти пока. Можно ли все-таки как-то наладить такое взаимодействие, или это нереализуемо?
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
23.10.2014, 16:21
А JNI_CreateJavaVM что возращает?

Добавлено через 21 минуту
Я никогда подобным не занимался, но задача интересная. Смотри, в файле jni.cpp нашел функцию
C++
1
_JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetCreatedJavaVMs(JavaVM **vm_buf, jsize bufLen, jsize *numVMs
ты можешь получить в vm_buf созданные машины и использовать одну из них. В numVMs будет кол-во машин, ну а buflen думаю понятно. Как ее потом использовать я не знаю. Можно посмотреть jni.cpp, наверняка найдется что-нибудь полезное. Я файл не смог прикрепить, слишком большой (даже в архиве). Есть проект IcedTea, у них есть mercurial репозиторий, где можно посмотреть / взять этот файл.

Добавлено через 18 минут
Опираясь на код из 3 поста можно попробовать так - при помощи JNI_GetCreatedJavaVMs получаем машины, проверяем, что они есть, берем первую машину, она будет в структуре
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct JavaVM_ {
    const struct JNIInvokeInterface_ *functions;
#ifdef __cplusplus
 
    jint DestroyJavaVM() {
        return functions->DestroyJavaVM(this);
    }
    jint AttachCurrentThread(void **penv, void *args) {
        return functions->AttachCurrentThread(this, penv, args);
    }
    jint DetachCurrentThread() {
        return functions->DetachCurrentThread(this);
    }
 
    jint GetEnv(void **penv, jint version) {
        return functions->GetEnv(this, penv, version);
    }
    jint AttachCurrentThreadAsDaemon(void **penv, void *args) {
        return functions->AttachCurrentThreadAsDaemon(this, penv, args);
    }
#endif
};
получем evn при помощи GetEnv, а дальше все как в 3 посте.
В penv тебе запишется вот что
C++
1
*(JNIEnv**)penv = ((JavaThread*) thread)->jni_environment();
т.е. *penv будет указывать на JNIEnv

Добавлено через 1 минуту
Цитата Сообщение от Kastaneda Посмотреть сообщение
берем первую машину
вот тут я не уверен можно ли просто так брать и использовать любую машину
1
Эксперт С++
 Аватар для ITcrusader
179 / 165 / 21
Регистрация: 12.02.2013
Сообщений: 410
27.10.2014, 10:21  [ТС]
В общем, проблема решена)

Выложу здесь в двух словах. Может, у кого-то в будущем возникнет похожая проблема, а она, как мне показалось, тяжело гуглится.

Вот код, который был у меня и работал, когда связка была следующей: C++ -> Java
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void JVM:: Init( const std:: string& javaClassesPath )
{
    // initializing of JVM options: 
    std:: string optionString = ( std:: string("-Djava.class.path=") + javaClassesPath );
    JavaVMOption options_;  
    options_.optionString = const_cast<char*>( optionString.c_str() );
    
    // initializing of JVM initial arguments:
    JavaVMInitArgs arguments_;
    memset( &arguments_, 0, sizeof( arguments_ ) );
    arguments_.version = JNI_VERSION_1_6;
    arguments_.nOptions = 1;
    arguments_.options = &options_;
    arguments_.ignoreUnrecognized = 0;
 
    // creating JVM:
    long status = JNI_CreateJavaVM( &jvm_, (void**)&env_, &arguments_ );    
    if ( status == JNI_ERR )        
        throw std:: exception("Error: unable to create Java Virtual Machine.\n");
 
    FindClass("ChartBuilder");
}
Вызывалось это так:
C++
1
JVM JChartBuilder( "D:\\Java Src\\Chart\\Chart.jar" ); // путь, который будет указан в качестве classpath при создании VM (иначе будет невозможно выполнить FindClass и добиться успешного выполнения его)

Далее, когда связка стала сложнее: Java -> C++ -> Java, то создавать новую машину в рамках уже запущенного процесса нельзя, поэтому нужно присоединяться к уже запущенной. Поэтому модифицировал код выше так, чтобы он определял, что ему делать:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void JVM:: Init( const std:: string& javaClassesPath )
{
    // initializing of JVM options: 
    std:: string optionString = ( std:: string("-Djava.class.path=") + javaClassesPath );
    JavaVMOption options_;  
    options_.optionString = const_cast<char*>( optionString.c_str() );
    
    // initializing of JVM initial arguments:
    JavaVMInitArgs arguments_;
    memset( &arguments_, 0, sizeof( arguments_ ) );
    arguments_.version = JNI_VERSION_1_6;
    arguments_.nOptions = 1;
    arguments_.options = &options_;
    arguments_.ignoreUnrecognized = 0;
 
    // creating JVM or attaching to JVM:
    long status;
    /* выясняем, есть ли созданная машина */
    JavaVM* createdVMs[1] = { nullptr };
    jsize numberOfVMs;
    status = JNI_GetCreatedJavaVMs(createdVMs, 1, &numberOfVMs);
    /* END OF выясняем, есть ли созданная машина */
    if( numberOfVMs != 0 )
    {   // если машина есть
        jvm_ = createdVMs[0]; // получаем машину
        jvm_->AttachCurrentThread((void**)&env_, NULL); // аттачимся к ней
    }
    else
    {   // если машин нет - создаем, как и раньше
        status = JNI_CreateJavaVM( &jvm_, (void**)&env_, &arguments_ ); 
    }
 
    if ( status == JNI_ERR )        
        throw std:: exception("Error: unable to create Java Virtual Machine.\n");
 
    FindClass("ChartBuilder");
}
Все бы ничего, но при запуске на выполнения Java-проекта, который является первым в связке Java->C++->Java, получаем проблему невозможности найти класс ChartBuilder. Т.е. к машине мы присоединились, но класс найти не можем. И не можем по понятным причинам: при создании новой JVM, её плюсовый проект передавал необходимый classpath. При запуске же всей беды через главный Java-проект, путь в момент аттача к машине из плюсов - неизвестен, поэтому остается лишь запускать главный Java-проект, указывая ему при запуске дополнительно тот classpath, который требуется для нахождения ChartBuilder.

Вот. Остается, конечно, еще нерешенный вопрос о том, можно ли после аттача как-то известить VM о новых classpath вместо того, чтобы вводить их при запуске всего проекта, но данный момент в рамках задачи моей не критичен, поэтому пока ответа на него у меня нет. Может, у кого-нибудь есть?

Kastaneda, да, спасибо, это все правильные были рекомендации, у меня, как оказалось, просто трудности были в доведении реализации до конца.
1
27.10.2014, 13:10

Не по теме:

Залез на SO по ссылке, чтоб решение выложить, да смотрю тов. с ником ITcrusader уже это сделал :)

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
27.10.2014, 13:10

IIS, ASP and SSI [code<!--#echo var='DATE_LOCAL'-->[/code]
&lt;!--#include file='text.txt'--&gt; &lt;!--#include file='conn.asp'--&gt; Всё это работает под IIS ... а вот это не работает :(( IIS...

В чём заключается разница между компиляцией в P-code и Native-code?
Извините что я такой ламмер, но в чём заключается разница между компиляцией в P-code и Native-code??? Просто очень интересно...

Передача строк data.php?code=$code&name=$name
При передаче строки $name=&quot;Hello word&quot;; data.php?code=$code&amp;name=$name передается только Неllo как сделать чтобы передавалась вся...

Visual Basic 5 компиляция в P-Code и в Native Code - различия
Из одного и того же исходного кода: скомпилировано два exe-файла один в P-Code - BitBlt32p.exe другой в Native Code -...

Code First с БД PostgreSQL в Visual Studio Code на Linux
Здравствуйте! Возникла проблема с подключением к БД PostgreSQL, обо всем по порядку: Стоит система Ubuntu 17.10, работаю в Visual...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
25
Ответ Создать тему
Опции темы

Новые блоги и статьи
Мысли в слух
kumehtar 17.08.2026
Забавно, насколько сейчас стала доступна информация. Например о магии, духовном развитии, медитациях, и других подобных направлениях, ранее зачастую тайных, передаваемых от учителя к ученику. Хотя. . .
Перемещение строк из ТЧ в другой документ с учетом текущего пробега
Maks 17.08.2026
Реализация из решения ниже выполнена на примере нетипового документа "Автозапчасти", с ТЧ "Шины". За основу взят алгоритм отсюда: https:/ / www. cyberforum. ru/ blogs/ 359708/ 10838. html Задача: . . .
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru