java使用jna調(diào)用c#中dll的方法詳解
前言
JNA(Java Native Access )提供一組Java工具類用于在運(yùn)行期動態(tài)訪問系統(tǒng)本地庫(native library:如Window的dll)而不需要編寫任何Native/JNI代碼。開發(fā)人員只要在一個java接口中描述目標(biāo)native library的函數(shù)與結(jié)構(gòu),JNA將自動實(shí)現(xiàn)Java接口到native function的映射。
優(yōu)點(diǎn)
JNA可以讓你像調(diào)用一般java方法一樣直接調(diào)用本地方法。就和直接執(zhí)行本地方法差不多,而且調(diào)用本地方法還不用額外的其他處理或者配置什么的,也不需要多余的引用或者編碼,使用很方便。 JNA最大的好處是避免了重復(fù)造輪子的浪費(fèi)時間的行為.
用過JNI的大神都知道,JNI是一種很變態(tài)的設(shè)計,JNI需要導(dǎo)入專門為Java生成的頭文件,是一種侵入式的設(shè)計,這樣被強(qiáng)行改造的源碼編譯的dll將不能被C#調(diào)用
JNA描述
JNA類庫使用一個很小的本地類庫sub 動態(tài)的調(diào)用本地代碼。程序員只需要使用一個特定的java接口描述一下將要調(diào)用的本地代碼的方法的結(jié)構(gòu)和一些基本屬性。這樣就省了為了適配多個平臺而大量的配置和編譯代碼。因為調(diào)用的都是JNA提供的公用jar 包中的接口。
一、需求闡述:
如果我們的項目利用c#開發(fā),到了開發(fā)后期需要和java組進(jìn)行合作,其中有一部分業(yè)務(wù)邏輯利用c#已經(jīng)code completed,那么我們可能會考慮用java來調(diào)用現(xiàn)成的c#dll實(shí)現(xiàn)需求。前幾天工作上正好遇到這樣一個問題,于是記下開發(fā)過程。
當(dāng)然這只是個假設(shè),具體情況具體分析,個人認(rèn)為重構(gòu)代碼才是王道……
二、原理說明:
其實(shí)具體原理我也沒弄太明白,我就根據(jù)自己的理解來說吧,拋磚引玉。
因為c#代碼是托管到.net平臺上的,所以java不能直接調(diào)用c#代碼,于是引入C++中間件,c++項目可以設(shè)置項目為clr公共運(yùn)行時,從而通過引用的方式調(diào)用c#相應(yīng)方法。而jna是可以直接調(diào)用c++生成的dll的,于是大致流程就走通了。c++調(diào)用寫好的c#dll,java再調(diào)用c++生成的dll中間件,大致流程就是這樣了,不過其中有很多坑,下面我會細(xì)說。
三、運(yùn)行平臺:
系統(tǒng):Windows 10 x64
開發(fā)工具:Visual Studio 2015/2017(我筆記本和公司電腦安裝不同版本,我都有實(shí)現(xiàn)過) MyEclipse2014
SDK:jdk-x86、jdk-x64 (dll分為x86和x64平臺,和jdk的版本要對應(yīng),同一臺電腦裝兩個版本的jdk比較煩,我采用的是系統(tǒng)配置jdk32位調(diào)試32位dll,然后myeclipse自帶64位jdk調(diào)試64位dll)
四、準(zhǔn)備工作:
1、首先準(zhǔn)備上述運(yùn)行平臺,建議選擇和系統(tǒng)位數(shù)一致的jdk(安裝vs、myeclipse或eclipse或sts);
2、下載jna.jar :JNA下載 (下載jna-4.4.0.jar 和 jna-platform-4.4.0),也可以 本地下載
五、開始CODE
5.1 生成c#DLL
5.1.1 以管理員方式啟動vs(項目涉及到注冊com組件,必須以管理員啟動才能完成),新建c#項目

5.1.2 設(shè)置c#項目
首先,右鍵剛剛新建的Invoke項目,點(diǎn)擊屬性。

繼續(xù)設(shè)置項目屬性。

記得保存。
然后新建需要被調(diào)用的CSharp類代碼。這里我們新建一些簡單的方法,為了演示效果我們分別對int、string、bool進(jìn)行操作。如圖:

然后右鍵項目,點(diǎn)擊生成。

第一步,完成,干得漂亮。
5.2 生成c++中間件
5.2.1 新建c++項目并設(shè)置屬性



