Java JNA-Jar应用程序在32位Windows系统中挂起

标签 java jframe 32bit-64bit jna keyhook

这是一个屏幕截图应用程序。使用 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);

    }
 }

最佳答案

我没有任何使用 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。另外,旋转变量来检测变化会严重减慢应用程序的速度(特别是 sleep 时间为 10 毫秒时)。为什么不在您的 ActionListener 中取消 Hook ?

3.
    while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {

在这里我不太确定,因为我没有 JNA 和 Windows 事件系统的经验。该方法等待发送到指定窗口的消息,但由于您没有指定任何消息(第二个参数为 null),我认为您永远不会收到消息。

  • 对于每个回调,您都会创建一个新的 JFrame,但在方法末尾,您仅使用 frame.setVisible(false); 隐藏它。由于它仍然被各种 Swing 类引用,因此它永远不会被垃圾收集。这会造成内存泄漏,从而降低应用程序的速度。您必须调用 frame.dispose() 来摆脱它。
  • 关于Java JNA-Jar应用程序在32位Windows系统中挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33207839/

    相关文章:

    java - 为什么这个 JPanel 不符合指定的大小?

    c++ - 将 unsigned int 的指针传递给 long int 的指针

    windows - 64位Windows在驱动开发方面的数据对齐

    visual-studio - 我想在 64 位模式下运行我的 Visual Studio

    java - jframe 中的 UnsupportedOperationException : Not supported yet.

    java - 尝试使用 SQL Server 身份验证连接到 SQL Server 2008 Express 数据库始终会导致 "Login failed for user ' .. .'."

    java - Hibernate Criteria 查询 select where 子句

    java - GATT 特性不改变值

    java - 使用索引递归地从 LinkedList 中删除 Odds

    Java 图形用户界面 : Display Area and 8 buttons