如何使用jna在java中获得chrome进程的句柄

30byixjq  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(596)

我是jna新手,我需要使用java和jna拍摄chrome窗口的截图,我已经有了使用以下代码拍摄给定窗口截图的功能:

  1. public BufferedImage capture(WinDef.HWND hWnd) {
  2. WinDef.HDC hdcWindow = User32.INSTANCE.GetDC(hWnd);
  3. WinDef.HDC hdcMemDC = GDI32.INSTANCE.CreateCompatibleDC(hdcWindow);
  4. WinDef.RECT bounds = new WinDef.RECT();
  5. User32Extra.INSTANCE.GetClientRect(hWnd, bounds);
  6. int width = bounds.right - bounds.left;
  7. int height = bounds.bottom - bounds.top;
  8. WinDef.HBITMAP hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcWindow, width, height);
  9. WinNT.HANDLE hOld = GDI32.INSTANCE.SelectObject(hdcMemDC, hBitmap);
  10. GDI32Extra.INSTANCE.BitBlt(hdcMemDC, 0, 0, width, height, hdcWindow, 0, 0, WinGDIExtra.SRCCOPY);
  11. GDI32.INSTANCE.SelectObject(hdcMemDC, hOld);
  12. GDI32.INSTANCE.DeleteDC(hdcMemDC);
  13. WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO();
  14. bmi.bmiHeader.biWidth = width;
  15. bmi.bmiHeader.biHeight = -height;
  16. bmi.bmiHeader.biPlanes = 1;
  17. bmi.bmiHeader.biBitCount = 32;
  18. bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
  19. Memory buffer = new Memory(width * height * 4);
  20. GDI32.INSTANCE.GetDIBits(hdcWindow, hBitmap, 0, height, buffer, bmi, WinGDI.DIB_RGB_COLORS);
  21. BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  22. image.setRGB(0, 0, width, height, buffer.getIntArray(0, width * height), 0, width);
  23. GDI32.INSTANCE.DeleteObject(hBitmap);
  24. User32.INSTANCE.ReleaseDC(hWnd, hdcWindow);
  25. return image;
  26. }

然后使用以下代码保存BuffereImage:

  1. BufferedImage image;
  2. WinDef.HWND hWnd = User32.INSTANCE.FindWindow(null, "notepad - untitled");
  3. image = capture(hWnd);
  4. File outputfile = new File("image.jpg");
  5. try {
  6. ImageIO.write(image, "jpg", outputfile);
  7. } catch (IOException e) {
  8. e.printStackTrace();
  9. }

这适用于某些应用程序,例如记事本,但不适用于chrome,对于chrome,它只是抛出一个非法参数异常,因为程序试图捕获宽度和高度基本为0的屏幕截图,因为找不到进程,所以完全异常如下:

  1. Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Allocation size must be greater than zero
  2. at com.sun.jna.Memory.<init>(Memory.java:111)
  3. at de.xliquid.stadiarpc.Main.capture(Main.java:103)
  4. at de.xliquid.stadiarpc.Main$1.run(Main.java:56)
  5. at com.sun.javafx.scene.KeyboardShortcutsHandler.processAccelerators(KeyboardShortcutsHandler.java:347)
  6. at com.sun.javafx.scene.KeyboardShortcutsHandler.dispatchBubblingEvent(KeyboardShortcutsHandler.java:163)
  7. at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
  8. at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
  9. at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
  10. at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
  11. at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
  12. at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
  13. at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
  14. at javafx.event.Event.fireEvent(Event.java:198)
  15. at javafx.scene.Scene$KeyHandler.process(Scene.java:3964)
  16. at javafx.scene.Scene$KeyHandler.access$1800(Scene.java:3910)
  17. at javafx.scene.Scene.impl_processKeyEvent(Scene.java:2040)
  18. at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2501)
  19. at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:217)
  20. at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:149)
  21. at java.security.AccessController.doPrivileged(Native Method)
  22. at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent$357(GlassViewEventHandler.java:248)
  23. at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
  24. at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:247)
  25. at com.sun.glass.ui.View.handleKeyEvent(View.java:546)
  26. at com.sun.glass.ui.View.notifyKey(View.java:966)
  27. at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
  28. at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
  29. at java.lang.Thread.run(Thread.java:748)

我试着使用当前的chrome标题,但没有成功,我认为最好的解决方案是只获得chrome的第一个选项卡的句柄。遗憾的是,我真的不知道从哪里开始。有人能告诉我我能做什么吗?提前谢谢。

ni65a41a

ni65a41a1#

jna的 WindowUtils 在这里上课是有帮助的。这个 getAllWindows() 方法将返回 List<DesktopWindow> 每个 DesktopWindow 示例包括标题(与chrome进程匹配)和 HWND 那扇Windows的把手。
这个 DesktopWindow 也有一个 Rectangle 使用位置和尺寸标注,因此您可以从桌面本身复制适当的尺寸标注,例如下面这个简单的一行:

  1. BufferedImage screenShot = new Robot().createScreenCapture(rectangle);

这个问题的答案确定了拍摄整个窗口截图的多个其他选项;简单地替换 Rectangle 你从 DesktopWindow 适当地初始化(或者使用上面的代码和矩形的尺寸)。
或者,如果您不需要 WindowUtils 类,您可以更直接地使用winapi的 EnumWindows 函数直接迭代窗口并仅捕获所需的信息。这就是函数 WindowUtils 在内部使用,所以它的源代码将是一个很好的简化起点。

相关问题