Я пишу программу запуска EXE для приложения Java с использованием AutoIt. Он отлично работает при запуске Java через ShellExecute, но по нескольким причинам я хотел бы вызвать его через DLL (чтобы не создавать отдельный процесс)
Но я не могу понять, как предоставить необходимую структуру DLL для вызова. Проблема в том, что это вложенная структура, где вложенный элемент представляет собой массив указателей char *.
Документация JDK содержит пример: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/invocation.html#JNI_CreateJavaV
JavaVMInitArgs vm_args;
JavaVMOption options[4];
// Defining the array and filling the elements is the part I don't know how to do with AutoIt
// (Don't mind the content here)
options[0].optionString = "-Djava.compiler=NONE"; /* disable JIT */
options[1].optionString = "-Djava.class.path=c:\myclasses"; /* user classes */
options[2].optionString = "-Djava.library.path=c:\mylibs"; /* set native library path */
options[3].optionString = "-verbose:jni"; /* print JNI-related messages */
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 4;
vm_args.ignoreUnrecognized = TRUE;
res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
И определения двух структур:
typedef struct JavaVMOption {
char *optionString;
void *extraInfo;
} JavaVMOption;
typedef struct JavaVMInitArgs {
jint version;
jint nOptions;
JavaVMOption *options;
jboolean ignoreUnrecognized;
} JavaVMInitArgs;
После просматривая несколько форумов, я нашел пример кода, который должен запускать JavaVM через DLL (в процессе):
Local $optionArray[2]
$optionArray[0] = "-cp MyApp.jar"
$optionArray[1] = "MyMain"
$env = 0
$option = DllStructCreate("struct;char* optionString;ptr extraInfo;endstruct")
$vmInitArgs = DllStructCreate("struct;LONG version;LONG nOptions;ptr options;BOOLEAN ignoreUnrecognized;endstruct")
; Not sure if this is correct
DllStructSetData($option, "optionString", $optionArray)
DllStructSetData($vmInitArgs, "version", 0x00010008)
DllStructSetData($vmInitArgs, "nOptions", 2)
DllStructSetData($vmInitArgs, "options", DllStructGetPtr($option))
DllStructSetData($vmInitArgs, "ignoreUnrecognized", 1)
Local $handle = DllOpen($dllPath)
$res = DllCall($handle, "INT", "JNI_CreateJavaVM", "ptr*", $env, "ptr", DllStructGetPtr($vmInitArgs))
ConsoleWrite("*** Error: " & @error & @CRLF)
ConsoleWrite("*** Result: " & $res[0] & @CRLF)
DllClose($handle)
Код @error всегда равен 0, но $ res [0] содержит код ошибки (-3), который в теории указывает, что версия JNI неверна, но большинство найденных ответов указывают на то, что это также может означать, что структура JavaVMInitArgs была заполнена неправильно. И учитывая тот факт, что JavaVMInitArgs делает некоторые вещи с указателями, я предполагаю, что способ, которым я заполняю его из AutoIt, не верен.
Я также попытался вызвать DllStructSetData с индексным номером, а не с «именем члена». Я также пытался вызвать DllStructCreate без маркеров "struct / endstruct" и без имен членов.
У меня нет опыта программирования на C / C ++, поэтому я затрудняюсь с отображением информации из Java документов в AutoIt.
Итак, как я могу инициализировать JavaVM из AutoIt, используя JNI_CreateJavaVM
?
Следующим шагом будет запуск программы Java. Для этого мне нужно было бы динамически вызвать findClass()
, чтобы получить указатель на основной класс, а затем вызвать его через JNI.
Если , я могу правильно загрузить JVM, это должно быть чем-то вроде
$aRET = DllCall($env, "str", "FindClass", "str", "ClassName")
Возможно ли то, что я пытаюсь сделать вообще? Или я должен использовать C / C ++ для этого? (Я бы тоже принял этот ответ)