Всем доброго времени суток! Сегодня разберем пример как получить загруженную JVM и подключиться к ней. Нужно нам это для того, чтобы выполнить внутри JVM некий код.Итак, приступим:
Создаем новый проект DLL. Добавим Process Attach:
Отлично, добавили. Далее нас потребуется в Uses добавить компонент JNI:
А теперь давайте реализуем поиск и подключение к JVM. Для этого в DllMain добавим переменные:
Далее в
Что же тут происходит. Для начала нам нужно получить адрес функции
Итак мы нашли и подключились к загруженной JVM. Теперь можно использовать любой код внутри JVM после строчки
Давайте приведем пример как это использовать. Допустим, у вас есть некая функция, которую вы хотите использовать в Java.
Это простое обращение к Методу в JNI и чтоб его использовать достаточно поместить эту процедуру после
В итоге мы получаем подключение к JVM и выполнение в ней некой процедуры.
Создаем новый проект DLL. Добавим Process Attach:
procedure DllMain(dwReason: LongWord);
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
//**************************
end;
DLL_PROCESS_DETACH:
begin
//***************************
end;
end;
end;
begin
DllProc := @DllMain;
DllProc(DLL_PROCESS_ATTACH);
end.
Отлично, добавили. Далее нас потребуется в Uses добавить компонент JNI:
uses
System.SysUtils,
System.Classes,
windows,
JNI;
А теперь давайте реализуем поиск и подключение к JVM. Для этого в DllMain добавим переменные:
var
I: Integer;
JVMArray: array of PJavaVM;
NumberOfVMs: JSize;
JNIEnv: PJNIEnv;
GetCreatedJavaVMs: TJNI_GetCreatedJavaVMs;
const
BufferSize = 128;
Далее в
DLL_PROCESS_ATTACH
реализуем поиск и подключение загруженной JVMbegin
try
GetCreatedJavaVMs := GetProcAddress(GetModuleHandle('jvm.dll'), 'JNI_GetCreatedJavaVMs');
SetLength(JVMArray, BufferSize);
GetCreatedJavaVMs(@JVMArray[0], BufferSize, @NumberOfVMs);
except
Exit;
end;
if NumberOfVMs > 0 then
begin
for I := 0 to NumberOfVMs - 1 do
begin
JVMArray[I]^.GetEnv(JVMArray[I], @JNIEnv, JNI_VERSION_1_8);
JVMArray[I]^.AttachCurrentThread(JVMArray[I], @JNIEnv, Nil);
end;
end
else
begin
Exit;
end;
Что же тут происходит. Для начала нам нужно получить адрес функции
JNI_GetCreatedJavaVMs
из jvm.dll. Затем установим длину буфера. Затем используем функцию GetCreatedJavaVMs
для получения всех загруженных JVM. Ну а дальше просто отсев в буфере пока не останется именно та загруженная JVM и подключаемся к ней AttachCurrentThread.
Итак мы нашли и подключились к загруженной JVM. Теперь можно использовать любой код внутри JVM после строчки
AttachCurrentThread
. И в итоге мы получаем код DLL:library Project1;
uses
System.SysUtils,
System.Classes,
windows,
JNI;
procedure DllMain(dwReason: LongWord);
var
I: Integer;
JVMArray: array of PJavaVM;
NumberOfVMs: JSize;
JNIEnv: PJNIEnv;
GetCreatedJavaVMs: TJNI_GetCreatedJavaVMs;
const
BufferSize = 256;
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
try
GetCreatedJavaVMs := GetProcAddress(GetModuleHandle('jvm.dll'), 'JNI_GetCreatedJavaVMs');
SetLength(JVMArray, BufferSize);
GetCreatedJavaVMs(@JVMArray[0], BufferSize, @NumberOfVMs);
except
Exit;
end;
if NumberOfVMs > 0 then
begin
for I := 0 to NumberOfVMs - 1 do
begin
JVMArray[I]^.GetEnv(JVMArray[I], @JNIEnv, JNI_VERSION_1_8);
JVMArray[I]^.AttachCurrentThread(JVMArray[I], @JNIEnv, Nil);
end;
end
else
begin
Exit;
end;
end;
DLL_PROCESS_DETACH:
begin
Exit;
end;
end;
end;
begin
DllProc := @DllMain;
DllProc(DLL_PROCESS_ATTACH);
end.
Давайте приведем пример как это использовать. Допустим, у вас есть некая функция, которую вы хотите использовать в Java.
procedure Com(JNIEnv: PJNIEnv);
var
JC: JClass;
JM: JMethodID;
Begin
JC:=jnienv^.FindClass(JNIEnv, 'ru/er_log/components/Frame');
JM:=jnienv^.GetMethodID(jnienv, jc, 'login', 'Ljavax/swing/JTextField;');
jnienv^.CallObjectMethod(jnienv, jc, jm);
End;
Это простое обращение к Методу в JNI и чтоб его использовать достаточно поместить эту процедуру после
AttachCurrentThread
. begin
JVMArray[I]^.GetEnv(JVMArray[I], @JNIEnv, JNI_VERSION_1_8);
JVMArray[I]^.AttachCurrentThread(JVMArray[I], @JNIEnv, Nil);
Com(JNIEnv);
end;
В итоге мы получаем подключение к JVM и выполнение в ней некой процедуры.
Поделиться с друзьями
Комментарии (2)
impwx
22.03.2017 16:01Чтобы статья имела какую-то ценность для обычного читателя, самое интересное должно было начаться после строчки «Теперь можно использовать любой код внутри JVM» — я ожидал пример такого кода и наглядный результат его работы.
Интуиция подсказывает, что сейчас все написанное покрывает один очень специфичный случай, когда в легаси-проекте пришлось ввернуть адский костыль.
Alexeyslav
Инструкция «как нарисовать сову в двух действиях». Не иначе.