項目新建成功,右鍵項目,選擇屬性。


5.2.2 書寫c++代碼
添加cpp文件


編輯cpp文件
好了,c++和c#全部工作完成,右鍵生成。

復(fù)制下dll生成文件全名,一會兒java里面用。
六、編寫java代碼
6.1 新建java project ,注意選擇和dll平臺一致的jdk。然后將之前下載的兩個jna的jar加載到項目里面,如圖:

6.2 開始寫java 代碼
然后我們運(yùn)行:

哦豁,報錯了【無效的內(nèi)存訪問】,因為java找到了c++dll,但是沒找到c#的dll,其中c++dll我們寫的全路徑名,可以直接找到,那么c#的dll怎么找呢。答案是將c#的dll復(fù)制到j(luò)dk的bin目錄下,jvm就能找到了。
如圖我們將Invoke.dll復(fù)制到j(luò)dk的bin目錄下:

然后再運(yùn)行:

nice!對于常用類型中的int、string、boolean都可以順利傳遞了,事實(shí)上其他類型的也可以實(shí)現(xiàn),只要遵循不同語言之間的類型對應(yīng)關(guān)系就可以了,具體的類型關(guān)系可以百度。
七、注意事項
7.1 java報錯:Exception in thread "main" java.lang.Error: Invalid memory access
可能原因:
1、c#dll沒有復(fù)制到j(luò)dk的bin目錄;
2、java和c++之間數(shù)據(jù)類型不對應(yīng);
7.1.2 java報錯:Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'D:\vs workplace\X86InvokeTest\Release\X86CPPDlls': Native library (win32-x86/D:\vs workplace\X86InvokeTest\Release\X86CPPDlls.dll) not found in resource path ([file:/G:/My%20Eclipse%20workplace/InvokeCSharpX86Test/bin/, file:/G:/My%20Eclipse%20workplace/InvokeCSharpX86Test/Lib/jna-4.4.0.jar, file:/G:/My%20Eclipse%20workplace/InvokeCSharpX86Test/Lib/jna-platform-4.4.0.jar])
可能原因:
1、c++dll路徑不正確,建議做test時用絕對路徑,這樣你在c++項目編譯過后不用拷貝便可以在java程序里面直接調(diào)用;
2、jdk的平臺和c++項目的平臺不匹配,jdk是32位那么c++dll一定也是32位的,64位也同樣;
7.1.3 windows64位下編譯的32位dll測試失敗,暫時不清楚是不是64位系統(tǒng)的原因,由于我電腦虛擬機(jī)沒有裝上,就沒有去32位系統(tǒng)上測試了。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
SpringBoot整合Redis的哨兵模式的實(shí)現(xiàn)
Redis提供了哨兵模式來處理主從切換和故障轉(zhuǎn)移,本文主要介紹了SpringBoot整合Redis的哨兵模式的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08
spring security中的csrf防御原理(跨域請求偽造)
這篇文章主要介紹了spring security中的csrf防御機(jī)制原理解析(跨域請求偽造),本文通過實(shí)例代碼詳解的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12
關(guān)于springboot的接口返回值統(tǒng)一標(biāo)準(zhǔn)格式
這篇文章主要介紹了關(guān)于springboot的接口返回值統(tǒng)一標(biāo)準(zhǔn)格式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05
Java Web檢查用戶登錄狀態(tài)(防止用戶訪問到非法頁面)
一般javaweb網(wǎng)站都有用戶登錄,而有一些操作必須用戶登錄才能進(jìn)行,本文主要介紹了Java Web檢查用戶登錄狀態(tài),具有一定的參考價值,感興趣的可以了解一下2023-09-09
Java實(shí)現(xiàn)FTP文件與文件夾的上傳和下載
本文主要分享了Java實(shí)現(xiàn)文件上傳和下載的具體實(shí)例,分為單個文件的上傳與下載和整個文件夾的上傳與下載。具有很好的參考價值,需要的朋友一起來看下吧2016-12-12
SpringBoot yaml語法與JRS303校驗超詳細(xì)講解
YAML 是 “YAML Ain’t Markup Language”(YAML 不是一種標(biāo)記語言)的遞歸縮寫。在開發(fā)的這種語言時,YAML 的意思其實(shí)是:“Yet Another Markup Language”(仍是一種標(biāo)記語言),本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10

