官方用法是 Java Native Interface(JNI),但是會牽扯到非 Java 的程式,還是先跳過好了。
找到一些 3rd-party library 可以用,包括 Jawin、Jacob 與 JNative,試過之後,發現 JNative 比較簡單用。
先去下載 JNative_1.4RC3_bin,解開後裡面只有一個 JNative.jar 檔,不像其他網路文章說得有二到三個檔案,包括一個 jar 檔、一個 Windows 用的 dll 檔和一個 Linux 用的 so 檔,這類 3rd-party library 運作邏輯大概是這樣呼叫流程:
Your Java Code -> JNative.jar -> JNative.dll -> Your DLL
那新版的 JNative.dll 在哪?解開 JNative.jar 裡面有個 lib-bin 就可以看到 dll 和 so。
先用網路上的範例試試看:
public class SystemTime extends AbstractBasicData這是呼叫 kernel32.dll 裡的 GetSystemTime,這個 dll 檔是在 Windows/system32 裡。{ public short wYear; public short wMonth; public short wDayOfWeek; public short wDay; public short wHour; public short wMinute; public short wSecond; public short wMilliseconds; /** * 分配内存,并返回指针 */ public Pointer createPointer() throws NativeException { pointer = new Pointer(MemoryBlockFactory.createMemoryBlock(getSizeOf())); return pointer; } /** * 内存大小 */ public int getSizeOf() { return 8 * 2; } /** * 获取通过内存指针解析出结果 */ public SystemTime getValueFromPointer() throws NativeException { wYear = getNextShort(); wMonth = getNextShort(); wDayOfWeek = getNextShort(); wDay = getNextShort(); wHour = getNextShort(); wMinute = getNextShort(); wSecond = getNextShort(); wMilliseconds = getNextShort(); return this; } public SystemTime() throws NativeException { super(null); createPointer(); } public String toString() { return wYear + "/" + wMonth + "/" + wDay + " at + " + wHour + ":" + wMinute + ":" + wSecond + ":" + wMilliseconds; } public static SystemTime GetSystemTime() throws NativeException, IllegalAccessException { // 创建对象 JNative nGetSystemTime = new JNative("Kernel32.dll", "GetSystemTime"); SystemTime systemTime = new SystemTime(); // 设置参数 nGetSystemTime.setParameter(0, systemTime.getPointer()); nGetSystemTime.invoke(); // 解析结构指针内容 return systemTime.getValueFromPointer(); } public static void main(String[] args) throws NativeException, IllegalAccessException { System.err.println(GetSystemTime()); } }
耶?執行失敗!
Exception in thread "main" java.lang.IllegalStateException: JNative library not loaded, sorry ! at org.xvolks.jnative.JNative.(JNative.java:502) at org.xvolks.jnative.JNative. (JNative.java:427) at idv.neil.cttn.ComBean.main(ComBean.java:47)
Google 了半天,發現 dll 有分 32 位元和64 位元,這個 JNative 應該是 32 位元的,傷腦筋,我從 OS、JDK 到 Eclipse 都是 64 位元的,JDK 和 Eclipse 要改還有可能,若要改 OS 那不如換別個 library 算了。
後來相當幸運的,只將 Eclipse 用的 JDK 改成 32 位元就執行成功了,OS 和 Eclipse 都還是 64 位元的。
再來試試自己的 dll 檔。
public class MyDLL { public static void main(String[] args) throws NativeException, IllegalAccessException { JNative jn = new JNative("HS380A.dll", "OpenPort"); jn.invoke(); System.out.println(jn.getRetVal()); } }因為沒有參數傳遞,就先不用 JNative 的 AbstractBasicData,一執行又出錯了。
Exception in thread "main" org.xvolks.jnative.exceptions.NativeException: DLL HS380A.dll not found at org.xvolks.jnative.JNative.nLoadLibrary(Native Method) at org.xvolks.jnative.JNative.loadLibrary(JNative.java:534) at org.xvolks.jnative.JNative.<init>(JNative.java:510) at org.xvolks.jnative.JNative.<init>(JNative.java:427) at idv.neil.cttn.MyDLL.main(MyDLL.java:16)找不到 DLL 檔?依樣畫葫蘆,將我的 dll 丟到 windows/system32 裡,噹,居然不行!
只好再去請教 Google,試過 LD_LIBRART_PATH 和 -Djava.library.path 都無效,去看 JNative 的 Source code 發現:
private native int nLoadLibrary(String dllName, String funcPointer) throws NativeException;喵的咧,居然將載入 dll 段寫在 dll裡,好樣的。
最後發現,只要將 dll 放在 Eclipse project 裡就可以了!
---
沒有留言:
張貼留言