JNI调用在驱动程序回调中失败

时间:2017-07-16 15:11:00

标签: java windows java-native-interface

我正在开发一个与硬件设备交互的应用程序。使用随硬件的官方应用程序提供的dll文件,我初始化设备并注册一些函数作为回调,以便在某些用户交互时调用。在这个回调函数中,我想调用Java函数来传输数据。但是,整个应用程序在回调中的此调用中退出时没有任何错误日志:

class String
  def green;"\e[32m#{self}\e[0m";end
  def yellow;"\e[33m#{self}\e[0m";end
  def cyan;"\e[36m#{self}\e[0m";end
  def bg_blue;"\e[44m#{self}\e[0m";end
  def bold;"\e[1m#{self}\e[22m";end
  def underline;"\e[4m#{self}\e[24m";end
  def border(num);"\n#{'-' * num}\n#{self}\n#{'-' * num}\n";end
end

puts;puts "Welcome to 'Guess My Number!'".bold.bg_blue;puts
print 'What is your name? '.green
name = gets.chomp
puts "\nWelcome, #{name.upcase!}!\n".cyan.underline
puts "I've got a random number between 1 and 100!\nCan you guess it?".border(44)
target = rand(100) + 1

num_guesses = 0
guessed_it = false
until num_guesses == 10 || guessed_it
  remaining_guesses = 10 - num_guesses
  puts "\nYou've got #{remaining_guesses} guesses left!\n"
  puts;print 'Make a guess, put down a number: '
  guess = gets.chomp
  case guess.to_i
  when (1...target)
    puts 'Ooops. Your guess was LOW'.yellow.border(26)
  when (target + 1..100)
    puts 'Ooops. Your guess was HIGH'.yellow.border(26)
  when target
    puts; puts; puts
    puts "Good job, #{name}!".bold.green
    puts 'You guessed my number in ' + "#{num_guesses} guesses!".cyan
    puts; puts; puts
    guessed_it = true
  else
    puts "Oooops. You didn't enter a number from 1 to 100".yellow.border(47); puts
  end

  num_guesses += 1
end

unless guessed_it
  puts;puts;puts "Sorry, you didn't get my number. My number was #{target}.".yellow;puts
end

如果在Java直接调用的函数中执行,则同一调用有效。 这种行为的原因是什么?从设备驱动程序调用中调用JNI有何不同?任何帮助表示赞赏。

编辑:我尝试了Vernee的建议,并尝试将驱动程序线程附加到JVM,但行为没有改变。此外,我丢失了jclass cls = env->FindClass("java/lang/String"); 输出,这是 - 我的唯一选择来调试JNI端。它们在附加操作之前工作,但之后停止工作。

1 个答案:

答案 0 :(得分:1)

如果您在Windows上进行开发,我强烈建议您使用visual studio来调试C代码。你可以启动你的java程序并在System.load上放置一个断点,当Java程序此时停止时,转到Visual studio并从工具>附加进程,这样就可以停止在C代码中放置的断点。之后,只需恢复java代码。从C线程调用java方法需要一些准备:

1-缓存JVM对象

JavaVM * javaVm;
(*jenv)->GetJavaVM(jenv, &javaVm);

2-高速缓存包含java回调方法的Class的Class对象。

clazz = (*jenv)->NewGlobalRef(jenv, (*jenv)->FindClass(jenv, "com/something/somepackage/SomeClass"));

3-如果您正在调用实例方法,则还需要使用名为

的实例
callback = (*jenv)->NewGlobalRef(jenv, callbackInstance);

4-将本机线程附加到虚拟机(当您需要调用java方法时)

JNIEnv * jenv;
int errorCode = (*j_javaVm)->AttachCurrentThread(j_javaVm, (void**) &jenv, NULL);

5-获取需要调用的方法ID(当需要调用java方法时)

jmethodID methodID = (*jenv)->GetMethodID(jenv, cachedhandlerClass, "methodNameHere", "methodSignetureHere");

6-进行方法调用

(*jenv)->CallVoidMethod(jenv, cachedCallbackInstance, methodID, param1, param2,....);

7-取消本机线程

(*j_javaVm)->DetachCurrentThread(j_javaVm);

步骤1,2和3需要一个java环境,它们可以在JNI_OnLoad方法或本机Java方法的实现中完成。