Calling Delphi-written DLLs in Java

Source: Internet
Author: User
Tags comparison table

Sometimes, to write some programs, in JAVA is very difficult to implement, but if the use of other programming languages but it is relatively easy, we might as well through the JNI to let the different languages of the program to do together.
JNI tutorial, online C is more, Java also provides javah.exe for the C language JNI program generation header file, if you are a Delphi programmer, can you let Java and Delphi program interaction? The answer is yes, let's take a look at a simple example today.
Helloworld. The main is to understand how JAVA calls the Delphi program method.

OK, let's start by creating a class:

Package alvinjni;

Class HelloWorld {
static {
System.loadlibrary ("Delphiaction"); Wait, we'll use Delphi to make a program, and then the resulting file is DelphiAction.dll. This is a dynamic link library file, which is loaded in a static statement block first.
}

public native void Printtext (); Declare a native local code program, we use Delphi to write. Note: This method is only declared here, and does not define the method body, because this method we have to use Delphi to achieve.

public static void Main (string[] args) {
Create the object and invoke the native method inside.
HelloWorld HW = new HelloWorld ();
Hw.printtext ();
}

}

After the class finishes compiling, the next thing is solved by Delphi.

We run Delphi after the new DLL project: File->new->other, and then select the DLL in the new tab The Wizard creates a new project,
We select a folder to save the project
After saving the project, we need to download Jni.pas to join our project, this is a program unit written by foreign experts, it is convenient for our Delphi program to interact with JAVA. Can be downloaded from the following address: Jni_pas.zip
After the decompression there are two files, which are stored in the project directory

Next we write Delphi code:

Library delphiaction; This sets the name of the dynamic link library, because we just wrote the JAVA class with Delphiaction, so here's what to set to Delphiaction

