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, но есть несколько вещей, которые не верны в вашем коде - я не думаю, что получил их все, но вот некоторые:

  1. close.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
    
        System.exit(0);   
        quit=true;
    }
    });
    

    quit=true никогда не будет достигнут, потому что ваша программа exit()до того, как он пойдет туда.

  2. 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Я не думаю, что вы когда-либо получите.

  1. Для каждого обратного вызова вы создаете новый JFrame но в конце метода вы только скрываете его, используя frame.setVisible(false);, Поскольку на него все еще ссылаются различные классы Swing, он никогда не будет собирать мусор. Это создает утечку памяти, которая замедляет работу вашего приложения. Вам придется позвонить frame.dispose() чтобы избавиться от этого.
Другие вопросы по тегам