0

我在 Windows 7 上使用 JDK 1.7.0_40 通过 Java 调用 DLL(用 GCC 编译)。我已将生成的文件复制hello.dll到我的java/bin目录中,并正在HelloJNI.java从控制台执行。

我收到此错误:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x610d70b4, pid=1956, tid=3960
#
# JRE version: Java(TM) SE Runtime Environment (7.0_40-b43) (build 1.7.0_40-b43)
# Java VM: Java HotSpot(TM) Client VM (24.0-b56 mixed mode, sharing windows-x86 )
# Problematic frame:
# C  [cygwin1.dll+0xd70b4]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# D:\workspace\HelloJNI\hs_err_pid1956.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

我的头文件,生成java -jni HelloJNI

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */

#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloJNI
 * Method:    sayHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloJNI_sayHello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

我的 C 代码,编译为gcc -Wl,--add-stdcall-alias -I"d:\Program Files\Java\jdk1.7.0_40\include" -I"d:\Program Files\Java\jdk1.7.0_40\include\win32" -shared -o hello.dll HELLOJNI.c

#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"

JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env,jobject thisObj) {
printf("Hai Welcome");
return;
}
4

1 回答 1

0

好吧,这是我对这个问题的解决方案。

我用 gcc 4.9.3 在 cygwin32 上解决了这个问题。

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-pc-cygwin/4.9.3/lto-wrapper.exe
Target: i686-pc-cygwin
Configured with: /cygdrive/i/szsz/tmpp/gcc/gcc-4.9.3-1.i686/src/gcc-4.9.3/configure --srcdir=/cygdrive/i/szsz/tmpp/gcc/gcc-4.9.3-1.i686/src/gcc-4.9.3
--prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=i686-
pc-cygwin --host=i686-pc-cygwin --target=i686-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --enable-shared --ena
ble-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with-arch=i686 --wit
h-tune=generic --disable-sjlj-exceptions --enable-languages=ada,c,c++,fortran,java,lto,objc,obj-c++ --enable-graphite --enable-threads=posix --enable-
libatomic --enable-libgomp --disable-libitm --enable-libquadmath --enable-libquadmath-support --enable-libssp --enable-libada --enable-libjava --enabl
e-libgcj-sublibs --disable-java-awt --disable-symvers --with-ecj-jar=/usr/share/java/ecj.jar --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/inc
lude/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id
Thread model: posix
gcc version 4.9.3 (GCC)

Java版本在这里

$ java -version
java version "1.7.0_60"
Java(TM) SE Runtime Environment (build 1.7.0_60-b19)
Java HotSpot(TM) Client VM (build 24.60-b09, mixed mode)
  1. 编译源代码

    gcc -Wl,--add-stdcall-alias -D__int64="long long" -c HelloJNI.c -o HelloJNI.o -I/where/java1.7/include -Iwhere/java1.7/include/win32

  2. 创建 def 文件,如 VC++ 制作 .def 文件的方式。

    dlltool --output-def HelloJNI.def --kill-at --add-stdcall-alias --dllname HelloJNI.dll HelloJNI.o

  3. 修改def文件,对于这个例子HelloJNI.def你可以看到文件的内容如下

    ; dlltool --output-def HelloJNI.def --kill-at --add-stdcall-alias --dllname HelloJNI.dll HelloJNI.o 导出 Java_com_tobee_jni_test_HelloJNI_message = Java_com_tobee_jni_test_HelloJNI_message@8 @ 1 Java_com_tobee_jni_test_HelloJNI_message@8 @ 2

你在排队时发现了一些奇怪的东西。我刚刚只定义了一个静态 JNI 方法,但在那里定义了两个方法。所以,删除第二行和第一行的equal('=')的左边部分,那么它必须在下面......

; dlltool --output-def HelloJNI.def --kill-at --add-stdcall-alias --dllname HelloJNI.dll HelloJNI.o
EXPORTS
    Java_com_tobee_jni_test_HelloJNI_message@8 @ 1
  1. 使用 dlltool 命令,我想我可以使用上面修改过的 def 文件来调整我的 dll,就像 windows 编程中的 dllexport 一样。

    dlltool --output-lib libHelloJNI.a --input-def HelloJNI.def --kill-at --add-stdcall-alias --dllname HelloJNI.dll HelloJNI.o

  2. 最后一件事是创建一个任意名称的库

    gcc -Wl,--add-stdcall-alias -shared -m32 HelloJNI.o -o HelloJNI.dll -Wall -L -IHelloJNI

我对这个过程没有任何问题。

这是我的源代码

class HelloJNI{

   private native String message();


   public static void main( String[] args ){
      System.out.println("=====>" + new HelloJNI().message());
   }

   static{
     System.loadLibrary( "HelloJNI" );
   }
}

#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"

JNIEXPORT jstring JNICALL Java_com_tobee_jni_test_HelloJNI_message( JNIEnv *env, jobject obj ){
   char buf[128];
   sprintf(buf, "this is my message\r\n");

   return (*env)->NewStringUTF(env, buf);
}

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_tobee_jni_test_HelloJNI */

#ifndef _Included_com_tobee_jni_test_HelloJNI
#define _Included_com_tobee_jni_test_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_tobee_jni_test_HelloJNI
 * Method:    message
 * Signature: ()V
 */
JNIEXPORT jstring JNICALL Java_com_tobee_jni_test_HelloJNI_message
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif
于 2015-11-05T18:00:14.210 回答