Results 1 to 1 of 1
  1. #1
    Bytesize
    Bytesize is offline
    New member
    Join Date
    2012 Oct
    Location
    rt.jar
    Posts
    5
    Thanks Thanks Given 
    0
    Thanks Thanks Received 
    0
    Thanked in
    0 Posts
    Rep Power
    0

    Java JNI tutorial (Bridge between Java and C)

    Hello, this is a tutorial I wrote back in '08. I hope this will benefit the community so I'm going to copy and paste it from my website. I've cleaned it up a bit and added some BB code to make it easier to read.

    This is a JNI tutorial that I (SteveO) put together to help anyone write The JNI (Java Native Interface) style natives.

    This brief tutorial will go over these topics:
    • Scope
    • Why JNI?
    • Passing Strings from C to Java through a StringBuffer, Accessor Methods
    • Passing Strings from Java to C, with localization
    • Passing int from java to C
    • Passing C Structures from C to Java
    • Directly Passing a String from C to Java, Field Access
    • Making Java Strings in C
    • Passing a Single String Array Element from C to Java
    • Passing a Single Int Array Element from Java to C
    • Passing a Single Int Array Element from C to Java
    • Newing up a Java object in C


    Scope of this document

    This document is for programmers that already know how to write Java native code and want to conform to the new JNI specification.

    Why convert my native code to JNI?

    First, if you do not, there is no guarantee that your natives will work with version 2.0 of the JVM. Version 1.1 is a transition version for native programming. I have heard rumors that unless you use JNI, your natives will not work with a 2.x version JVM. The JVM from Microsoft will not work with JNI. They have splintered off with their own JVM which uses a different flavor of natives. Microsoft's solution is RNI: Raw Native Interface. If you want natives to work with the MS JVM, you will have to maintain a different source for the RNI natives. If you plan on distributing libraries, you should write to the JNI and the RNI interfaces.

    Before the JNI, assumptions about memory layout were taken. The JNI is not difficult, neither is it trivial. It is more difficult than just unhanding a java object and making the calls. But once you get used to it, it isn't that bad.

    Step 1: Declaring the Native

    Code:
    public native int add(int a, int b);
    Step 2: Compile the java file with the Native

    Code:
    javac AddMe
    Step 3: Run javah -jni on the class file

    Code:
    javah -jni file
    Step 4: Look at the .h file produced

    Step 5: Access java objects with the JNIEnv pointer

    You must use the generated names for you functions straight from the .h file. So:
    Code:
    JNIEXPORT jint JNICALL Java_AddMe_AddMeNtv  (JNIEnv *, jobject, jint, jint);
    is the call generate by javah (see AddMe.h), and that must be your function declaration in your C code. See the sun tutorial for more information.

    Passing Strings from C to Java through a StringBuffer, Accessor Methods

    C code:
    Code:
          	HArrayOfChar *charArray;
          	long length = unilen(cAbbreviatedName);
          
          	charArray = makeCharArray(cAbbreviatedName, length);
    
          	execute_java_dynamic_method (
                   EE(),
                   (HObject *) abbreviatedName,
                   "append",
                   "([C)Ljava/lang/StringBuffer;",
                   charArray);
    Using JNI:

    Code:
          	JNIEXPORT jint JNICALL 
    Java_COM_novell_nsi_libsWrapper_BinderyJNI_NWScanObject  /* modified for example */
    (
       JNIEnv   *env,
       jclass   obj, 
       jobject  objName,           // out, optional, StringBuffer
    )
    {
       nstr8 cObjectName [MAX_BINDERY_OBJECT_NAME_LEN];
    
       jstring javaString;   
       jclass cls;
       jmethodID mid;   
       
       //...
    
       //Some code to get cObjectName
       javaString = (jstring)(*env)->NewStringUTF(env, (const char *)cObjectName);
    
       cls = (*env)->GetObjectClass(env, objName);
       mid = (*env)->GetMethodID(env, cls, "append","(Ljava/lang/String;)Ljava/lang/StringBuffer;");
       if (0 == mid)
       {
          printf("GetMethodID returned 0\n");
          return(-1);
       }
       (*env)->CallObjectMethod(env, objName, mid, javaString);
    Passing Strings from Java to C, with Localization

    The 1.0 old way was to use the call:

    Code:
    javaString2CString(javaStr,cStr,sizeof(cStr));
    Now we have two options:
    Use the netware localization routines to make a CString
    or call
    Code:
    GetStringUTF(env,javaobj,cStr);
    GetStringUTF creates a UTF string which if the high bit is not set, then it is like any normal CString. If the Highbit is set, it indicates the next char belongs to the same character. UTF is compressed unicode. Example (old way):
    Code:
    javaString2CString (oldPassword, oldPasswordStr, sizeof (oldPasswordStr));
    Example (new way with localization):

    Code:
          	CFunction(JNIEnv *env,
             jclass cls,
             jstring  jString) // this guy comes in
    {
    
       unicode *uStr;
       pnstr cLocalizedStr;
       size_t uLength;
    
       cLocalizedStr =(pnstr) malloc(((*env)->GetStringLength(env,jString)+1)*2);
       uStr = (unicode *)(*env)->GetStringChars(env,jString,0);  //stays in unicode
    
       ccode = NWUnicodeToLocal(_hUnicodeToLocal,
                                  ((pnuint8) cLocalizedStr), // this will contain our new string
                                  ((*env)->GetStringLength(env,jString)+1),
                                  uStr,
                                  0xFF, // strNoMap
                                  &uLength
                                  );
    
       if(N_SUCCESS != ccode)
       {
          return(ccode);
       }
    }
    Example (jni way without localization):

    Code:
    uStr = (unicode *)(*env)->GetStringChars(env,jString,0);  //stays in unicode
    Example Cstring, you are sure is not unicode ever.

    Code:
    Str = (*env)->GetStringUTFChars(env,jString,0);  //regular C string
    Passing int from Java to C

    This is so simple it hardly deserves mention.
    In java:

    The native declaration:
    Code:
    public native int passInt(int intToPass);
    The java call

    Code:
          	int j = 1;
       passInt(j);
    The native handling in C

    Code:
          	JNIEXPORT jint JNICALL 
    Java_passInt(jint  thePassedInt)
    {
       //jint in C is a signed 32 bit integer;
       printf("the int is %d",thePassedInt);
       
       //There is no way to change the java variable directly.
       thePassedInt = 5; // this gets lost after the return.
       return(thePassedInt); // you could return it, 
                             // But what if you have more than one to return?
                             // Then you must pass in (Integer?) objects and set the values
                             // through CallObjectMethod() or SetIntField().
    }
    Passing Objects from C to Java

    Code:
            cls = (*env)->GetObjectClass(env, objID);
             mid = (*env)->GetMethodID(env, cls, "setValue","(I)V");
             if (0 == mid)
             {
                printf("GetMethodID returned 0\n");
                return(-1);
             }
             (*env)->CallVoidMethod(env, objID, mid, cObjectID);
    Directly Passing a String from C to Java, Field Access

    Code:
          	name = (*env)->NewStringUTF(env,entryInfo.entryName);
          if (name == NULL)
          {
             printf("NewStringUTF returned NULL\n");
             return (-1);
          }
          fid = (*env)->GetFieldID(env,clazz,"entryName","Ljava/lang/String;");
    
          (*env)->SetObjectField(env,info,fid,name);
    Passing C Structures from C to Java

    In java you need an object to represent the structure.
    Then you pass the java object into the native.
    From C, access the class directly with calls to SetTypeField, where type
    is a java type.

    In the following example, info is the java type which represents the
    C structure testInfo.

    Code:
    struct info{
          int index;
          int space;
          int count;
          int key;
          int nameLength;
          char name[30];
    }testInfo;
    Here is the java class to represent testInfo

    Code:
    public class EntryInformation
    {
       protected int index;
       protected int space;
       protected int count;
       protected int key;
       protected int nameLength;
       protected String  name;
    }
    Here is the native call.

    Code:
          	JNIEXPORT jint JNICALL 
    Java_FillCStruct
    (
       JNIEnv *env, 
       jclass obj, 
       jobject    info      // EntryInformation object instantiation
    )
    {
       testInfo entryInfo;
       jclass clazz;
       jfieldID fid;
       jmethodID mid;
    
       GetInfo(entryInfo);   // fills in the entryInfo
    
       clazz = (*env)->GetObjectClass(env, info);
       if (0 == clazz)
       {
          printf("GetObjectClass returned 0\n");
          return(-1);
       }
       fid = (*env)->GetFieldID(env,clazz,"index","I");
    
       // This next line is where the power is hidden. Directly change
       // even private fields within java objects. Nasty!
       (*env)->SetIntField(env,info,fid,testInfo.index); 
    
       fid = (*env)->GetFieldID(env,clazz,"space","I");
       (*env)->SetIntField(env,info,fid,testInfo.space);
    
       fid = (*env)->GetFieldID(env,clazz,"count","I");
       (*env)->SetIntField(env,info,fid,testInfo.count);
    
       fid = (*env)->GetFieldID(env,clazz,"key","I");
       (*env)->SetIntField(env,info,fid,testInfo.key);
    
       fid = (*env)->GetFieldID(env,clazz,"nameLength","I");
       (*env)->SetIntField(env,info,fid,testInfo.nameLength);
       
       name = (*env)->NewStringUTF(env,testInfo.name);
       if (name == NULL)
       {
          clazz = (*env)->FindClass(env,"java/lang/OutOfMemoryError");
          (*env)->ThrowNew(env,clazz,NULL);
          return (-1);
       }
       fid = (*env)->GetFieldID(env,clazz,"name","Ljava/lang/String;");
       (*env)->SetObjectField(env,info,fid,name);
    }
    Making Java Strings in C

    non-jni code:
    Code:
          	Hjava_lang_String *name;
          name = makeJavaString (cName, strlen (cName));
    jni code:
    Code:
          	name = (*env)->NewStringUTF(env,cName);
          if (name == NULL)
          {
             clazz = (*env)->FindClass(env,"java/lang/OutOfMemoryError");
             (*env)->ThrowNew(env,clazz,NULL);
             return (-1);
          }
    Passing a Single String Array Element from C to Java

    non-jni code:
    Code:
          	Hjava_lang_String *javaVolName;
          unhand (volName)->body[0] = (HString *) javaVolName;
    jni code:
    Code:
          	jobjectArray volName;
          jstring javaVolName;
          javaVolName = (*env)->NewStringUTF(env, cVolNameStr);
          (*env)->SetObjectArrayElement(env,volName,0,javaVolName);

    Passing a Single Int Array Element from Java to C

    non-jni code:
    Code:
    cInt = unhand (volNumber)->body[0];
    jni code:
    Code:
     jint *arr;
          arr = (*env)->GetIntArrayElements(env, javaIntArr,0);
          cInt = (nuint8) arr[0];
          (*env)->ReleaseIntArrayElements(env, javaIntArr, arr, 0);
    Passing a Single Int Array Element from C to Java

    non-jni code:
    Code:
    unhand (volNumber)->body[0] = cInt;
    jni code:
    Code:
          	//...
          jint jIntTemp[1]; // SetIntArrayRegion expects a jintArray coming in
    
    
          jIntTemp[0] = searchSequence.searchDirNumber; 
          (*env)->SetIntArrayRegion(env, javaIntArr,0,1,jIntTemp);
       //...
    Newing up a Java object in C
    Code:
    cls = (*env)->FindClass(env, "com/novell/java/lang/IntegerBuffer");
             mid = (*env)->GetMethodID (env, cls, "init","(I)V");  (put init inbetween greater than, less than brackets) 
             object = (*env)->NewObject(env, cls, mid, (jint) cValue);

Similar Threads

  1. [Release] Minecraft 1.7.3 Full Portable with Java
    By Grooguz in forum MineCraft
    Replies: 1
    Last Post: 2017-04-06, 04:20 AM
  2. Replies: 12
    Last Post: 2013-04-20, 03:34 PM
  3. [Info] Java Application Analysis and Reverse Engineering
    By Bytesize in forum Game Research, Development
    Replies: 0
    Last Post: 2012-10-27, 08:32 PM
  4. [JAVA] Simple Java Socket Programming.
    By emoisback in forum Programming Tutorials
    Replies: 0
    Last Post: 2011-12-21, 08:52 AM
  5. [Release] Minecraft 1.8.1 Full Portable with Java
    By Grooguz in forum MineCraft
    Replies: 0
    Last Post: 2011-09-21, 07:15 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •