07年的时候就用过JNI这东西了,那时候是为了给项目的J2EE应用写一个授权功能,通过调用vc写的读取硬件id的dll使得cdkey能够跟机器一一对应起来,从而做到控制一个cdkey只能装到一台机器上上。那会儿用的dll是别人写的,java中调用dll也是用的小日本儿写的一个叫jcom的组件,这次决定自己做一遍整个流程.
- 编写java文件
/** * Copyright (C), 2009-2010 * File Name: jni.WinMessage.java * Encoding UTF-8 * Version: 1.0 * Date: Dec 29, 2009 * History: */ package jni; /** * * @author (bestirwiny@gmail.com) * @version Revision: 1.00 2:12:24 PM */ public class WinMessage { static{ System.loadLibrary("WinMsgDll"); } public native void showMsgBox(String msg); }
loadLibrary用于load一个dll,该dll应该在java.library.path定义的路径下啊。
- 用javac编译该文件,不用讲。
- javah -jni WinMessage,会生成一个jni_WinMessage.h的头文件,下面要做的工作就是dll的编写了。
/* DO NOT EDIT THIS FILE - it is machine generated */ #include "jni.h" /* Header for class jni_WinMessage */ #ifndef _Included_jni_WinMessage #define _Included_jni_WinMessage #ifdef __cplusplus extern "C" { #endif /* * Class: jni_WinMessage * Method: showMsgBox * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_jni_WinMessage_showMsgBox (JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif
- 创建一个win32动态连接库的工程,将$JAVAHOME/include,$JAVA_HOME/include/win32目录加入到工程需要引用的头文件路径中。
#include "tchar.h" #include "stdlib.h" #include "stdio.h" #include "AtlBase.h" #include "AtlConv.h" #include "windows.h" #include "jni_WinMessage.h" /* * Class: * Method: showMsgBox * Signature: (Ljava/lang/String;)V */ JNIEXPORT void JNICALL Java_jni_WinMessage_showMsgBox (JNIEnv * env, jobject jobj, jstring str){ const char * msg; msg = env->GetStringUTFChars(str,0); WCHAR* strA; int i= MultiByteToWideChar ( CP_UTF8 , 0 ,msg ,-1 ,NULL,0); strA = new WCHAR[i]; MultiByteToWideChar ( CP_UTF8 , 0 ,( char * ) msg, -1, strA , i ); USES_CONVERSION; MessageBox(NULL,strA,_T("Java invoke "),MB_OK); env->ReleaseStringUTFChars(str,msg); }
由于win32变成才开始学,所以这个东西弄了好久才弄好,网上的例子中通过GetStringUTFChars取回的msg直接传到MessageBox中用,可我用的是VS2008,直接用会报错误,大致是说不能将const char *转换为LPCWSTR * ,
LPCWSTR是long pointer constant wide string的意思,是一种wchar_t类型,char类型占用一个byte,而wchar_t占用两个byte,所以这边就要用一个转换 函数,网上查好久才查到MutiByteToWideChar函数,才解决了中文乱码的问题。 - 编译完会成成一个dll文件,拷贝到java.library.path下,我是拷贝到了c:\windows下。
- 编写一个java类调用上面的WinMessage
/** * Copyright (C), 2009-2010 * File Name: jni.TestWinMessage.java * Encoding UTF-8 * Version: 1.0 * Date: Dec 29, 2009 * History: */ package jni; /** * * @author (bestirwiny@gmail.com) * @version Revision: 1.00 4:54:25 PM */ public class TestWinMessage { /** * @param args */ public static void main(String[] args) { WinMessage wm = new WinMessage(); wm.showMsgBox("MC Hotdog,哈狗帮!"); } }
- ok,这下就完成了从java程序中调用win32 API弹出windows原生的窗口了 。