Thứ Tư, 2 tháng 3, 2011

Thao tác với DLL bằng Java

Môi trường triển khai



  • JDK 1.6_0.16

  • Eclipse

  • JUnit

  • VC++ Express 2010



Mục đích

File Calc.dll được tạo ra và bao gồm hai phương thức với đặc tả như sau



  • int add (int a, int b)

  • int substract (int a, int b)



Viết đoạn mã Java sử dụng sẵn hai phương thức đã được viết bằng VC++ và được dịch ra file dll.

Quy định chung

Một số tên gọi được giữ nguyên tiếng Anh thay vì viết tiếng Việt.

Thuật ngữ

Java = nền tảng Java & ngôn ngữ lập trình Java

C/C++ = ngôn ngữ lập trình C/C++

service(s) (trong tài liệu này) = các hàm viết bằng ngôn ngữ lập trình khác java

Intermediate platform = lớp trung gian giao tiếp giữa ứng dụng viết bằng Java & ứng dụng viết bằng các ngôn ngữ lập trình khác.

JNI (Java Native Interface) = lớp giao tiếp giúp JVM gọi các services được viết bằng ngôn ngữ lập trình khác.

JNA (Java Native Access) = truy cập vào các thư viện native mà không phải viết code JNI

Tổng quát

Bản thân ngôn ngữ Java không tự gọi được các hàm viết bằng các ngôn ngữ lập trình khác. Vì thế, trong Java Platform có cung cấp Java Native Interface (JNI) cho phép tích hợp chương trình viết bằng Java với những services được tạo ra trên nền tảng khác. JNI định nghĩa các chuẩn đặt tên và cách thức gọi hàm tích hợp trong JVM.

Kiến trúc



[caption id="" align="aligncenter" width="571" caption="JNI architecture"]JNI architecture[/caption]




Các bước gọi hàm trong file dll dịch từ C++



  • viết code java, bao gồm tên hàm & các tham số.

  • biên dịch file java = javac

  • tạo file header (*.h) = javah -jni

  • viết code C++ để thực thi, include file header tạo ra từ code java trên.

  • build mã nguồn C++ ra file dll

  • load file dll vào mã nguồn java và chạy.




[caption id="" align="aligncenter" width="556" caption="Calling JNI"]Calling JNI[/caption]

Trên là trường hợp lý tưởng khi có đủ cả mã nguồn & công cụ thực thi của các file dll. Tuy nhiên, trường hợp không thể có mã nguồn của dll mà chỉ có đặc tả kỹ thuật của các phương thức cần dùng thì công việc lại vất vả hơn chút. Đó là phải tự viết code C++ để đọc các

phương thức từ dll, tức là tự viết lớp intermediate platform ở trên để làm việc kết nối Java & dll (lập trình bằng C/C++)

Giải pháp khác

Có nhiều thư viện giải quyết việc giao tiếp giữa mã nguồn Java & dll (C/C++), JNA là một trong số đó với đặc điểm dễ dùng & miễn phí. Những thông tin cần thiết bao gồm



  • download jna.jar

  • import vào dự án (giả sử dùng eclipse)

  • load dll lên và sử dụng, cần có đặc tả kỹ thuật của các phương thức (tên, tham số, kiểu dữ liệu nên chính xác)



Làm bằng JNI đơn thuần

1. Viết file Calc.java


public native int add(int a, int b);

public static void main(String[] args) {

Calculator cal = new Calculator();

int sum = cal.add(1,2);

}

2. Biên dịch file Calc.java


javac Calc.java

3. Tạo ra file header (*.h) để sử dụng trong mã nguồn C++


javah -jni Calc

File Calc.h thu được có nội dung như dưới


#include <jni.h>

/* Header for class Calculator */

#ifndef _Included_Calculator

#define _Included_Calculator

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: Calculator

* Method: add

* Signature: (II)I

*/

JNIEXPORT jint JNICALL Java_Calculator_add

(JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus

} #

endif

#endif

Trong đó



  • JNIEXPORT jint JNICALL là quy tắc viết giao tiếp của JNI

  • jint là kiểu native của int



