Java

JNI(Java Native Interface) Part II

_침묵_ 2006. 3. 24. 08:44

JNI(Java Native Interface) Part II

 

Part I 에서 JAVA에서 JNI를 사용 C/C++ 로 만든 모듈을 호출하고 실행시켜 보았다.

그런데, 실행만 시킬 수 있는가? 자바를 만든 개발자들이 바보가 아닌이상 그렇게만 해 놓았겠는가

이번엔 씨로 만든 프로그램에서 리턴값을 받아와보자...ㅇㅎㅎㅎㅎ

 

1. 전달인자와 리턴값

JAVA

 C

BYTE

 boolean  jboolean  1
 byte  jbyte  1
 char  char  2
 short  jshort  2
 int  jint  4
 long  jlong  8
 float  jfloat  4
 double  jdouble  8

C/C++와 자바 사이에 숫자를 전달할때, 서로간에 데이터형을 이해하는 것이 중요하다.

예를 들어 C의 int는 플렛폼에 따라 각기 16비트 또는 32비트가 될수 있지만, 자바에서 int는 항상

32비트 이다.

이런 문제점을 해결하기 위해 자바 인터페이스는 위표와 같은 jint 같은 타입을 정의한다.

 

2. 문자열 전달인자

자바에서 문자열은 16비트 유니코드 문자들의 연속이며, C의 문자열은 8비트 문자들의 null로

끝나는 문자열이다. 따라서 두 문자열의 구조는 상당히 다르다.

자바 고유 인터페이스는 두개의 함수 셋을 가지고 있는데, 하나는 자바 문자열을 UTF(Unicode

Text Format)으로 변경하고 다른 하나는 자바 문자열을 유니코드 문자들의 배열로 변환한다.

즉, jchar 배열로 변환한다.

String 전달인자를 가진 고유 메서드는 실제 jstring형의 구조체에 대한 포인터를 받는데, String형의

값을 반환하는 자바 메서드는 반드시 jstring구조체에 대한 포인터를 반환해야 한다. 예를 들면

NewStringUTF 함수는 UTF 인코딩된 문자들을 포함하고 있는 char배열로부터 jstring 객체를

만든다.

 

3. 문자열 전달인자 예제

Part I 의 프로그램을 수정하여 문자열을 리턴받는 프로그램으로 변경해본다.

JNI를 사용하기 위한 자바클레스를 작성한다.

----------------------------------------------------------------------------------------

* ExecuteJNI.java

class ExecuteJNI {
    public static void main(String[] args)
    {
       System.out.println(new JNILoader().greet()); 
    }
}

 

* JNILoader.java

class JNILoader {
    public native Stringgreet();
 
    static {
        System.loadLibrary("HardInfo");
    }
}

----------------------------------------------------------------------------------------

 

javah를 이용해서 네이티브 메서드를 위한 C++해더파일을 생성한다.

> javah -jni JNILoader

----------------------------------------------------------------------------------------

* 생성된 JNILoader.h

/* DO NOT EDIT THIS FILE - it is machine generated */

#include "jni.h"
/* Header for class JNILoader */

#ifndef _Included_JNILoader
#define _Included_JNILoader
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JNILoader
 * Method:    greet
 * Signature: ()V
 */
JNIEXPORTjstringJNICALL Java_JNILoader_greet
     (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

----------------------------------------------------------------------------------------

 

JNILoader.java의 void greet() 메서드를 구현할 C++ 네이티브 메서드를 구현한다. C/C++ 컴파일

러는 UNIX에서 cc나 gcc, Win32에서 Turbo C나 Visual C++등을 쓸 수 있다. 참고로 여기서

구현한 것은 Visual C++로 구현된것이다.

----------------------------------------------------------------------------------------

* HardInfo.cpp

#include "stdafx.h"
#include "JNILoader.h"

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
    return TRUE;
}

JNIEXPORTjstringJNICALL Java_JNILoader_greet(JNIEnv *env, jobject obj) { 
 
    char cSerialNumber[16];
    DWORD dwSerialNumber;
   jstring jstr;

    GetVolumeInformation("C:\\", NULL, 0, &dwSerialNumber, NULL, NULL, NULL, 0); 
    sprintf(cSerialNumber, "%8X", dwSerialNumber);
   jstr = env ->NewStringUTF(cSerialNumber);

 

    returnjstr;

}

----------------------------------------------------------------------------------------

 


사용자 삽입 이미지
 
자바 클레스에서 System.out 으로 찍은 내용이 뜬다. 무사히 시스템의 볼륨 시리얼을 읽어왔음을
알수가 있다. 보통 이런 부분은 프로그램 라이센스에 중요한 역할을 할 수도 있다. 예를 들어
자신이 자바로 만든 어떠한 상용 프로그램에 대해서 라이센스를 걸고 싶을때 컴퓨터 한대에만
권한을 주려할때 초기 라이센스를 설치한 컴퓨터의 하드디스크 시리얼을 읽어와서 비교...시리얼이
다를 경우 잘못된 라이센스임을 확인할 수가 있을것이다.
뭐...이런경우 개인 PC라면 하드디스크 교환이라던지의 상당히 짜증나는경우가 생길수 있음을
명심하길 바란다....^^
 
JNI를 이용해 객체를 전달한다던지 혹은, C에서 자바의 메서드를 호출하는 방법도 있다고한다.
시간이 허락한다면...Part III 에서 한번더 짚고 넘어가고 싶으나...없으면 걍 넘어간다...ㅡㅡ;;
 
 
PS. 오랜만에 비가 주적주적 내리는 날씨네요. 약간은 우울하고...또 한편으론 시원한...모두들
      좋은하루 되시구요. 행복한 하루되길....
 
by kange