java调用CC++编写的DLL文件问题

感谢大家支持,这几天我在IBM中文及SUN官方网站中找了不少关于JNI的文章,受益非浅,希望 
  
  有相关问题的朋友,可到那找查相关资料. 
  
  1)在   Windows   中实现   Java   本地方法 
  http://www-900.ibm.com/developerWorks/cn/java/jnimthds/index.shtml 
  2)Java   Native   Interface:   Programmer's   Guide   and   Specification   
  http://java.sun.com/docs/books/jni 
  
  上面的文章对JNI介绍非常详细,对JNI有性趣的朋友可以看看. 
  
  对于我提出的问题,我己有了成功例子,贴出来与大家分享. 
  有一myDll.dll库,接口Trim(LPSTR   lpString),功能是把lpString中的空格去掉。文件原码 
  
  如下: 
  #include   <string.h> 
  #include   <windows.h> 
  
  #ifdef   _cplusplus 
  extern   "C"{ 
  #endif 
  __declspec(dllexport)   void   Trim(LPSTR   lpString) 
  { 
  int   iLength   =   strlen(lpString); 
  int   iCount   =   0; 
  char   *lpChar   =   lpString; 
  int   i; 
  for(i=0;i<iLength;i++) 
  { 
  if(   *lpChar   !=   '   '   ) 
  { 
  lpString[   iCount   ]   =   *lpChar; 
  iCount   ++; 
  } 
  lpChar   ++; 
  } 
  lpString[iCount   ++]   =   0; 
  } 
  
  #ifdef   _cplusplus 
  } 
  #endif 
  
  (用VC6的cl编译该文件生成动态链接库,cl   -LD   myDll.c   -FemyDll.dll   ) 
  
  这里假设我们不能得到该动态链接库的原代码,只有DLL及LIB文件,在通过JNI用java调用时 
  
  ,由于没有DLL原代码修改权限,需要我们自己用C/C++再做一个中介库DLL2,java调用这个 
  
  中介库,该中介库再调用原如的DLL库,间接实现java本地方法的调用。 
  下面是我做的例子,环境:Win2000Server,JDK1.3,VC6.0 
  
  先编一个java程序,java2dll.java,代码如下: 
  public   class   Java2dll 
  { 
  
  
  
  
  //声明要用到的本地方法cTrim由中介库(java2dll.dll)实现,它又调用了myDll.dll库的T 
  
  rim(...)函数 
  private   native   String   cTrim(String   str); 
  static 
  { 
  System.loadLibrary(   "java2dll"   );     //加载本地方法(java2dll为动态 
  
  链接库文件名) 
  } 
  
  //自己定义的一个java方法,调用本地方法cTrim(),有点多余,实际上你可直接访 
  
  问本地方法cTrim() 
  public   String   javaTrim(String   str) 
  { 
  return   cTrim(str); 
  } 
  
  //演示结果 
  public   static   void   main(String[]   args) 
  { 
  Java2dll   ss   =   new   Java2dll(); 
  String   str1="I   love   You."; 
  String   str2=ss.javaTrim(str1); 
  System.out.println("调用c   DLL前:"); 
  System.out.println("str1="+str1); 
  System.out.println("调用c   DLL后:"); 
  System.out.println("str2="+str2); 
  } 
  } 
  
  编译该文件,生成Java2dll.class文件:   
  javac   Java2dll.java 
  生成C的头文件Java2dll.h:     
  javah   -jni   Java2dll 
  
  用C编写中介库java2dll.c 
  #include   <stdio.h> 
  #include   "java2dll.h" 
  
  JNIEXPORT   jstring   JNICALL   Java_Java2dll_cTrim 
    (JNIEnv   *env,   jobject   obj,   jstring   str) 
  { 
  const   char   *strTemp; 
  strTemp=(*env)->GetStringUTFChars(env,str,NULL); 
  //错误出现时 
  if(strTemp==NULL) 
  { 
  return   NULL; 
  } 
  
  //调用myDll.dll库中的Trim()方法,去掉strTemp中的空格 
  Trim(strTemp); 
  return   (*env)->NewStringUTF(env,   strTemp); 
  
  (*env)->ReleaseStringUTFChars(env,str,strTemp); 
  } 
  说明:如果你用C++编写,cpp文件,上面代码中的“(*env)”应改为“env” 
  
  编译生成java2ddl.dll文件。 
  用VC6的cl编译。 
  cl   -Id:/jdk13/include   -Id:/jdk13/include/win32   -LD   java2dll.c   myDll.lib   -Fejava2dll.dll 
  说明:-Id:/jdk13/include指明JNI需要的头文件.h位置,D:/JDK13为我的JDK安装目录 
  -LD   表明要生成动态链接库   
  myDll.lib或   -link   
  
  myDll.lib表明要把myDll.dll链接上,否则中介库java2dll找不到Trim(..)方法。 
  您可用cl   /?得到HELP帮助。 
  
  编译成功后,可得到中介库java2dll,运行一下,检查结果。 
  java   Java2dll 
  
  好了,你自己试一下吧。

