IT_Programming/Java

[펌] JNI 를 사용해서 C 로 작성된 dll을 실행하기

JJun ™ 2008. 11. 18. 00:23

○ JNI ( Java Nayive Interface) 기술

JNI는 자바 언어로 작성된 프로그램에서 C/C++ 언어로 작성된 함수를 호출할 수 있도록 해준다.

JNI는 주로 하드웨어를 제어하기 위해서, 혹은 기존 C/C++ 라이브러리를 이용하기 위해서

사용될 수 있다. 그러나, JNI를 사용하면 플랫폼간에 호환성이 떨어지고, Applet에서 사용할 수 없다는

단점이 있다. 이러한 단점에도 불구하고 자바언어의 장점을 가지고 하드웨어에 접근하기 위한 방법으로

JNI는 매우 중요한 위치를 차지한다.

 

    ○ JNI의 기능

       - creat, inspect,update java object

       - java method 호출

       - catch & throw exception

      

     ○ native method interface

       - jdk 1.2.2

       - Netscape's java runtime interface

       - MS's Raw Native Interface

       - Java/Com Interface

  

      ○ JNI Program의 작성 단계

            ① JAVA 클래스를 작성한다.

 

            ② JAVA 클래스를 컴파일 한다. ( Javac를 이용 )

 

            ③ C언어의 헤더 파일을 생성한다.

                  Javah를 이용해서 Native Method를 위한 C언어 헤더 파일을 생성한다.

                  Javah를 사용할때는 -jni옵션을 이용하고, Argument로 Native Method를 갖는

                  JAVA 클래스 이름을 기술한다.

 

            ④ Native Method를 작성한다.

                  실제적인 작업을 수행할 Native Method를 C 언어로 구현하는 것이다.

                  Native Method를 구현하기 위해서는 jni.h 헤더 파일과 Javah로 생성된 헤더 파일을

                  Include해야 한다.

 

            ⑤ 라이브러리를 만든다.

                  Visual C++같은 Tool을 이용해 동적 라이브러리(*.dll) 파일을 만든다.

 

            ⑥ 프로그램을 실행시킨다.

                 라이브러리를 작성하면 JAVA CLASS를 실행시킬 수 있다. 라이브러리 Path가 설정되지

                 않은 경우에 에러가 발생할 수 있다. Path가 설정되어 있지 않았다면 UNIX의 C-Shell에서

                 는 setenv 명령어를 이용해서 Path를 설정한다. Window 에서는 Autoexec.bat파일에

                 설정하거나, DOS창에서 환경변수를 맞추어줄 수 있다.

 


더보기

 

자바에서 JNI 를 쓰면 C 코드로 작성된 라이브러리를 불러 쓸 수 있다.

아래 테스트 환경은 vc++ 6.0 에서 했습니다. 
JNI 형식에만 맞는다면 dll 을 로드 할수 있습니다.

[예는 두수를 곱하는것과 메세지를 출력하는 부분은 C 로 작성된 dll 라이브러리를 사용하는 예제]

jni 가 사용된 메소드는 native 한정자를 적음으로써 가능합니다. 

--------------------------------NativeTest2.java-----------------------------------

public class NativeTest2

{
 static

{
  System.loadLibrary("DisplayMessage2");
 }
 public static void main(String []args)

{
  System.out.println(calcul(3,4,true));
 } 
 

public static native void printMessage(String str); 
 

public static native int calcul ( int a, int b, boolean bool );



printMessage 와 calcul 메소드는 다른 언어로 쓰여질 것이므로 native 라고 붙입니다.
그러므로 정의만 하고 내용은 없다.

 
이 파일을 우선 자바로 컴파일 한 후..
java -h NativeTest2 를 수행 시키면 C 에서 사용되는 헤더파일( NativeTest2.h ) 가 생깁니다.

헤더 파일의 내용은 다음과 같게 됩니다. 
 

-----------------------NativeTest2.h(자동으로 생성되는 파일임)----------------------

/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class NativeTest2 */

#ifndef _Included_NativeTest2
#define _Included_NativeTest2
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:    NativeTest2
 * Method:    printMessage
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_NativeTest2_printMessage
  (JNIEnv *, jclass, jstring);

/*
 * Class:    NativeTest2
 * Method:    calcul
 * Signature: (IIZ)I
 */
JNIEXPORT jint JNICALL Java_NativeTest2_calcul__IIZ
  (JNIEnv *, jclass, jint, jint, jboolean);

/*
 * Class:    NativeTest2
 * Method:    calcul
 * Signature: ([I)I
 */

#ifdef __cplusplus
}
#endif
#endif

위와 같은 C 헤더 파일이 생깁니다.

여기서 주의 사항을 보자면 C 에서 include 하는것을 보면 jni.h 를 합니다.
그러나 vc++ 6.0 에는 해당 라이브 러리가 없는데, 이것은 자바에서 포함합니다.
Option → Directory 가셔서,  자바홈include\win32 디렉토리를 포함시켜야 합니다
예를 들면 c:\jdk1.4\include\win32  를 추가 시킵니다.

그리고 아래와 같이 C 코드를 아래와 같이 작성하는 됩니다. 

위에서 라이브 러리는 DisplayMessage2 를 호출하는것으로 되어 있기 때문에,
DisplayMessage2.c 로 만들어야 합니다. 생성 결과는 dll 이어야 하므로 Project 는 dll 을 선택해야 합니다.

------------------------------Displaymessage2.c---------------------------------

#include
#include "NativeTest2.h"

JNIEXPORT void JNICALL Java_NativeTest2_printMessage
 (JNIEnv *env, jclass cl , jstring text)

{
 
 const char *asciiString = (*env)->GetStringUTFChars(env,text, 0);
 printf("Hello. %s",asciiString);
 (*env)->ReleaseStringUTFChars(env,text,asciiString);
}

JNIEXPORT jint JNICALL Java_NativeTest2_calcul
(JNIEnv *env, jclass cl, jint a, jint b, jboolean c)

{
      jint d;
      if ( c == JNI_TRUE )

      {
           d = a * b;
      }

      else

      {
          d = a / b;
      }
      return d;


jni 를 사용하므로 자체 자료형을 사용한다. jint 는 물론 일반 C 에서 int 와 같다.
int d 라고 선언했는데 jint d 라고 선언하더라도 관계 없다.

const char *asciiString = (*env)->GetStringUTFChars(env,text, 0); 부분은 UTF-8 형으로 변환시키는 작업

해당 파일을 빌드 시키면 dll 파일이 생성되게 된다.
이 dll 을 사용하려면 해당 파일을 windows\system32 폴더에 넣은 후, java NativeTest2 하면 수행이 된다. 


public class NativeTest2

{
 static

{
  System.loadLibrary("DisplayMessage2");
 }
 public static void main(String []args)

{
  System.out.println(calcul(3,4,true));
 }
 public static native void printMessage(String str);
 public static native int calcul ( int a, int b, boolean bool );



이걸 다시 보자면 loadLibrary 에서 해당 dll 을 로드 하게 됩니다. 

자바가 시스템 쪽에 컨트롤이 안되는데 jni 를 사용하면 이것이 가능하게 된다...
자바의 특성인 포터빌러티가 사라지게 되지만 괜찮다고 봅니다. 
 

많이 응용이 되겠죠... 자바를 이용한 윈도우 서비스 제어도 되겠고....
파일의 속성을 변경한다던지 같은 기능이 되겠죠...