利用jna呼叫使用C#的dll檔案
目前所做java專案中有部分模組需要使用客戶提供的dll動態庫檔案中封裝的演算法,客戶提供了一個dll檔案以及C#語言編寫的可執行檔案例項,演算法具體程式碼未提供。之前只涉及過利用jna呼叫c++所生成的dll檔案,最終的目的則是需要java呼叫C#生成的dll檔案。
本人涉及dll的封裝操作不是很久,暫時未能找到java利用jna呼叫C#生成的dll的更有效方法,於是採用一種變通的方法。
這種方法的思路是:c++專案設定為clr公共執行時,可以通過引用的方法呼叫C#相應方法,java可以通過jna呼叫c++生成的dll,所以首先需要將C#的dll封裝成c++的dll,再通過jna呼叫封裝好的c++的dll檔案。
工具:vs2010
首先,生成C#的dll檔案。
客戶給的dll檔案是直接由C#生成的,如果熟悉這dll檔案的內部結構則可直接略過此步驟。因為客戶給的dll名稱空間不夠明確,並且其中有兩個相似的類,而每個類下又有功能相同且名稱相同的幾個方法,為了能夠明確呼叫給定的C#的dll動態庫檔案中的方法,同時為了c++呼叫方便,這裡是將客戶給的dll檔案利用C#重新封裝了一層。步驟如下。
1) 開啟vs2010,新建專案,選擇C#語言下的“類庫”,填寫專案名稱。
2) 在生成專案上右擊設定專案屬性,點選“程式集資訊”,勾選“使程式集COM可見”,點選確定。
3) 設定“生成”屬性,勾選“為COM互操作註冊”,儲存設定。
4) 在專案的“引用”中新增客戶提供的dll檔案。
5) 新增必須的C#程式碼。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using QiJuSiChu.SpeechLib;//新增引用的dll名稱 namespace PackLib { public class Class1 { acelp_cn_8k lpc8k; //引用的dll中的演算法的例項 public void dealVoiceToPcm(string voicePath, int curgainshift) { lpc8k = new acelp_cn_8k(); lpc8k.Initialize();//初始化 lpc8k.SetGainShift(curgainshift);//設定增益 lpc8k.decodeframe(voicePath);//解碼 } } }
6) 點選生成專案,成功。
其次,使用c++封裝dll檔案。
為了能夠使用jna呼叫C#生成的dll檔案,必須使用c++進行進行一次封裝,這一步驟至關重要。
1) 新建c++專案。
2) 在專案名稱上右擊,設定專案屬性。
3) 在專案名稱上右擊,選擇“引用”,引入之前生成的C#的dll。
4) 新增cpp檔案,書寫必須的c++程式碼。程式碼如下。
#ifdef MYLIBAPI
#else
#define MYLIBAPI extern "C" __declspec(dllimport)
#endif
MYLIBAPI void DealVoiceToPcm(char *voicePath,int curgainshift); //新增函式宣告,此函式為生成的C++的dll的外部公開函式
using namespace System;
using namespace PackLib;//新增引入的C#的dll名稱
void DealVoiceToPcm(char *voicePath,int curgainshift)
{
String ^ paraStr = gcnew String(voicePath);//需要將char *轉換為託管的String型別,否則失敗
Class1 ^method = gcnew Class1();//例項化C#的類
method->dealVoiceToPcm(paraStr, curgainshift);//呼叫C#的dll中的方法
}
5) 生成專案,成功。
最後,需要使用jna引用新生成的C++的dll檔案,這與一般的jna呼叫dll動態庫檔案的方法一樣,不再贅述。
注:這裡如果將所有的C#及c++的dll檔案放到java專案的目錄下,會出現錯誤,原因是java雖然可以找到c++的dll檔案,但是找不到C#的dll檔案,需要將C#的dll檔案放到執行機器jdk安裝目錄下的bin資料夾下。問題解決。
再次重複一句這些成的dll檔案應當與執行機器上安裝的jdk的版本一致(x86或者x64),否則會出現調用出錯。