从   Java   程序调用   C   或   C   ++   代码的过程由六个步骤组成。我们将在下面几页中深入讨论每个步骤,但还是先让我们迅速地浏览一下它们。 
  
  
  编写   Java   代码。我们将从编写   Java   类开始,这些类执行三个任务:声明将要调用的本机方法;装入包含本机代码的共享库;然后调用该本机方法。 
  
  
  编译   Java   代码。在使用   Java   类之前,必须成功地将它们编译成字节码。 
  
  
  创建   C/C++   头文件。C/C++   头文件将声明想要调用的本机函数说明。然后,这个头文件与   C/C++   函数实现(请参阅步骤   4)一起来创建共享库(请参阅步骤   5)。 
  
  
  编写   C/C++   代码。这一步实现   C   或   C++   源代码文件中的函数。C/C++   源文件必须包含步骤   3   中创建的头文件。 
  
  
  创建共享库文件。从步骤   4   中创建的   C   源代码文件来创建共享库文件。 
  
  
  运行   Java   程序。运行该代码,并查看它是否有用。我们还将讨论一些用于解决常见错误的技巧。   
  
  
    
  步骤   1:编写   Java   代码   第   3   页(共16   页)   
  
  
  
  
  我们从编写   Java   源代码文件开始,它将声明本机方法(或方法),装入包含本机代码的共享库,然后实际调用本机方法。 
  
  这里是名为   Sample1.java   的   Java   源代码文件的示例: 
  
  
    1.   public   class   Sample1 
    2.   { 
    3.       public   native   int   intMethod(int   n); 
    4.       public   native   boolean   booleanMethod(boolean   bool); 
    5.       public   native   String   stringMethod(String   text); 
    6.       public   native   int   intArrayMethod(int[]   intArray); 
    7. 
    8.       public   static   void   main(String[]   args) 
    9.       { 
  10.           System.loadLibrary("Sample1"); 
  11.           Sample1   sample   =   new   Sample1(); 
  12.           int           square   =   sample.intMethod(5); 
  13.           boolean   bool       =   sample.booleanMethod(true); 
  14.           String     text       =   sample.stringMethod("JAVA"); 
  15.           int           sum         =   sample.intArrayMethod( 
  16.                                                   new   int[]{1,1,2,3,5,8,13}   ); 
  17. 
  18.           System.out.println("intMethod:   "   +   square); 
  19.           System.out.println("booleanMethod:   "   +   bool); 
  20.           System.out.println("stringMethod:   "   +   text); 
  21.           System.out.println("intArrayMethod:   "   +   sum); 
  22.       } 
  23.   } 
  
  
  
    第二步接下来,我们需要将   Java   代码编译成字节码。完成这一步的方法之一是使用随   SDK   一起提供的   Java   编译器   javac。用来将   Java   代码编译成字节码的命令是: 
  
          
  javac   Sample1.java 
  
  第三步是创建   C/C++   头文件,它定义本机函数说明。完成这一步的方法之一是使用   javah.exe,它是随   SDK   一起提供的本机方法   C   存根生成器工具。这个工具被设计成用来创建头文件,该头文件为在   Java   源代码文件中所找到的每个   native   方法定义   C   风格的函数。这里使用的命令是: 
  
    
  javah   Sample1   
  第四步当谈到编写   C/C++   函数实现时,有一点需要牢记:说明必须和   Sample1.h   的函数声明完全一样。我们将研究用于   C   实现和   C++   实现的完整代码,然后讨论两者之间的差异 
  以下是   Sample1.c,它是用   C   编写的实现: 
  
  
    1.   #include   "Sample1.h" 
    2.   #include   <string.h> 
    3.   
    4.   JNIEXPORT   jint   JNICALL   Java_Sample1_intMethod 
    5.       (JNIEnv   *env,   jobject   obj,   jint   num)   { 
    6.         return   num   *   num; 
    7.   } 
    8.   
    9.   JNIEXPORT   jboolean   JNICALL   Java_Sample1_booleanMethod 
  10.       (JNIEnv   *env,   jobject   obj,   jboolean   boolean)   { 
  11.       return   !boolean; 
  12.   } 
  13. 
  14.   JNIEXPORT   jstring   JNICALL   Java_Sample1_stringMethod 
  15.       (JNIEnv   *env,   jobject   obj,   jstring   string)   { 
  16.           const   char   *str   =   (*env)->GetStringUTFChars(env,   string,   0); 
  17.           char   cap[128]; 
  18.           strcpy(cap,   str); 
  19.           (*env)->ReleaseStringUTFChars(env,   string,   str); 
  20.           return   (*env)->NewStringUTF(env,   strupr(cap)); 
  21.   } 
  22.   
  23.   JNIEXPORT   jint   JNICALL   Java_Sample1_intArrayMethod 
  24.       (JNIEnv   *env,   jobject   obj,   jintArray   array)   { 
  25.           int   i,   sum   =   0; 
  26.           jsize   len   =   (*env)->GetArrayLength(env,   array); 
  27.           jint   *body   =   (*env)->GetIntArrayElements(env,   array,   0); 
  28.           for   (i=0;   i<len;   i++) 
  29.           { sum   +=   body[i]; 
  30.           } 
  31.           (*env)->ReleaseIntArrayElements(env,   array,   body,   0); 
  32.           return   sum; 
  33.   } 
  34.   
  35.   void   main(){} 
  
  
  
    
  步骤   5:创建共享库文件   第   13   页(共16   页)   
  
  
  
  
  接下来,我们创建包含本机代码的共享库文件。大多数   C   和   C++   编译器除了可以创建机器代码可执行文件以外,也可以创建共享库文件。用来创建共享库文件的命令取决于您使用的编译器。下面是在   Windows   和   Solaris   系统上执行的命令。 
  
  Windows:   cl   -Ic:/jdk/include   -Ic:/jdk/include/win32   -LD   Sample1.c   -FeSample1.dll   
  Solaris:   cc   -G   -I/usr/local/jdk/include   -I/user/local/jdk/include/solaris   Sample1.c   -o   Sample1.so   
  
    
  
  
  最后一步是运行   Java   程序,并确保代码正确工作。因为必须在   Java   虚拟机中执行所有   Java   代码,所以需要使用   Java   运行时环境。完成这一步的方法之一是使用   java,它是随   SDK   一起提供的   Java   解释器。所使用的命令是: 
  
          
  java   Sample1 
  
  
  当运行   Sample1.class   程序时,应该获得下列结果: 
  
  
  PROMPT>java   Sample1 
  intMethod:   25 
  booleanMethod:   false 
  stringMethod:   JAVA 
  intArrayMethod:   33 
  
  PROMPT> 
  
  来自ibm的jni教程


这是Sun的教程 
  http://java.sun.com/docs/books/tutorial/native1.1/index.html 
  
  Java调用C,C调用Java

你可能感兴趣的:(java,String,Solaris,jni,dll,编译器)