Java: JNI full manual

Source: Internet
Author: User
Tags sca

Java is favored by people for its cross-platform features. Due to its cross-platform purpose, Java has little internal connection with local machines and limits its functions. One way to solve Java local operations is JNI. Java calls local methods through JNI, while local methods are stored in the form of library files (on Windows platforms, DLL files and so files on UNIX machines ). By calling the internal method of the local library file, Java can achieve close connection with the local machine and call system-level interface methods.

AD:

Recently, I made a mobile phone project in the company. Java programs need to connect to a third-party SMS Server when sending text messages. The SMS interface is written in C ++. After three days, I learned about the main part of JNI. Sort out your experiences and hope your friends can avoid detours.
First, I will reference an article to introduce a simple JNI call process.
Java is favored by people for its cross-platform features. Due to its cross-platform purpose, Java has little internal connection with local machines and limits its functions. One way to solve Java local operations is JNI.
Java calls local methods through JNI, while local methods are stored in the form of library files (on Windows platforms, DLL files and so files on UNIX machines ). By calling the internal method of the local library file, Java can achieve close connection with the local machine and call system-level interface methods.
A brief introduction and application are as follows:
I. What needs to be done in Java
In a Java program, you must declare the name of the called library in the class as follows:

Static {
System. loadlibrary ("Goodluck ");
}

Here, you do not need to write the extension name of the Library. The system determines whether the extension name is DLL or so.
You also need to make a local Declaration on the method to be called. The keyword is native. You only need to declare it, but not implement it. As follows:

Public native static void set (int I );
Public native static int get ();

Then compile the Java program file, generate the class, and use the javah command, JNI will generate the header file of C/C ++.
For example, the content of the program testdll. Java is:

Public class testdll
{
Static
{
System. loadlibrary ("Goodluck ");
}
Public native static int get ();
Public native static void set (int I );
Public static void main (string [] ARGs)
{
Testdll test = new testdll ();
Test. Set (10 );
System. Out. println (test. Get ());
}
}

Compile it with javac testdll. Java to generate testdll. Class.
Then use javah testdll to generate the testdll. h file in the current directory. This file needs to be called by the C/C ++ program to generate the required library file.
II. C/C ++
For the generated. h header file, all C/C ++ needs to do is to implement each of its methods. Compile and connect to the database file. Copy the library file to the path of the Java program, and you can use Java to call the functions implemented by C/C ++.
Connect to the example. Let's take a look at the content of testdll. h:

/* Do not edit this file-it is machine generated */
# Include
/* Header for class testdll */
# Ifndef _ included_testdll
# DEFINE _ included_testdll
# Ifdef _ cplusplus
Extern "C "{
# Endif
/*
* Class: testdll
* Method: Get
* Signature: () I
*/
Jniexport jint jnicall java_testdll_get (jnienv *, jclass );
/*
* Class: testdll
* Method: Set
* Signature: (I) V
*/
Jniexport void jnicall java_testdll_set (jnienv *, jclass, jint );
# Ifdef _ cplusplus
}
# Endif
# Endif

In actual implementation, we only care about two function prototypes.
Jniexport jint jnicall java_testdll_get (jnienv *, jclass); and
Jniexport void jnicall java_testdll_set (jnienv *, jclass, jint );
In this case, both jniexport and jnicall are JNI keywords, indicating that this function is called by JNI. Jint is a type of communication between the Java int type and the local int type through JNI. We can ignore it and use it as an int. The function name is composed of Java _, the package path of the Java program, and the function name. Parameters, we only need to care about the parameters that exist in the Java program. As for jnienv * And jclass, we generally do not need to touch it.
Well, we will use the testdll. cpp file to implement these two functions:

# Include "testdll. H"
Int I = 0;
Jniexport jint jnicall java_testdll_get (jnienv *, jclass)
{
Return I;
}
Jniexport void jnicall java_testdll_set (jnienv *, jclass, jint J)
{
I = J;
}

Compile and connect to the library file. In this example, it is done in windows and the DLL file is generated. And the name must be the same as that to be called in Java. Here is Goodluck. dll. Copy Goodluck. DLL to the directory testdll. Class, and run Java testdll to check the result.

My project is complicated and I need to call the dynamic link library. In this way, when JNI transfers parameters to the C program, the parameters need to be processed and converted. Can be recognized by the C program.
The general procedure is as follows:
Public class sendsms {
Static
{
System. Out. println (system. getproperty ("Java. Library. Path "));
System. loadlibrary ("SMS ");
}
Public native static int smsinit ();
Public native static int smssend (byte [] mobileno, byte [] smcontent );
}

Note that the path must contain the path of the class library. Otherwise, an exception will be thrown during the program running:
Java. Lang. unsatisfiedlinkerror: no SMS in Java. Library. Path
At java. Lang. classloader. loadlibrary (classloader. Java: 1491)
At java. Lang. runtime. loadlibrary0 (runtime. Java: 788)
At java. Lang. system. loadlibrary (system. Java: 834)
At com. mobilesoft. SMS. mobilesoftinfo. sendsms. (sendsms. Java: 14)
At com. mobilesoft. SMS. mobilesoftinfo. Test. Main (test. Java: 18)
Exception in thread "Main"
The Guidance path should be at the upper level of the. dll file. If it is indicated by. dll, it will report:
Java. Lang. unsatisfiedlinkerror: C: \ SMS. dll: Can't Find dependent Libraries
At java. Lang. classloader $ nativelibrary. Load (native method)
At java. Lang. classloader. loadlibrary0 (classloader. Java: 1560)
At java. Lang. classloader. loadlibrary (classloader. Java: 1485)
At java. Lang. runtime. loadlibrary0 (runtime. Java: 788)
At java. Lang. system. loadlibrary (system. Java: 834)
At com. mobilesoft. SMS. mobilesoftinfo. Test. Main (test. Java: 18)
Exception in thread "Main"
Generate the header file com_mobilesoft_sms_mobilesoftinfo_sendsms.h after compilation. (It is recommended to use JBuilder for compilation, which is easier to operate !) This header file is the bond between Java and C. Pay special attention to the jbytearray parameter passed in the method, which will be highlighted in the following process.

/* Do not edit this file-it is machine generated */
# Include
/* Header for class com_mobilesoft_sms_mobilesoftinfo_sendsms */
# Ifndef _ included_com_mobilesoft_sms_mobilesoftinfo_sendsms
# DEFINE _ included_com_mobilesoft_sms_mobilesoftinfo_sendsms
# Ifdef _ cplusplus
Extern "C "{
# Endif
/*
* Class: com_mobilesoft_sms_mobilesoftinfo_sendsms
* Method: smsinit
* Signature: () I
*/
Jniexport jint jnicall java_com_mobilesoft_sms_mobilesoftinfo_sendsms_smsinit
(Jnienv *, jclass );
/*
* Class: com_mobilesoft_sms_mobilesoftinfo_sendsms
* Method: smssend
* Signature: ([B [B) I
*/
Jniexport jint jnicall java_com_mobilesoft_sms_mobilesoftinfo_sendsms_smssend
(Jnienv *, jclass, jbytearray, jbytearray );
# Ifdef _ cplusplus
}
# Endif
# Endif

For the dynamic link library of the C program that I want to call, the C program also needs to provide a header file, SMS. h. The methods to be called in this file are listed.

/*
* SMS API
* Author: yippit
* Date: 2004.6.8
*/
# Ifndef mcs_sms_h
# Define mcs_sms_h
# Define dllexport _ declspec (dllexport)
/* SMS storage */
# Define sms_sim 0
# Define sms_mt 1
/* SMS States */
# Define sms_unread 0
# Define sms_read 1
/* SMS type */
# Define sms_noparse-1
# Define sms_normal 0
# Define sms_flash 1
# Define sms_mmsnoti 2
Typedef struct tagsmsentry {
Int index;/* index, start from 1 */
Int status;/* read, unread */
Int type;/*-1-can't parser 0-normal, 1-flash, 2-mms */
Int storage;/* sms_sim, sms_mt */
Char date [24];
Char number [32];
Char text [144];
} Smsentry;
Dllexport int smsinit (void );
Dllexport int smssend (char * phonenum, char * content );
Dllexport int smssetsca (char * SCA );
Dllexport int smsgetsca (char * SCA );
Dllexport int smssetind (int ind );
Dllexport int smsgetind (void );
Dllexport int smsgetinfo (INT storage, int * max, int * used );
Dllexport int smssaveflash (INT flag );
Dllexport int smsread (smsentry * entry, int storage, int index );
Dllexport int smsdelete (INT storage, int index );
Dllexport int smsmodifystatus (INT storage, int index);/* unread-> Read */
# Endif

