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 的经验,但是您的代码有几处错误 - 我认为我没有全部理解,但这里有一些:

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

    quit=true 将永远无法到达,因为您的程序 exit()s 才到达那里。

  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 事件系统的经验。该方法等待发送到指定 window 的消息,但由于您没有指定任何消息(第二个参数是 null),我认为您永远不会收到消息。

  1. 对于每个回调,您都在创建一个新的 JFrame,但在方法结束时,您仅使用 frame.setVisible(false); 隐藏它。因为它仍然被各种 Swing-类 引用,所以它永远不会被垃圾收集。这会造成内存泄漏,从而减慢您的应用程序。您将不得不调用 frame.dispose() 来摆脱它。