【问题标题】:Java JNA- Jar application hangs in 32 bit windows systemJava JNA-Jar 应用程序在 32 位 Windows 系统中挂起
【发布时间】:2016-01-17 09:53:07
【问题描述】:

这是一个屏幕截图应用程序。使用 1.8 JDK 编译,在 64 位系统中运行良好,但在 32 位系统中的两次迭代中会出现滞后和挂起。

基本上,这个应用程序使用机器人类截取屏幕截图,从用户那里获取文件名,这是一个 URL。截断并删除其中的所有非法字符,并使用带有时间戳作为前缀的另存为对话框将其保存。

我正在使用 Windows Low 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);

    }
 }

【问题讨论】:

  • 您的开关盒没有break;
  • 据我所知,switch 语句不需要中断。
  • 那么您是否尝试过调试应用程序,或对其进行分析以查看它在哪里花费了所有时间?
  • 我一直在这样做。 Windows 低级键扫描我按下的每个输入。可能是这个原因。

标签: java jframe 32bit-64bit jna keyhook


【解决方案1】:

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

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

【讨论】:

  • 非常感谢您列出可能的原因。已经处理了第 4 点,第 1 点,正在纠正 2 和 3。再次感谢,我会调查并回复 :)
  • 纠正了错误。 JFrame 仍然没有出现在第三次迭代中,即当我第三次按 PrtSc 时,有什么建议吗?我会尽快更新我的代码。
猜你喜欢
  • 1970-01-01
  • 2015-08-11
  • 2012-05-14
  • 2012-09-01
  • 2013-05-23
  • 2014-07-05
  • 1970-01-01
  • 2013-09-01
  • 2012-07-11
相关资源
最近更新 更多