With these two header files, you can write C Programs. That is, two methods to call JNI. In the materials on the Internet, the implementation of the called method is relatively simple (mostly print strings), so it avoids the most troublesome part of JNI and is also the most critical part, parameter transfer. Because Java and C are encoded differently, the passed parameters must be processed. Otherwise, the C program will warn the parameters during compilation, for example, warning c4024: 'smssend': Different Types for formal and actual parameter 2.

The SMS. C program is as follows:
# Include "SMS. H"
# Include "com_mobilesoft_sms_mobilesoftinfo_sendsms.h"
Jniexport jint jnicall java_com_mobilesoft_sms_mobilesoftinfo_sendsms_smsinit (jnienv * ENV, jclass jobject)
{
Return smsinit ();
}
Jniexport jint jnicall java_com_mobilesoft_sms_mobilesoftinfo_sendsms_smssend (jnienv * ENV, jclass jobject, jbytearray inclueno, jbytearray smscontent)
{
Char * psmscontent;
// Jsize thearraylengthj = (* env)-> getarraylength (ENV, inclueno );
Jbyte * arraybody = (* env)-> getbytearrayelements (ENV, inclueno, 0 );
Char * pmobileno = (char *) arraybody;
Printf ("[% s] \ n", pmobileno );
// Jsize size = (* env)-> getarraylength (ENV, smscontent );
Arraybody = (* env)-> getbytearrayelements (ENV, smscontent, 0 );
Psmscontent = (char *) arraybody;
Printf ("<% S> \ n", psmscontent );
Return smssend (pmobileno, psmscontent );
}

For C or C ++, the program is slightly different, which can be modified by the reader. Note that getarraylength, getbytearrayelements, and other methods included in these JNI are provided specifically for the conversion parameter type. There are many specific methods, which will be introduced in the next article.
After completing the above files, you can compile SMS. C to generate the. dll file (we recommend that you compile the file in release, so that the dynamic link library will have a small volume !)
After compiling the. dll file, you can call the methods in the C program in Java. For example, test. Java

Public class test {
Public test (){
}
Public static void main (string [] ARGs ){
Byte [] inclueno = {
0x31, 0x33, 0x36, 0x36, 0x31, 0x36, 0x33, 0x30, 0x36, 0x36, 0x37, 0x00 };
String smscontentemp = "good morning ";
Byte [] temp = {0 };
Try {
Byte [] smscontentdb = smscontentemp. getbytes ("GBK ");
Byte [] smscontent = new byte [smscontentdb. Length + temp. Length];
System. arraycopy (smscontentdb, 0, smscontent, 0, smscontentdb. Length );
System. arraycopy (temp, 0, smscontent, smscontentdb. length, temp. Length );
Sendsms = new sendsms ();
Sendsms. smsinit ();
If (sendsms. smssend (inclueno, smscontent)> = 0 ){
System. Out. println ("Chenggong! ");
}
Else {
System. Out. println ("shibai! ");
}
} Catch (exception ex ){}
}
}

Note that when passing the byte array to the C program, the final end must end with 0. This is a method of laziness, but it is an effective method. In most cases, interfaces are provided by a third party. Therefore, we generally do not know how to process parameters in the C method. C requires that the array has a length. Therefore, in Java, if you do not want to write the length of the array passed by a program, ending with 0 in the array is the most convenient method. Of course, if there is a better method, I hope you can propose it.
Here, a complete Java program that calls the dynamic link library through JNI is complete. In fact, it is not very complicated. It is easy to pay more attention to the details.

Original

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.