JNI不与__stdcall工作 [英] JNI does not work with __stdcall

查看:452
本文介绍了JNI不与__stdcall工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在玩弄JNI在Windows 7x64,Java版本为1.7.0_40和MinGW / GCC / G ++ 4.7.2。

I'm playing around with JNI on Windows 7x64, Java version is 1.7.0_40 and MinGW / GCC / G++ 4.7.2.

试图从Java我的显示器关闭。所以,我创建了一个类:

Trying to power off my monitor from Java. So, I've created a class:

public class MonitorTrigger {
    static {
        try {
            System.load(new ClassPathResource("MonitorTrigger.dll").getFile().getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public native void on();

    public native void off();
}

然后,生成的 ^ h 从该文件(与Eclipse,但我beleive它使用 JAVAH

Then, generated h file from it (with Eclipse, but I beleive it uses javah):

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

#ifndef _Included_by_dev_madhead_bubikopf_desktop_monitortrigger_util_MonitorTrigger
#define _Included_by_dev_madhead_bubikopf_desktop_monitortrigger_util_MonitorTrigger
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     by_dev_madhead_bubikopf_desktop_monitortrigger_util_MonitorTrigger
 * Method:    on
 * Signature: ()V
 */
JNIEXPORT void
        JNICALL Java_by_dev_madhead_bubikopf_desktop_monitortrigger_util_MonitorTrigger_on(
                JNIEnv *, jobject);

/*
 * Class:     by_dev_madhead_bubikopf_desktop_monitortrigger_util_MonitorTrigger
 * Method:    off
 * Signature: ()V
 */
JNIEXPORT void
        JNICALL Java_by_dev_madhead_bubikopf_desktop_monitortrigger_util_MonitorTrigger_off(
                JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

和实现它:

#include "by_dev_madhead_bubikopf_desktop_monitortrigger_util_MonitorTrigger.h"

#include <iostream>
#include <windows.h>

JNIEXPORT void JNICALL Java_by_dev_madhead_bubikopf_desktop_monitortrigger_util_MonitorTrigger_on
(JNIEnv * env, jobject object) {
    SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) -1);
}

JNIEXPORT void JNICALL Java_by_dev_madhead_bubikopf_desktop_monitortrigger_util_MonitorTrigger_off
(JNIEnv * env, jobject object) {
    SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2);
}

它不工作!我得到异常:

It does not work! I get exception:

Exception in thread "main" java.lang.UnsatisfiedLinkError: by.dev.madhead.bubikopf.desktop.monitortrigger.util.MonitorTrigger.off()V
    at by.dev.madhead.bubikopf.desktop.monitortrigger.util.MonitorTrigger.off(Native Method)
    at by.dev.madhead.bubikopf.desktop.monitortrigger.App.main(App.java:7)

我被卡住了位,但谷歌搜索后,我找到了一个解决方案 - 使用 __ CDECL 而不是 __ STDCALL 约定导出的函数。所以,我做了一个非常肮脏的黑客:

I was stuck for a bit, but after googling, I've found a solution - use __cdecl instead of __stdcall convention for exported function. So, I've made a very dirty hack:

#define JNICALL __cdecl

和它的作品!

这是在 jni_md.h pviously定义为__stdcall $ P $。我知道我在做一个非常糟糕的事情,这伤害小猫,但我缺乏的C / C ++的经历,我想不通,我为什么要重新定义呢?为什么标准头( jni_md.h )定义了这个错误?

It was previously defined as __stdcall at jni_md.h. I realize that I'm doing a very bad thing, which harm kittens, but I lack of experience in C/ C++, and I cannot figure out, why I should redefine this? Why standard header (jni_md.h) defines this incorrectly?

推荐答案

有关32位的DLL文件正在使用JNI时,code有没有通常被编译 __ STDCALL 装饰品 - 即code不能有 @N 后缀的符号名;但它仍然需要在 __ STDCALL要编译模式。

For 32 bit DLLs being used by jni, the code has to be compiled without the usual __stdcall adornments - i.e. the code can't have the @N postfix on the symbol name; but it still needs to be compiled in __stdcall mode.

在编译的MinGW下的DLL,您需要添加的选项 - 杀 - 以来的链接。这是使用 -Wl一般过去了, - 杀 - 以。这将导致要删除的 @N 后缀,因此会显示为一个简单的符号,可在由JVM运行时被链接。该选项可以缩写为轮候册,-k 以及

When compiling the dll under mingw, you need to add the option --kill-at to the linker. This is generally passed using -Wl,--kill-at. This will cause the @N postfix to be removed, and so appear as a simple symbol which can be linked at run-time by the JVM. The option can be abbreviated to -Wl,-k as well.

另一种方法是使用一个映射文件,其中出口符号在其重整的形式,这是与微软自己的Visual Studio编译器在编译时所使用的最常见的机制。

An alternative is to use a map file, which exports the symbols in their unmangled form, which is the mechanism that's used most often when compiling with microsoft's own visual studio compiler.

这是pretty不良记录,你会得到所产生的误差,当它发生不利于太清楚了。

This is pretty poorly documented, and the resulting error you get when it happens doesn't help too well.

我建议在看 JNA ,这使得编写本地code包装简单了很多,在这种情况下,就意味着没有C ++ code需要。

I'd recommend looking at JNA, which makes writing native code wrappers a lot simpler, and in this case would mean no C++ code needed.

在JNA code来完成这个样子:

The JNA code to accomplish this looks like:

import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.WPARAM;

public class JNAMonitorTrigger {
    public void monitor(LPARAM param) {
        User32.INSTANCE.PostMessage(WinUser.HWND_BROADCAST,
            WinUser.WM_SYSCOMMAND,
            new WPARAM(0xf170), param);
    }
    public void on() {
        monitor(new LPARAM(-1));
    }

    public void off() {
        monitor(new LPARAM(2));
    }

    public static void main(String args[]) throws Exception {
        JNAMonitorTrigger me = new JNAMonitorTrigger();
        me.off();
        Thread.sleep(1000);
        me.on();
    }
};

这篇关于JNI不与__stdcall工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