📜 ⬆️ ⬇️

JNI Receive and Connect to JVM in Delphi

Good day to all! Today we will analyze an example of how to get a loaded JVM and connect to it. We need this in order to execute some code inside the JVM. So, let's start:

Create a new project DLL. Add 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. 

Great, added. Next, we need to add a JNI component to Uses:

 uses System.SysUtils, System.Classes, windows, JNI; 

And now let's implement the search and connection to the JVM. To do this, add variables to DllMain:
')
 var I: Integer; JVMArray: array of PJavaVM; NumberOfVMs: JSize; JNIEnv: PJNIEnv; GetCreatedJavaVMs: TJNI_GetCreatedJavaVMs; const BufferSize = 128; 

Next in DLL_PROCESS_ATTACH implement the search and connection of the loaded JVM

 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; 

What is going on here? First we need to get the address of the JNI_GetCreatedJavaVMs function from jvm.dll. Then set the buffer length. Then use the GetCreatedJavaVMs function to get all the loaded JVMs. Well, then just dropout in the buffer until it remains exactly that loaded JVM and connect to it AttachCurrentThread.

So we found and connected to the loaded JVM. Now you can use any code inside the JVM after the AttachCurrentThread line. And in the end we get the DLL code:

 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. 

Let's give an example of how to use it. Suppose you have some function that you want to use in 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; 

This is a simple call to the Method in JNI and in order to use it, it is enough to put this procedure after AttachCurrentThread .

  begin JVMArray[I]^.GetEnv(JVMArray[I], @JNIEnv, JNI_VERSION_1_8); JVMArray[I]^.AttachCurrentThread(JVMArray[I], @JNIEnv, Nil); Com(JNIEnv); end; 

As a result, we get a connection to the JVM and the execution of some procedure there.

Source: https://habr.com/ru/post/324594/


All Articles