隨筆 - 63  文章 - 0  trackbacks - 0
          <2009年5月>
          262728293012
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          Java代碼
          1. 簡單介紹及應用如下:    
          2.   一、JAVA中所需要做的工作    
          3.   在JAVA程序中,首先需要在類中聲明所調用的庫名稱,如下:    
          4.   
          5. static {    
          6. System.loadLibrary(“goodluck”);    
          7. }   
          8.   
          9.   
          10.   在這里,庫的擴展名字可以不用寫出來,究竟是DLL還是SO,由系統自己判斷。    
          11.   
          12.   還需對將要調用的方法做本地聲明,關鍵字為native。且只需要聲明,而不需要具體實現。如下:    
          13.   
          14. public native static void set(int i);    
          15. public native static int get();   
          16.   
          17.   
          18.   然后編譯該JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就會生成C/C++的頭文件。    
          19.   
          20.   例如程序testdll.java,內容為:    
          21.   
          22. public class testdll    
          23. {    
          24. static    
          25. {    
          26. System.loadLibrary("goodluck");    
          27. }    
          28. public native static int get();    
          29. public native static void set(int i);    
          30. public static void main(String[] args)    
          31. {    
          32. testdll test = new testdll();    
          33. test.set(10);    
          34. System.out.println(test.get());    
          35. }    
          36. }   
          37.   
          38.   
          39.   用javac testdll.java編譯它,會生成testdll.class。    
          40.   再用javah testdll,則會在當前目錄下生成testdll.h文件,這個文件需要被C/C++程序調用來生成所需的庫文件。    
          41.   
          42.   二、C/C++中所需要做的工作    
          43.   對于已生成的.h頭文件,C/C++所需要做的,就是把它的各個方法具體的實現。然后編譯連接成庫文件即可。再把庫文件拷貝到JAVA程序的路徑下面,就可以用JAVA調用C/C++所實現的功能了。    
          44.   接上例子。我們先看一下testdll.h文件的內容:    
          45.   
          46. /* DO NOT EDIT THIS FILE - it is machine generated */    
          47. #include    
          48. /* Header for class testdll */    
          49. #ifndef _Included_testdll    
          50. #define _Included_testdll    
          51. #ifdef __cplusplus    
          52. extern "C" {    
          53. #endif    
          54. /*   
          55. * Class: testdll   
          56. * Method: get   
          57. * Signature: ()I   
          58. */    
          59. JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);    
          60. /*   
          61. * Class: testdll   
          62. * Method: set   
          63. * Signature: (I)V   
          64. */    
          65. JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);    
          66. #ifdef __cplusplus    
          67. }    
          68. #endif    
          69. #endif   
          70.   
          71.   
          72.   在具體實現的時候,我們只關心兩個函數原型    
          73.   JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); 和    
          74.   JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);   
          75.   
          76.   這里JNIEXPORT和JNICALL都是JNI的關鍵字,表示此函數是要被JNI調用的。而jint是以JNI為中介使JAVA的int類型與本 地的int溝通的一種類型,我們可以視而不見,就當做int使用。函數的名稱是JAVA_再加上java程序的package路徑再加函數名組成的。參數 中,我們也只需要關心在JAVA程序中存在的參數,至于JNIEnv*和jclass我們一般沒有必要去碰它。    
          77.   
          78.   好,下面我們用testdll.cpp文件具體實現這兩個函數:    
          79.   
          80. #include "testdll.h"    
          81. int i = 0;    
          82. JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)    
          83. {    
          84. return i;    
          85. }    
          86. JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)    
          87. {    
          88. i = j;    
          89. }   
          90.   
          91.   
          92.   編譯連接成庫文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名稱要與JAVA中需要調用的一致,這里就是goodluck.dll 。把goodluck.dll拷貝到testdll.class的目錄下,java testdll運行它,就可以觀察到結果了。    
          93.   我的項目比較復雜,需要調用動態鏈接庫,這樣在JNI傳送參數到C程序時,需要對參數進行處理轉換。才可以被C程序識別。   
          94.   大體程序如下:   
          95.   
          96. public class SendSMS {    
          97. static    
          98. {    
          99.   
          100.   
          101.     
          102. System.out.println(System.getProperty("java.library.path"));    
          103. System.loadLibrary("sms");    
          104. }    
          105. public native static int SmsInit();    
          106. public native static int SmsSend(byte[] mobileNo, byte[] smContent);    
          107. }    
          108.   
          109.   在這里要注意的是,path里一定要包含類庫的路徑,否則在程序運行時會拋出異常:   
          110.   java.lang.UnsatisfiedLinkError: no sms in java.library.path   
          111.   at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1491)   
          112.   at java.lang.Runtime.loadLibrary0(Runtime.java:788)   
          113.   at java.lang.System.loadLibrary(System.java:834)   
          114.   at com.mobilesoft.sms.mobilesoftinfo.SendSMS.(SendSMS.java:14)   
          115.   at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)   
          116.   Exception in thread "main"  
          117.   
          118.   指引的路徑應該到.dll文件的上一級,如果指到.dll,則會報:   
          119.   java.lang.UnsatisfiedLinkError: C:\sms.dll: Can't find dependent libraries   
          120.   at java.lang.ClassLoader$NativeLibrary.load(Native Method)   
          121.   at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1560)   
          122.   at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1485)   
          123.   at java.lang.Runtime.loadLibrary0(Runtime.java:788)   
          124.   at java.lang.System.loadLibrary(System.java:834)   
          125.   at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)   
          126.   Exception in thread "main"  
          127.   
          128.   通過編譯,生成com_mobilesoft_sms_mobilesoftinfo_SendSMS.h頭文件。(建議使用Jbuilder進行編 譯,操作比較簡單!)這個頭文件就是Java和C之間的紐帶。要特別注意的是方法中傳遞的參數jbyteArray,這在接下來的過程中會重點介紹。   
          129.   
          130. /* DO NOT EDIT THIS FILE - it is machine generated */    
          131. #include    
          132. /* Header for class com_mobilesoft_sms_mobilesoftinfo_SendSMS */    
          133. #ifndef _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS    
          134. #define _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS    
          135. #ifdef __cplusplus    
          136. extern "C" {    
          137. #endif    
          138. /*   
          139. * Class: com_mobilesoft_sms_mobilesoftinfo_SendSMS   
          140. * Method: SmsInit   
          141. * Signature: ()I   
          142. */    
          143. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit    
          144. (JNIEnv *, jclass);    
          145. /*   
          146. * Class: com_mobilesoft_sms_mobilesoftinfo_SendSMS   
          147. * Method: SmsSend   
          148. * Signature: ([B[B)I   
          149. */    
          150. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsSend    
          151. (JNIEnv *, jclass, jbyteArray, jbyteArray);    
          152. #ifdef __cplusplus    
          153. }    
          154. #endif    
          155. #endif   
          156.   
          157.   
          158.   
          159.   對于我要調用的C程序的動態鏈接庫,C程序也要提供一個頭文件,sms.h。這個文件將要調用的方法羅列了出來。   
          160.   
          161. /*   
          162. * SMS API   
          163. * Author: yippit   
          164. * Date: 2004.6.8   
          165. */    
          166. #ifndef MCS_SMS_H    
          167. #define MCS_SMS_H    
          168. #define DLLEXPORT __declspec(dllexport)    
          169. /*sms storage*/    
          170. #define SMS_SIM 0    
          171. #define SMS_MT 1    
          172. /*sms states*/    
          173. #define SMS_UNREAD 0    
          174. #define SMS_READ 1    
          175. /*sms type*/    
          176. #define SMS_NOPARSE -1    
          177. #define SMS_NORMAL 0    
          178. #define SMS_FLASH 1    
          179. #define SMS_MMSNOTI 2    
          180. typedef struct tagSmsEntry {    
          181. int index; /*index, start from 1*/    
          182. int status; /*read, unread*/    
          183. int type; /*-1-can't parser 0-normal, 1-flash, 2-mms*/    
          184. int storage; /*SMS_SIM, SMS_MT*/    
          185. char date[24];    
          186. char number[32];    
          187. char text[144];    
          188. } SmsEntry;    
          189. DLLEXPORT int SmsInit(void);    
          190. DLLEXPORT int SmsSend(char *phonenum, char *content);    
          191. DLLEXPORT int SmsSetSCA(char *sca);    
          192. DLLEXPORT int SmsGetSCA(char *sca);    
          193. DLLEXPORT int SmsSetInd(int ind);    
          194. DLLEXPORT int SmsGetInd(void);    
          195. DLLEXPORT int SmsGetInfo(int storage, int *max, int *used);    
          196. DLLEXPORT int SmsSaveFlash(int flag);    
          197. DLLEXPORT int SmsRead(SmsEntry *entry, int storage, int index);    
          198. DLLEXPORT int SmsDelete(int storage, int index);    
          199. DLLEXPORT int SmsModifyStatus(int storage, int index); /*unread -> read*/    
          200. #endif   
          201.   
          202.   
          203.   在有了這兩個頭文件之后,就可以進行C程序的編寫了。也就是實現對JNI調用的兩個方法。在網上的資料中,由于調用的方法實現的都比較簡單,(大多是打印字符串等)所以避開了JNI中最麻煩的部分,也是最關鍵的部分,參數的傳遞。     
          204. 由于Java和C的編碼是不同的,所以傳遞的參數是要進行再處理,否則C程序是會對參數在編譯過程中提出警告,例如;warning C4024: 'SmsSend' : different types for formal and actual parameter 2等。   
          205.   Sms.c的程序如下:   
          206.   
          207. #include "sms.h"    
          208. #include "com_mobilesoft_sms_mobilesoftinfo_SendSMS.h"    
          209. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit(JNIEnv * env, jclass jobject)    
          210. {    
          211. return SmsInit();    
          212. }    
          213.   
          214. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsSend(JNIEnv * env, jclass jobject, jbyteArray mobileno, jbyteArray smscontent)    
          215. {    
          216. char * pSmscontent ;    
          217. //jsize theArrayLengthJ = (*env)->GetArrayLength(env,mobileno);    
          218. jbyte * arrayBody = (*env)->GetByteArrayElements(env,mobileno,0);    
          219. char * pMobileNo = (char *)arrayBody;    
          220. printf("[%s]\n ", pMobileNo);    
          221. //jsize size = (*env)->GetArrayLength(env,smscontent);    
          222. arrayBody = (*env)->GetByteArrayElements(env,smscontent,0);    
          223. pSmscontent = (char *)arrayBody;    
          224. printf("<%s>\n", pSmscontent);    
          225. return SmsSend(pMobileNo,pSmscontent);    
          226. }   
          227.   
          228.   
          229.   
          230.   對于C或C++,在程序上是會有稍微的不同,這可以由讀者對其進行適當的修改。這里要注意的是GetArrayLength,GetByteArrayElements等這些JNI中已經包含的方法,這些方法是專門對轉換參數類型而提供的。具體的方法有很多,在下一篇中會做專門的介紹。   
          231.   在完成了上述的文件后,可以對sms.c進行編譯,生成.dll文件(建議在release中編譯,這樣動態鏈接庫的容積會比較小?。?  
          232.   完成.dll文件的編譯后,就可以在Java中調用C程序中的方法了。例如文件test.java   
          233.   
          234. public class test {    
          235. public test() {    
          236. }    
          237. public static void main(String[] args) {    
          238. byte[] mobileno = {    
          239. 0x310x330x360x360x310x360x330x300x360x360x370x00};    
          240. String smscontentemp = "早上好";    
          241. byte[] temp = {0};    
          242. try {    
          243. byte[] smscontentdb = smscontentemp.getBytes("gbk");    
          244. byte[] smscontent = new byte[smscontentdb.length + temp.length];    
          245. System.arraycopy(smscontentdb, 0, smscontent, 0, smscontentdb.length);    
          246. System.arraycopy(temp, 0, smscontent, smscontentdb.length, temp.length);    
          247. SendSMS sendSMS = new SendSMS();    
          248. sendSMS.SmsInit();    
          249. if (sendSMS.SmsSend(mobileno, smscontent) >= 0) {    
          250. System.out.println("chenggong !");    
          251. }    
          252. else {    
          253. System.out.println("shibai !");    
          254. }    
          255. }catch (Exception ex) {}    
          256. }    
          257. }   
          258.   
          259.   
          260.   
          261.   在這個文件中要注意的有一點,就是在傳遞字節數組到C程序中時,最后的結尾一定要以0結束。這是一個偷懶的做法,不過是個有效的做法。因為大多數情況 下,接口是由第三方提供的。所以我們一般是不知道在C的方法里,具體是怎么處理參數的。而C又是要求數組是有長度。所以,在Java中,如果你不想寫程序 傳數組的長度,那么在數組中以0結尾就是最方便的方法了。當然,如果有更好的方法也希望大家提出。   
          262.   
          263.   到這里,一個完整的Java通過JNI調用動態鏈接庫的程序就完成了。實際上也不是很復雜。只要多注意一下細節,是很容易得出來的。  
          posted on 2009-05-07 11:04 lanxin1020 閱讀(176) 評論(0)  編輯  收藏 所屬分類: j2se
          主站蜘蛛池模板: 泾川县| 西充县| 若尔盖县| 盐亭县| 邵东县| 定边县| 阿瓦提县| 大洼县| 芮城县| 阿合奇县| 探索| 乡城县| 惠来县| 会昌县| 修水县| 宝应县| 镇沅| 聂荣县| 忻州市| 前郭尔| 湖北省| 阜平县| 郧西县| 平罗县| 巢湖市| 贵定县| 苏州市| 郁南县| 永清县| 石狮市| 奉节县| 精河县| 陕西省| 黔西| 普兰店市| 东丰县| 新平| 小金县| 上蔡县| 宁武县| 木里|