{Important Note about DLL memory Management:sharemem must is the
First unit in your library ' s USES clause and your project ' s (select
Project-view Source) USES clause If your DLL exports any procedures or
Functions that pass strings as parameters or function results. This
Applies to all strings passed to and from your dll--even those
is nested in records and classes. SHAREMEM is the interface unit to
The BORLNDMM. DLL shared Memory manager, which must be deployed along
With your DLL. To avoid using BORLNDMM. DLL, pass string information
Using PChar or shortstring parameters. There are comments, which are automatically generated and can be deleted.

Uses
JNI; Note that we have just downloaded Jni.pas put in the project directory, here to Uses inside the declaration, in order to use.

Let's write a function to implement a simple method for the JAVA class just now.
Because you want JAVA to be able to invoke this function, the name of the function is very particular, and the delimiter for each segment is the _ Underline
The function of this example is as follows: The method name in the class name _ Java_ Package Name _
function must be set to StdCall
Procedure Java_alvinjni_helloworld_printtext (penv:pjnienv; Obj:jobject); stdcall;
Begin
The function body is very simple, because we just know how to invoke the function of Delphi.
Writeln (' Hello! See how it works. ‘);
End

Exports
Java_alvinjni_helloworld_printtext; Make a declaration of the function so that it is actually called to the

End.

Code complete, we ctrl+f9 compile DLL
After generating DelphiAction.dll, we copy him to the Java engineering directory
Note: The above class is packaged in a ALVINJNI package
If our Java project is in C:/test
Then the compiled class must be placed in the C:/test/alvinjni/helloworld.class
And the newly compiled DelphiAction.dll is placed in the C:/test/delphiaction.dll.
Then execute in the C:/test directory: Java alvinjni/helloworld
See how your Java program invokes the effect of delphiaction.

Oh, cool it! Today we did a little bit, only to learn how to call Delphi and the program in JAVA, in the next, I will post more tutorials to learn some advanced a little bit of JNI knowledge.

Now rare to look at their own blog, today very difficult to find an agent, the way to continue before the topic, is the JAVA and Delphi interaction.

In the previous article, we said how to call Delphi Program in Java a method, today we go a little further, is how to submit a parameter Delphi method, to dynamically control the Delphi method.
Now, let's cut to the chase.

First, we define the following Java classes:

//----------------------------------------------------------------------------------------------------------
Package alvinjni;

Class HelloWorld {
static {
System.loadlibrary ("Delphiaction");
}

public native void Printtext (String str);

public static void Main (string[] args) {
HelloWorld HW = new HelloWorld ();
Hw.printtext ("Hello! See how it works. ");
}

}
//----------------------------------------------------------------------------------------------------------

We'll be like the last time. Build the DLL project in Delphi and write the following code (with comments):

//----------------------------------------------------------------------------------------------------------
Library delphiaction;

Uses
JNI;

This time we're going to write this method because we want to receive a Java pass-through parameter, so let's take a look at this parameter list problem
The first parameter in the argument list is penv type pjnienv, which is the type defined in Jni.pas, and we have a lot of work to do through it, which can be seen as a bridge to help your program communicate with Java.
The first parameter in the argument list, the obj type, is jobject. These two parameters are fixed, and this second parameter is not used for the time being.
Today, we're going to add a parameter to this method that accepts Java-passed arguments. Str:jstring

Procedure Java_alvinjni_helloworld_printtext (penv:pjnienv; Obj:jobject; str:jstring); stdcall;
This time we need to use a Tjnienv object, we declare
Var
jvm:tjnienv;
tmpstr:string;

Begin
Instantiate the JVM, which can be seen as a Java virtual machine. (Self-understanding)
JVM: = Tjnienv.create (penv);

The string submitted by the argument is actually a jstring object, and we are going to use the JVM to transform it here.
We can implement jstring to String conversions by invoking the unicodejstringtostring function of the JVM.
TMPSTR: = JVM. Unicodejstringtostring (str);

Writeln (TMPSTR);

Once we're done with the JVM, we'll release it.
Jvm. Free;
End

Exports
Java_alvinjni_helloworld_printtext; Make a declaration of the function so that it is actually called to the
End.
//----------------------------------------------------------------------------------------------------------

We can now generate DelphiAction.dll to put it in the Java Engineering directory, and then execute alvinjni.helloworld to see the effect.

Well, today we basically realized how to submit a parameter to the Delphi method when Java calls it.
Isn't that cool?

In the previous article, we talked about how to invoke a method of Delphi program with Java and pass it to a string parameter, now let's take a look at what to do if the arguments passed are other basic types.


First, let's look at how to pass an int parameter, which defines the following Java class:

//----------------------------------------------------------------------------------------------------------
Package alvinjni;

Class HelloWorld {
static {
System.loadlibrary ("Delphiaction");
}

public native void Printtext (int i);

public static void Main (string[] args) {
HelloWorld HW = new HelloWorld ();
Hw.printtext (100);
}

}
//----------------------------------------------------------------------------------------------------------

We'll be like the last time. Build the DLL project in Delphi and write the following code (with comments):

//----------------------------------------------------------------------------------------------------------
Library delphiaction;

Uses
JNI;

The parameter we add to this method is: I:jint
Procedure Java_alvinjni_helloworld_printtext (penv:pjnienv; Obj:jobject; I:jint); stdcall;
Var
Tmpint:integer;

Begin
Parameter submitted by the int type data, here is a JInt data, it is actually an Integer data, it is more convenient to use
It can directly participate in the operation of Interger type data, is not very easy.
Tmpint: = i + 100;
Tmpint: = tmpInt-100;
Writeln (Tmpint);
End

Exports
Java_alvinjni_helloworld_printtext;
End.
//----------------------------------------------------------------------------------------------------------

Look at the effect again, is it successful?

If this is a long parameter, it should be set to the Jlong type when it is received, it can also operate with the corresponding integer number, and we use it with Int64.
If the parameter type is float, it is set to the Jfloat type when the parameter is received, and it can be calculated with a single
If the parameter type is double, it is set to the jdouble type when the parameter is received, and it can also be combined with the double type data in Delphi
If the parameter type is Boolean, it is set to the Jboolean type when the parameter is received, and it can also be operated with Boolean data in Delphi
If the parameter type is short, it is set to the Jshort type when the parameter is received, and it can be operated with the SMALLINT type data.
If the parameter type is byte, it is set to the Jbyte type when the parameter is received, and it can also be operated with the Shortint type data
If the parameter type is a Java object, and is to be set to the Jobject type when it is received, it is more complex to use (involving the operation of Java classes and objects) and we will learn later.
If the parameter type is an type[] array, the receive parameter is set to the Jobject type, because Java treats the array as an object. It is to be used in the following way:

For example: We are going to pass a byte[] type array to the Delphi method, and the parameter is declared as Bytearray:jobject when we define the Delphi method

In the method:
Var
Pbytearr:pjbyte//pjbyte is Jni.pas definition, there are Pjboolean, Pjobject, Pjint and so on.
jvm:tjnienv;
Iscopy:boolean;
Begin
jvm:= tjnienv.create (penv);
Iscopy: = false;
Pbytearr: = JVM. Getbytearrayelements (ByteArray, iscopy); Call this method, you can get the address of the parameter ByteArray, iscopy decide whether to copy the array
After that, we can manipulate the passed-in array using the Pbytearr, Inc. (PBYTEARR) pointer.
End

In the previous article, we talked about how to invoke a method of Delphi program with Java and pass it to a parameter
Now let's take a look at what to do if the method you are calling has a return value.


First, we first define the following Java classes:

//------------------------------------------------------------------------------
Package alvinjni;

Class HelloWorld {
static {
System.loadlibrary ("Delphiaction");
}

Public native string Printtext (string arg);

public static void Main (string[] args) {
HelloWorld HW = new HelloWorld ();
System.out.println (Hw.printtext ("Hello"));
}

}
//-------------------------------------------------------------------------------

We'll be like the last time. Build the DLL project in Delphi and write the following code (with comments):

//-------------------------------------------------------------------------------
Library delphiaction;

Uses
JNI;

Today, because this method has a return value, so it is no longer the procedure process, we are going to be function functions, the return value type is jstring
function Java_alvinjni_helloworld_printtext (penv:pjnienv; Obj:jobject; arg:jstring): jstring; stdcall;
Var
tmpstr:string;
jvm:tjnienv;
Tt:boolean;
Begin
jvm:= tjnienv.create (penv);

We're going to use the jstring after we've converted the arguments to a String in Delphi.
TMPSTR: = ' The string you want to output is: ' ' + JVM. Unicodejstringtostring (ARG) + ' ". ‘;

When a string is converted to jstring we need to UTF8 encode the string before converting it to PChar and converting it to jstring
This will ensure that the returned string is not garbled in JAVA
Result: = JVM. Stringtojstring (Pchar (Utf8encode (TMPSTR)));
Jvm. Free;
End

Exports
Java_alvinjni_helloworld_printtext;
End.
//--------------------------------------------------------------------------------

Look at the effect again, is it successful?

Here if the type of the return value is other of its type, such as Jlong,jint,jfloat,jdouble,jboolean,jshort,jbyte
These types of data can be directly related to the data operations in Delphi, corresponding to Int64,integer,single,double,boolean,smallint,shortint
When returned, the value of Delphi can be assigned directly to Result. Such as:
function Java_alvinjni_helloworld_getint (penv:pjnienv; Obj:jobject): JInt; stdcall;
Var
Tmp:integer;
Begin
TMP: = 10;
Result: = tmp;
End

If the type of the return value is a Java object, return the Jobject type, its usage we will come back to learn later.
If the type of the return value is type[] array, to receive the parameter to be set to the Jobject type, how to create such an array object, I do not know, I know later I will paste
Because Java treats arrays as objects. It is to be used in the following ways:

For example: We are going to pass a byte[] type array to the Delphi method, and the parameter is declared as Bytearray:jobject when we define the Delphi method

In the method:
Var
Pbytearr:pjbyte//pjbyte is Jni.pas definition, there are Pjboolean, Pjobject, Pjint and so on.
jvm:tjnienv;
Iscopy:boolean;
Begin
jvm:= tjnienv.create (penv);
Iscopy: = false;
Pbytearr: = JVM. Getbytearrayelements (ByteArray, iscopy); Call this method, you can get the address of the parameter ByteArray, iscopy decide whether to copy the array
After that, we can manipulate the passed-in array using the Pbytearr, Inc. (PBYTEARR) pointer.
End

Before, we learned a way to call Delphi programs in Java.
What if the Delphi program needs to call Java programs at the appropriate time?

First, we first define the following Java classes:

//------------------------------------------------------------------------------
Package alvinjni;

Class HelloWorld {
static {
System.loadlibrary ("Delphiaction");
}
String str = "Hello";

public native void Callprinttext (HelloWorld hw);

public void Printtext (String arg) {
System.out.println (ARG);
}

public static void Main (string[] args) {
HelloWorld HW = new HelloWorld ();
Hw.callprinttext (HW);
}

}
//-------------------------------------------------------------------------------

We'll be like the last time. Build the DLL project in Delphi and write the following code (with comments):

//-------------------------------------------------------------------------------
Library delphiaction;

Uses
JNI;

Today's program is a little more complicated, because the way to invoke Java objects, here you can learn the operation of Jobject
Procedure Java_alvinjni_helloworld_callprinttext (penv:pjnienv; Obj:jobject; Arg:jobject); stdcall;
Var
jvm:tjnienv;
C:jclass; Class ID
Fid:jfieldid; Property ID
Mid:jmethodid; Method ID
tmpstr:jstring;
javaargs:array[0..0] of Jvalue; Parameters when calling a method
Begin
JVM: = Tjnienv.create (penv);

{Let's take a look at how to get a property value for an object}
{----------------------------------------}
{Our operation on the Java object is selected to get the ClassID of this object, we can get it using the following method.}
c: = JVM. Getobjectclass (ARG);

{Let us first get the parameter HelloWorld arg object's String str value of this property
Here we first get the property ID of this property in the class where it resides}
FID: = JVM. Getfieldid (c, ' str ', ' ljava/lang/string; ');
{The parameters in this method called above are: owning Class ID, property name, attribute type signature
For the signature of the property type, the following ' Description 1 ' is given}

{Below, we can get the property value based on the property ID, here we get to arg.str this string}
TMPSTR: = JVM. Getobjectfield (ARG, FID);
{This is the JVM above.} Getobjectfield (ARG, FID) used to get property values
The parameters are: The property ID of the property to get the property of the object to get its properties
Here is a Java String object, is jstring, in fact, it is the jobject type of}
Writeln (' Delphi output: ' + JVM. Unicodejstringtostring (TMPSTR));


{Let's take a look at how to invoke a Jobject method, where we're going to call the Arg.printtext () method}
{------------------------------------------------------------------------------------}
We still need to use the class id:c above.
This time we're going to get the method ID of this method
Mid: = JVM. Getmethodid (c, ' Printtext ', ' (ljava/lang/string;) V ');
The parameters in this method called above are: owning Class ID, method name, method (parameter + return value) type signature
The signature for the type of method (parameter + return value) is given in the following ' Description 2 '

With the method ID, we can use this ID to invoke this method, the method we want to invoke here is: Arg.printtext (parameter);
Because the method we are calling has parameters, when calling the Java method, if there are arguments, to create an array of arguments, here we create the array
JAVAARGS[0].L: = Tmpstr;
{This javaargs is a jvalue type. It's a bit special, and its usage is explained in the following 3 given}

{There is a class image, a method ID, a parameter. Below we can call Arg.printtext (Javaargs) This method, using the following method can be implemented}
Jvm. Callobjectmethoda (ARG, Mid, @javaargs);

Jvm. Free;
End

Exports
Java_alvinjni_helloworld_callprinttext;
End.

//--------------------------------------------------------------------------------

Here we can get the properties of Java objects from Delphi, and we can call a Java object method, isn't it cool?
Did you learn that?


########################## #说明1 ###############################
Now, let's get to know a signature that gets the property ID.
In the example above: FID: = JVM. Getfieldid (c, ' str ', ' ljava/lang/string; '); The signature used is: ' ljava/lang/string; '
Because the property just to be obtained is of type java.lang.String, so its signature is: ' ljava/lang/string; '
If we are going to get a property other than that, how do we sign it when we get the property ID? Here is a comparison table

BYTE--B
Char---C
Double--D
Float--F
INT--I
Long--J (Note: J is not L)
Short--S
void--V
Boolean-z (Note: Z is not B)
Class (object type)-' L ' + Full class name + '; ' (The package path delimiter is: '/'.) as the String pair in the example above, the signature is: ' ljava/lang/string; ')

Array type[]--' [' +type (e.g. float[] signature is ' [float ')
(if it is a two-dimensional array, such as float[][], the signature is ' [[float ')


########################### #说明2 ###############################
Now, let's get to know a signature that gets the "method ID".
In the example above: Mid: = JVM. Getmethodid (c, ' Printtext ', ' (ljava/lang/string;) v '), with the signature: ' (ljava/lang/string;) v '
Signature of method ID, divided into two parts
Part is in the front parenthesis, which is the signature of the parameter type
The other part is after the parentheses, which is the signature of the return value type
The type signature of one of the check and return values is the same as the signature that gets the property ID.
The method to be called above has only one parameter, what if there are multiple parameters?

such as: int getInt (Long A, double b); Such a Java method to sign this way: ' (JD) I '
(Note: The parameter signature is continuous, there is no delimiter, here the first parameter, long signature is: J, the second parameter signature is: D, the return value type int is signed as: I)
Speaking of which, I believe everyone will use this signature.


########################### #说明3 ###############################
When invoking a Java method, if the method has parameters, we will pass the address of an array of arguments to the Java
Now, let's learn more about creating such a parameter array
The arguments passed to the Java method are of type Jvalue. It's a packed record.


If, we are going to call the method void MyMethod (int A, long B, String c); There are 3 parameters
So
1. We will first declare the following array:
Var
Args:array[0..1] of Jvalue;
2. Assigning values to arrays
ARGS[0].I: = 100;
ARGS[1].J: = 100;
ARGS[2].L: = JVM. Stringtojstring (Pchar (Utf8encode (' Open source Chinese Community http://www.oschina.net '));
3. Call
Jvm. Callvoidmethoda (Java object, method ID, @args);

Jvalue is a packed record, which is defined as follows:
Jvalue = Packed record
Case Integer of
0: (Z:jboolean);
1: (B:jbyte);
2: (C:jchar);
3: (S:jshort);
4: (I:jint);
5: (J:jlong);
6: (f:jfloat);
7: (d:jdouble);
8: (L:jobject);
End

When calling a method, Tjnienv also:
Callobjectmethoda:function (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue): Jobject; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callbooleanmethoda:function (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue): Jboolean; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callbytemethoda:function (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue): Jbyte; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callcharmethoda:function (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue): Jchar; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callshortmethoda:function (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue): Jshort; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callintmethoda:function (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue): JInt; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Calllongmethoda:function (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue): Jlong; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callfloatmethoda:function (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue): jfloat; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Calldoublemethoda:function (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue): jdouble; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callvoidmethoda:procedure (env:pjnienv; Obj:jobject; Methodid:jmethodid; Args:pjvalue); {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtualobjectmethoda:function (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue): Jobject; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtualbooleanmethoda:function (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue): Jboolean; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtualbytemethoda:function (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue): Jbyte; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtualcharmethoda:function (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue): Jchar; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtualshortmethoda:function (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue): Jshort; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtualintmethoda:function (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue): JInt; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtuallongmethoda:function (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue): Jlong; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtualfloatmethoda:function (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue): jfloat; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtualdoublemethoda:function (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue): jdouble; {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}
Callnonvirtualvoidmethoda:procedure (env:pjnienv; Obj:jobject; Aclass:jclass; Methodid:jmethodid; Args:pjvalue); {$IFDEF mswindows} stdcall; {$ENDIF} {$IFDEF LINUX} cdecl; {$ENDIF}


Well, here, I believe that we have a certain understanding of the JNI to do Delphi
On the topic of Delphi JNI, let's talk about this.
If you are interested, you can open Jni.pas learn more


Calling Delphi-written DLLs in Java

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.