2015/04/10

[C#][Java] jni4net 基本使用 - Java呼叫C# 函式庫

首先, 到 jni4net 官方網站下載此套件. (我下載的是0.8.8版)
解壓縮後, 會得到三個資料夾:
  • bin: 內有 proxygen.exe 執行檔, 用來產生Java與C#程式間溝通用的Proxy.
  • lib: 包含將來執行時要用到的 .dll 與 .jar 檔.
  • samples: 顧名思義, 放的是 jni4net 的範例程式碼.
使用情境: 撰寫一個 C# 的函式庫, 讓 Java 程式可透過 jni4net 套件執行該 C# 函式庫.
Step 1: 利用 Visual Studio 建立一個名為 CSharpLib 的 C# 函式庫專案, 並簡單寫一個MainTable.cs 程式如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharpLib
{
  public class MainTable
  {
    public string GetHello(string name)
    {
      return string.Format("Hello, {0}", name);
    }

    public HelloModel GetHelloObject()
    {
      HelloModel m = new HelloModel();
      m.Hello = "hello";
      m.World = "world";
      return m;
    }
  }

  public class HelloModel
  {
    public string Hello { get; set; }
    public string World { get; set; }
  }
}
這程式簡單地說明如下:
  • class HelloModel: 為了後續驗證 java 程式對 C# Model 的使用.
  • GetHello(): 輸入一個字串參數, 用 string.Format() 包裝後回傳回去.
  • GetHelloObject(): 設定一個 HelloModel 物件的 Hello 跟 World 兩個屬性後, 再將此物件回傳.
Step 2: 建置此專案, 並得到一個 CSharpLib.dll
Step 3: 利用 proxygen.exe 產生 Proxy 相關函式庫.
  1. 開啟一個 cmd, 並輸入以下指令:
    "F:\Software\jni4net-0.8.8.0-bin\bin\proxygen.exe" "C:\test\CSharpLib.dll" -wd "C:\test2"
    
    參數1是 proxygen.exe 所在位置, 參數2是 CSharpLib.dll 所在位置, 最後的 -wd path 是指定輸出目錄.
  2. 執行完畢, 會在 C:\test2\內看到2個目錄, 2個檔案:
    clr\
    jvm\
    build.cmd
    CSharpLib.proxygen.xml
Step 4: 修改 build.cmd. (此程序不一定要修改, 主要是看個人的環境設定.)
  • 如果執行 build.cmd 發生 "'csc' 不是內部或外部命令、可執行的程式或批次檔。"的錯誤, 可到 C:\Program Files (x86)\MSBuild\12.0\Bin\ 或 C:\Program Files (x86)\MSBuild\12.0\Bin\amd64\ 找到 csc.exe, 將 build.cmd 內的 csc 改為"C:\Program Files (x86)\MSBuild\12.0\Bin\csc.exe".
  • 如果執行 proxygen.exe 後, 你有搬移一些檔案, 可在 build.cmd 內再確認一次檔案路徑是否都正確.
Step 5: 若 build.cmd 內的設定都正確, 執行該檔案後會在目錄內看到2個檔案: CSharpLib.j4n.dll 與 CSharpLib.j4n.jar
Step 6: 開發環境的設定(Eclipse):
  1. 建立一個名為 Jni4NetTest 的 Java Project, 並加入必要的 jar 參考 :
    在 Jni4NetTest 專案上按右鍵 –> [Build Path] –> [Configure Build Path…] –> 切到 [Libraries] 頁籤 –> 按下 [Add External JARs…] –> 將 jni4net.j-0.8.8.0.jar 與 CSharpLib.j4n.jar 加到專案的參考.
  2. 在專案內新增一個 lib 目錄, 並加入必要的 dll 檔案:
    將 CSharpLib.dll, CSharpLib.j4n.dll, jni4net.n-0.8.8.0.dll, jni4net.n.w64.v40-0.8.8.0.dll 加入該資料夾.
    至於 jni4net-0.8.8.0-bin\lib\ 裡的 jni4net.n.w32.v20-0.8.8.0.dll, jni4net.n.w32.v40-0.8.8.0.dll, jni4net.n.w64.v20-0.8.8.0.dll, jni4net.n.w64.v40-0.8.8.0.dll 四個檔案要選哪一個, 就要看當初建 C# 專案時, 是選什麼 Framework, 以及是在 32/64 位元環境執行.
  3. 新增一個測試用的 JniTest.java, 程式碼如下:
    package com.test;
    
    import java.io.File;
    import java.io.IOException;
    import net.sf.jni4net.Bridge;
    import csharplib.HelloModel;
    import csharplib.MainTable;
    
    public class JniTest {
    
      public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
          Bridge.setVerbose(true);
          Bridge.init(new File(
              "C:/Users/yilin/workspace/Jni4NetTest/lib/jni4net.n.w64.v40-0.8.8.0.dll"));
          Bridge.LoadAndRegisterAssemblyFrom(new File(
              "C:/Users/yilin/workspace/Jni4NetTest/lib/CSharpLib.j4n.dll"));
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
        MainTable m = new MainTable();
        HelloModel hm = m.GetHelloObject();
        System.out.println(m.GetHello("test"));
        System.out.println(hm.getHello());
        System.out.println(hm.getWorld());
      }
    }
    
    
  4. 完成後的專案結構圖如下:
    eclipse_project
注意事項:
  • 要注意 C# 函式庫轉換到 Java 後的 namespace 大小寫有改變。
  • 若執行時出現 "Exception in thread "main" java.lang.UnsatisfiedLinkError:" ,  表示程式未正確找到相關的 dll 檔, 解決方式是在 Bridge.init() 時指定一個完整路徑的 jni4net.n.w64.v40-0.8.8.0.dll 檔案.
  • 程式中, 有關 dll 的路徑指定, 用絕對路徑是較無問題的. 若擔心程式寫死路徑不好, 可以考慮放到其他設定檔或資料庫內.
  • 一開始使用時, 可先設定 Bridge.setVerbose(true); , 確認 clr.version 是 v2或v4, 以及 clr.arch 是 32/64 bit, 以利確認用哪一版正確的 jni4net.n.w32.v20-0.8.8.0.dll, jni4net.n.w32.v40-0.8.8.0.dll, jni4net.n.w64.v20-0.8.8.0.dll, jni4net.n.w64.v40-0.8.8.0.dll
參考網址:
Generating Proxies

沒有留言: