Java JNA- Jar-приложение зависает в 32-битной системе Windows
Вот скриншот приложения. Скомпилированный с 1.8 JDK, прекрасно работает в 64-битных системах, но в 32-битных системах отстает и зависает в двух итерациях.
В основном это приложение делает снимок экрана, используя класс робота, берет имя файла от пользователя, который является URL. Обрезает и удаляет все недопустимые символы из него и сохраняет его с помощью диалогового окна "Сохранить как" с меткой времени в качестве префикса.
Я использую Windows Key Level KeyHook для запуска скриншота с помощью клавиши PrtSc.
Ошибка в 32-битных системах: требуется только 2 снимка экрана, а затем он не отвечает, когда я нажимаю 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);
}
}
1 ответ
У меня нет опыта работы с JNA, но есть несколько вещей, которые не верны в вашем коде - я не думаю, что получил их все, но вот некоторые:
close.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); quit=true; } });
quit=true
никогда не будет достигнут, потому что ваша программаexit()
до того, как он пойдет туда. 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. Метод ожидает сообщений, отправленных в указанное окно, но так как вы не указываете ничего (второй параметр null
Я не думаю, что вы когда-либо получите.
- Для каждого обратного вызова вы создаете новый
JFrame
но в конце метода вы только скрываете его, используяframe.setVisible(false);
, Поскольку на него все еще ссылаются различные классы Swing, он никогда не будет собирать мусор. Это создает утечку памяти, которая замедляет работу вашего приложения. Вам придется позвонитьframe.dispose()
чтобы избавиться от этого.