Java JNA- Jar 应用程序在 32 位 windows 系统中挂起
Java JNA- Jar application hangs in 32 bit windows system
这是一个屏幕截图应用程序。使用 1.8 JDK 编译,在 64 位系统中运行良好,但在 32 位系统中滞后并在两次迭代中挂起。
基本上这个应用程序使用机器人 class 截取屏幕截图,从用户那里获取文件名 URL。截断并删除其中的所有非法字符,并使用以时间戳为前缀的另存为对话框将其保存。
我正在使用 Windows Low Level KeyHook 通过 PrtSc 键启动屏幕截图。
32 位系统错误:
它只需要 2 个屏幕截图,然后在我第 3 次按 PrtSc 时没有响应。 JFrame 会不会导致任何问题,它肯定会加载缓慢。我应该使用 JFrame 之外的任何替代文本框,还是因为我已经遵守 java 1.8 jdk 64 位环境,它在较低版本的 jdk 或 32 位系统中不起作用。
public class KeyHook {
private static HHOOK hhk;
private static LowLevelKeyboardProc keyboardHook;
static JFileChooser fileChooser = new JFileChooser();
public static void main(String[] args) {
final User32 lib = User32.INSTANCE;
HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
keyboardHook = new LowLevelKeyboardProc() {
public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
if (nCode >= 0) {
switch(wParam.intValue()) {
case WinUser.WM_KEYUP:
case WinUser.WM_KEYDOWN:
case WinUser.WM_SYSKEYUP:
case WinUser.WM_SYSKEYDOWN:
if (info.vkCode == 44) {
try {
Robot robot = new Robot();
// Capture the screen shot of the area of the screen defined by the rectangle
BufferedImage bi=robot.createScreenCapture(new Rectangle(0,25,1366,744));
JFrame frame = new JFrame();
JFrame.setDefaultLookAndFeelDecorated(true);
frame.toFront();
frame.requestFocus();
frame.setAlwaysOnTop(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// prompt the user to enter their name
String name = JOptionPane.showInputDialog(frame, "Enter file name");
// frame.pack();
frame.dispose();
String fileName= dovalidateFile(name);
FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG", ".png");
fileChooser.setFileFilter(filter);
fileChooser.setSelectedFile(new File (fileName));
int returnVal = fileChooser.showSaveDialog(null);
if ( returnVal == JFileChooser.APPROVE_OPTION ){
File file = fileChooser.getSelectedFile();
file = validateFile(file);
System.out.println(file);
ImageIO.write(bi, "png", file);
}
}
catch (NullPointerException e1)
{e1.printStackTrace(); }
catch (AWTException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
return lib.CallNextHookEx(hhk, nCode, wParam, info.getPointer());
}
private File validateFile(File file) {
DateFormat dateFormat = new SimpleDateFormat("HH.mm.ss.ddMMMMMyyyy");
//get current date time with Calendar()
Calendar cal = Calendar.getInstance();
// System.out.println(dateFormat.format(cal.getTime()));
String filePath = file.getAbsolutePath();
if (filePath.indexOf(".png") == -1) {
filePath += "." + dateFormat.format(cal.getTime()) + ".png";
}
//System.out.println("File Path :" + filePath);
file = new File(filePath);
if (file.exists()) {
file.delete();
}
try {
file.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
private String dovalidateFile(String name) {
String input = name.replace("https://www.","");
input = input.replaceAll("http://www.","");
input = input.replaceAll("https://","");
input = input.replace("http://","");
input = input.replace("/?",".");
input = input.replace("/",".");
input = input.replace("|",".") ;
input = input.replace("%",".");
input = input.replace("<",".");
input = input.replace(">",".");
input = input.replaceAll("\?",".");
input = input.replaceAll("\*",".");
input = input.replace(":",".");
input = input.replace("\",".");
input = Character.toUpperCase(input.charAt(0)) + input.substring(1);
return input;
}
};
hhk = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardHook, hMod, 0);
if(!SystemTray.isSupported()){
return ;
}
SystemTray systemTray = SystemTray.getSystemTray();
Image image = Toolkit.getDefaultToolkit().getImage(KeyHook.class.getResource("/images/icon.png"));
//popupmenu
PopupMenu trayPopupMenu = new PopupMenu();
MenuItem close = new MenuItem("Exit");
close.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.err.println("unhook and exit");
lib.UnhookWindowsHookEx(hhk);
System.exit(0);
}
});
trayPopupMenu.add(close);
//setting tray icon
TrayIcon trayIcon = new TrayIcon(image, "captur", trayPopupMenu);
//adjust to default size as per system recommendation
trayIcon.setImageAutoSize(true);
try{
systemTray.add(trayIcon);
}catch(AWTException awtException){
awtException.printStackTrace();
}
int result;
MSG msg = new MSG();
while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
if (result == -1) {
System.err.println("error in get message");
break;
}
else {
System.err.println("got message");
lib.TranslateMessage(msg);
lib.DispatchMessage(msg);
}
}
lib.UnhookWindowsHookEx(hhk);
}
}
我没有任何使用 JNA 的经验,但是您的代码有几处错误 - 我认为我没有全部理解,但这里有一些:
close.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
quit=true;
}
});
quit=true
将永远无法到达,因为您的程序 exit()
s 才到达那里。
2.
new Thread() {
public void run() {
while (!quit) {
try { Thread.sleep(10); } catch(Exception e) { }
}
System.err.println("unhook and exit");
lib.UnhookWindowsHookEx(hhk);
System.exit(0);
}
}.start();
没有任何意义,因为 quit
永远不会是 true
。同时旋转一个变量来检测变化会严重减慢你的应用程序(特别是睡眠时间为 10 毫秒)。为什么不在您的 ActionListener
中取消挂钩?
3.
while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
这里我不太确定,因为我没有使用 JNA 和 windows 事件系统的经验。该方法等待发送到指定 window 的消息,但由于您没有指定任何消息(第二个参数是 null
),我认为您永远不会收到消息。
- 对于每个回调,您都在创建一个新的
JFrame
,但在方法结束时,您仅使用 frame.setVisible(false);
隐藏它。因为它仍然被各种 Swing-类 引用,所以它永远不会被垃圾收集。这会造成内存泄漏,从而减慢您的应用程序。您将不得不调用 frame.dispose()
来摆脱它。
这是一个屏幕截图应用程序。使用 1.8 JDK 编译,在 64 位系统中运行良好,但在 32 位系统中滞后并在两次迭代中挂起。
基本上这个应用程序使用机器人 class 截取屏幕截图,从用户那里获取文件名 URL。截断并删除其中的所有非法字符,并使用以时间戳为前缀的另存为对话框将其保存。
我正在使用 Windows Low Level KeyHook 通过 PrtSc 键启动屏幕截图。
32 位系统错误: 它只需要 2 个屏幕截图,然后在我第 3 次按 PrtSc 时没有响应。 JFrame 会不会导致任何问题,它肯定会加载缓慢。我应该使用 JFrame 之外的任何替代文本框,还是因为我已经遵守 java 1.8 jdk 64 位环境,它在较低版本的 jdk 或 32 位系统中不起作用。
public class KeyHook {
private static HHOOK hhk;
private static LowLevelKeyboardProc keyboardHook;
static JFileChooser fileChooser = new JFileChooser();
public static void main(String[] args) {
final User32 lib = User32.INSTANCE;
HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
keyboardHook = new LowLevelKeyboardProc() {
public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
if (nCode >= 0) {
switch(wParam.intValue()) {
case WinUser.WM_KEYUP:
case WinUser.WM_KEYDOWN:
case WinUser.WM_SYSKEYUP:
case WinUser.WM_SYSKEYDOWN:
if (info.vkCode == 44) {
try {
Robot robot = new Robot();
// Capture the screen shot of the area of the screen defined by the rectangle
BufferedImage bi=robot.createScreenCapture(new Rectangle(0,25,1366,744));
JFrame frame = new JFrame();
JFrame.setDefaultLookAndFeelDecorated(true);
frame.toFront();
frame.requestFocus();
frame.setAlwaysOnTop(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// prompt the user to enter their name
String name = JOptionPane.showInputDialog(frame, "Enter file name");
// frame.pack();
frame.dispose();
String fileName= dovalidateFile(name);
FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG", ".png");
fileChooser.setFileFilter(filter);
fileChooser.setSelectedFile(new File (fileName));
int returnVal = fileChooser.showSaveDialog(null);
if ( returnVal == JFileChooser.APPROVE_OPTION ){
File file = fileChooser.getSelectedFile();
file = validateFile(file);
System.out.println(file);
ImageIO.write(bi, "png", file);
}
}
catch (NullPointerException e1)
{e1.printStackTrace(); }
catch (AWTException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
return lib.CallNextHookEx(hhk, nCode, wParam, info.getPointer());
}
private File validateFile(File file) {
DateFormat dateFormat = new SimpleDateFormat("HH.mm.ss.ddMMMMMyyyy");
//get current date time with Calendar()
Calendar cal = Calendar.getInstance();
// System.out.println(dateFormat.format(cal.getTime()));
String filePath = file.getAbsolutePath();
if (filePath.indexOf(".png") == -1) {
filePath += "." + dateFormat.format(cal.getTime()) + ".png";
}
//System.out.println("File Path :" + filePath);
file = new File(filePath);
if (file.exists()) {
file.delete();
}
try {
file.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
private String dovalidateFile(String name) {
String input = name.replace("https://www.","");
input = input.replaceAll("http://www.","");
input = input.replaceAll("https://","");
input = input.replace("http://","");
input = input.replace("/?",".");
input = input.replace("/",".");
input = input.replace("|",".") ;
input = input.replace("%",".");
input = input.replace("<",".");
input = input.replace(">",".");
input = input.replaceAll("\?",".");
input = input.replaceAll("\*",".");
input = input.replace(":",".");
input = input.replace("\",".");
input = Character.toUpperCase(input.charAt(0)) + input.substring(1);
return input;
}
};
hhk = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardHook, hMod, 0);
if(!SystemTray.isSupported()){
return ;
}
SystemTray systemTray = SystemTray.getSystemTray();
Image image = Toolkit.getDefaultToolkit().getImage(KeyHook.class.getResource("/images/icon.png"));
//popupmenu
PopupMenu trayPopupMenu = new PopupMenu();
MenuItem close = new MenuItem("Exit");
close.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.err.println("unhook and exit");
lib.UnhookWindowsHookEx(hhk);
System.exit(0);
}
});
trayPopupMenu.add(close);
//setting tray icon
TrayIcon trayIcon = new TrayIcon(image, "captur", trayPopupMenu);
//adjust to default size as per system recommendation
trayIcon.setImageAutoSize(true);
try{
systemTray.add(trayIcon);
}catch(AWTException awtException){
awtException.printStackTrace();
}
int result;
MSG msg = new MSG();
while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
if (result == -1) {
System.err.println("error in get message");
break;
}
else {
System.err.println("got message");
lib.TranslateMessage(msg);
lib.DispatchMessage(msg);
}
}
lib.UnhookWindowsHookEx(hhk);
}
}
我没有任何使用 JNA 的经验,但是您的代码有几处错误 - 我认为我没有全部理解,但这里有一些:
close.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); quit=true; } });
quit=true
将永远无法到达,因为您的程序exit()
s 才到达那里。
2.
new Thread() {
public void run() {
while (!quit) {
try { Thread.sleep(10); } catch(Exception e) { }
}
System.err.println("unhook and exit");
lib.UnhookWindowsHookEx(hhk);
System.exit(0);
}
}.start();
没有任何意义,因为 quit
永远不会是 true
。同时旋转一个变量来检测变化会严重减慢你的应用程序(特别是睡眠时间为 10 毫秒)。为什么不在您的 ActionListener
中取消挂钩?
-
3.
while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
这里我不太确定,因为我没有使用 JNA 和 windows 事件系统的经验。该方法等待发送到指定 window 的消息,但由于您没有指定任何消息(第二个参数是 null
),我认为您永远不会收到消息。
- 对于每个回调,您都在创建一个新的
JFrame
,但在方法结束时,您仅使用frame.setVisible(false);
隐藏它。因为它仍然被各种 Swing-类 引用,所以它永远不会被垃圾收集。这会造成内存泄漏,从而减慢您的应用程序。您将不得不调用frame.dispose()
来摆脱它。