gpt4 book ai didi

java - JNI 不适用于 __stdcall

转载 作者:太空宇宙 更新时间:2023-11-04 00:50:28 30 4
gpt4 key购买 nike

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

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

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,但我相信它使用 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);
}

没用!我得到异常:

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 导出函数的约定。所以,我做了一个非常肮脏的 hack:

#define JNICALL __cdecl

而且有效!

它之前在 jni_md.h 中被定义为 __stdcall。我意识到我在做一件非常糟糕的事情,伤害了小猫,但我缺乏 C/C++ 经验,我想不通,为什么我要重新定义它?为什么标准 header (jni_md.h) 对此定义不正确?

最佳答案

对于 jni 使用的 32 位 DLL,代码必须在没有通常的 __stdcall 修饰的情况下编译 - 即代码不能有 @N 后缀交易品种名称;但仍然需要在__stdcall模式下编译。

在mingw下编译dll时,需要在链接器中加入选项--kill-at。这通常使用 -Wl,--kill-at 传递。这将导致 @N 后缀被删除,因此显示为一个简单的符号,可以在运行时由 JVM 链接。该选项也可以缩写为-Wl,-k

另一种方法是使用映射文件,它以未损坏的形式导出符号,这是使用 Microsoft 自己的 visual studio 编译器进行编译时最常用的机制。

这没有很好的记录,并且当它发生时你得到的结果错误并没有太大帮助。

我建议查看 JNA ,这使得编写 native 代码包装器变得更加简单,在这种情况下意味着不需要 C++ 代码。

完成此操作的 JNA 代码如下所示:

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();
}
};

关于java - JNI 不适用于 __stdcall,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20790001/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com