4. Viết mã nguồn C++



  • #include file Calc.h header như trên

  • viết mã nguồn chính




#include <jni.h>

#include "Calc.h"

JNIEXPORT jint JNICALL

Java_Calc_add(JNIEnv *env, jobject obj, jint a, jint b)

{

return a + b;

}

5. Dịch mã nguồn C++ thành file dll. Trường hợp đã có sẵn file *.dll, từ bước (1) - (4) thì viết các phương thức theo như đặc tả kỹ thuật của file *.dll nhận được. Tại bước (4), viết các hàm C++ để gọi đến hàm C++ trong file *.dll đó.

6. Sử dụng file dll vừa dịch trong mã nguồn Java.

Cách này đòi hỏi người làm vừa phải làm với Java, vừa phải làm với C/C++. Nếu các lập trình viên Java ngại làm việc với C/C++ thì thư viện Java Native Access (JNA) là một trong số những lựa chọn tốt để sử dụng. Lợi ích của nó là có thể tránh cho lập trình viên can thiệp hoặc viết mới mã nguồn C/C++, tức là bỏ qua bước (3), (4) ở trên.

Sử dụng JNA

1. Vào website https://jna.dev.java.net/ và download thư viện cần thiết



  • jna.jar

  • platform.jar (không bắt buộc)



2. Import thư viện jna.jar và viết mã nguồn java


○ file Calc.java

package Calculator;

import com.sun.jna.*;

public interface Calc extends Library {

int add(int a, int b);

}

○ file Cal.java

package Calculator;

import com.sun.jna.*;

public class Cal {

static Calc init() {

Calc c = (Calc) Native.loadLibrary("Path/to/Calc",

Calc.class);

return c;

} public static void main (

String [] args) {

System.out.println(add(1, 2));

} public static int add(int a, int b) {

return init().add(a, b);

} public static int substract(int a, int b) {

return init().substract(a, b);

}

}

Có thể gộp 2 files trên thành 1, tuy nhiên, việc viết interface mô tả các phương thức gọi các hàm native làm cho code dễ quản lý hơn.

Vậy là chạy roài.

Hai lỗi thường gặp



  • java.lang.UnsatisfiedLinkError: Error looking up function '<function’s name>': The specified procedure could not be found. -> kiểm tra lại chính xác tên hàm, kiểu dữ liệu (native) & tham số.

  • java.lang.UnsatisfiedLinkError: Unable to load library 'C:\Users\nguyen.duc.hoang\Documents\Visual Studio 2010\Projects\Calc\Debug\<library’s name>': The specified module could not be found -> kiểm tra lại tên file dll, đường dẫn đến file, phiên bản build & nền tảng lập trình của file đó.



Hạn chế của JNA

Tốc độ chậm hơn JNI native khoảng 10 lần (nghe nói thế), tuy nhiên vẫn có những cách để tăng thêm hiệu suất làm việc (chưa thử). Việc mapping giữa library & functions giữa JNA và native code cũng gặp vấn đề về



  • tính chính xác

  • các kiểu dữ liệu.



Những yêu cầu của file *.dll dùng được



  • có mô tả chính xác tên hàm, giá trị trả về & tham số truyền vào.

  • có mô tả chi tiết các kiểu dữ liệu, hằng số

  • ngoài ra, file *.dll nên được viết (nếu = C/C++) đúng chuẩn xuất ra dll chứ không phải dll gắn trực tiếp & cố định vào một ứng dụng cụ thể (vì lý do ràng buộc giữ các thư viện - nếu có).

  • có thể xem được tên hàm của file *.dll bằng các chương trình phân tích dll đơn giản.



Tham khảo thêm



  • website chính của dự án JNA https://jna.dev.java.net/

  • Sheng Liang The Java™ Native Interface (Programmer’s Guide and Specification)


1 nhận xét:

  1. hsDDJ1 sacesgecblbz, [url=http://xzgddlqcclab.com/]xzgddlqcclab[/url], [link=http://ferpgsxusdtb.com/]ferpgsxusdtb[/link], http://hgpxkfpfcgbt.com/

    Trả lờiXóa