Music Studio專案心得--JNI實現C++呼叫JAVA

凝霜發表於2011-03-06

     這個專案是我參加內蒙古挑戰杯的比賽專案,由於時間關係,我沒時間實現OpenOMR開源專案由JAVA完全向C++的轉換,經過我半個多月的嘗試,我將OpenOMR中的1/3的程式碼改寫成C++,不過很快我就發現,如果按照這個進度,我是無論如何也無法按時完成工作了,更重要的是Joone人工智慧庫的演算法要是完全移植不是我一個大二學生能夠在這麼短的時間做到的,於是我放棄JAVA轉C++的解決方。

    取而代之的是,我使用JAVA做演算法的核心,這樣就可以用最小的代價快速完成專案,而用C++去呼叫JAVA的方法,並封裝成dll,最後使用C# + IrisSkin2 + 自繪空間的方式製作介面並實現業務邏輯(不要認為C++的步驟多此一舉,實際上我的母語是C++,所以做起來非常順手,反而使我的效率大幅度提升)。

    下面說一下我在實現C++呼叫JAVA的過程中遇到的一些問題。

 

    開發環境: Visual Studio 2010 Ultimate (英文版) + eclipse 3.6.1 + JDK 1.6.0_10


     眾所周知JAVA依賴jvm,而且執行起來非常繁瑣,我這個專案的命令列如下(批處理)

     java -cp %cd%/joone-engine-2.0.0RC1/joone-engine.jar;%cd%/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;.;%cd%/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar -Xmx256m openomr.openomr.SheetMusic

     不要說使用者看這東西會不知所措,就是我看著這東西也是很頭疼(雖然我很熟悉dos)

 

     下面講一下技術難點:

 

     一、不依賴使用者機器上的JAVA環境

     解決方案:使用本地應用程式整合jre環境,脫離對客戶機器jre的依賴

     遇見的問題:最開始的時候我認為只需要附帶jvm.dll即可實現我的目的,程式碼如下

   

    我將jvm.lib和jvm.dll都放在Debug資料夾中,我發現這時的程式能正確載入jvm.dll,但是執行

    JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");

    就提示失敗了,為了解決這個問題我開始閱讀jni的文件,但是收效甚微,於是開始在各大技術論壇開始尋找解決方案,但是沒有找到解決方案,於是我將系統的jre中的jvm.dll載入到程式中,這次程式終於正常跑了起來。

    小結:jvm.dll的執行依賴jre中許多dll,而我在專案初期只外掛一個jvm.dll導致了jvm無法正常建立,順便說一下,解決這個問題從下午5點一直到晚上接近十點才徹底解決,有時候人的慣性思維真的會限制住靈感。

    技術難點二:帶有目錄結構的java類呼叫

    這個糾結了小半天,直接貼程式碼了

   

 

    期間遇到的主要問題就是在VS2010上除錯程式,始終FindClass查詢類失敗,為此試了各種辦法,先是呼叫jar,後來又把jar解壓。。。都沒有成功,於是乎。。。各種糾結。。。下午趕上騰訊的CF有活動,因此申請了個新QQ,去領了把M4A1-A + 防彈衣嘿嘿,小小的YD一下。。。晚上回來突然想法一個問題,就是VS2010的解決方案的目錄結構問題

   先看一下我的測試專案的目錄結構-

 

    大家注意,E:/工程/Cpp呼叫Java/Debug是可執行檔案生成的資料夾,我的庫也是直接放在了這個資料夾內,但是這就導致了一個問題,我的程式碼和exe不再同一個目錄,於是

static char ClassPath[] = "-Djava.class.path=./;E:/joone-engine-2.0.0RC1/joone-engine.jar;E:/jfreechart-1.0.1/lib/jcommon-1.0.0.jar;E:/jfreechart-1.0.1/lib/jfreechart-1.0.1.jar";

static char LibraryPath[] = "-Djava.library.path=./";

這裡面的”./“在原始碼中代表的路徑就是E:/工程/Cpp呼叫Java/Cpp呼叫Java

而在生成的exe中是E:/工程/Cpp呼叫Java/

但由於VS2010的特性,它的工作目錄不是exe所在目錄,而是原始碼所在目錄,這就導致了

static char AppClass[] = "openomr/openomr/SheetMusic";

在加上工作目錄組成的絕對路徑錯誤,也就是真正導致FindClass失敗的原因

小結:這個問題在很詭異,需要在今後的開發中注意,不能再犯這種低階錯誤了

 

哈哈,呼叫java方法成功了,我可以放鬆一下了。。。我去CF了。。。

 

 

 

相關文章