java - 如何使用 JNA 在 java 中获取 chrome 进程的句柄
问题描述
我是 JNA 的新手,我需要使用 java 和 JNA 截取 chrome 窗口的屏幕截图,我已经拥有使用以下代码截取给定窗口的功能:
public BufferedImage capture(WinDef.HWND hWnd) {
WinDef.HDC hdcWindow = User32.INSTANCE.GetDC(hWnd);
WinDef.HDC hdcMemDC = GDI32.INSTANCE.CreateCompatibleDC(hdcWindow);
WinDef.RECT bounds = new WinDef.RECT();
User32Extra.INSTANCE.GetClientRect(hWnd, bounds);
int width = bounds.right - bounds.left;
int height = bounds.bottom - bounds.top;
WinDef.HBITMAP hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcWindow, width, height);
WinNT.HANDLE hOld = GDI32.INSTANCE.SelectObject(hdcMemDC, hBitmap);
GDI32Extra.INSTANCE.BitBlt(hdcMemDC, 0, 0, width, height, hdcWindow, 0, 0, WinGDIExtra.SRCCOPY);
GDI32.INSTANCE.SelectObject(hdcMemDC, hOld);
GDI32.INSTANCE.DeleteDC(hdcMemDC);
WinGDI.BITMAPINFO bmi = new WinGDI.BITMAPINFO();
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -height;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
Memory buffer = new Memory(width * height * 4);
GDI32.INSTANCE.GetDIBits(hdcWindow, hBitmap, 0, height, buffer, bmi, WinGDI.DIB_RGB_COLORS);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
image.setRGB(0, 0, width, height, buffer.getIntArray(0, width * height), 0, width);
GDI32.INSTANCE.DeleteObject(hBitmap);
User32.INSTANCE.ReleaseDC(hWnd, hdcWindow);
return image;
}
然后我使用以下代码保存缓冲图像:
BufferedImage image;
WinDef.HWND hWnd = User32.INSTANCE.FindWindow(null, "notepad - untitled");
image = capture(hWnd);
File outputfile = new File("image.jpg");
try {
ImageIO.write(image, "jpg", outputfile);
} catch (IOException e) {
e.printStackTrace();
}
这适用于某些应用程序,例如记事本,但不适用于 chrome,对于 chrome,它只会引发非法参数异常,因为程序正在尝试捕获宽度和高度基本上为 0 的屏幕截图,因为找不到该进程,完整例外是:
Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: Allocation size must be greater than zero
at com.sun.jna.Memory.<init>(Memory.java:111)
at de.xliquid.stadiarpc.Main.capture(Main.java:103)
at de.xliquid.stadiarpc.Main$1.run(Main.java:56)
at com.sun.javafx.scene.KeyboardShortcutsHandler.processAccelerators(KeyboardShortcutsHandler.java:347)
at com.sun.javafx.scene.KeyboardShortcutsHandler.dispatchBubblingEvent(KeyboardShortcutsHandler.java:163)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$KeyHandler.process(Scene.java:3964)
at javafx.scene.Scene$KeyHandler.access$1800(Scene.java:3910)
at javafx.scene.Scene.impl_processKeyEvent(Scene.java:2040)
at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2501)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:217)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:149)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent$357(GlassViewEventHandler.java:248)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:247)
at com.sun.glass.ui.View.handleKeyEvent(View.java:546)
at com.sun.glass.ui.View.notifyKey(View.java:966)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$152(WinApplication.java:177)
at java.lang.Thread.run(Thread.java:748)
我尝试使用当前的 chrome 标题,但这不起作用,我认为最好的解决方案是获取 chrome 的第一个选项卡的句柄。可悲的是,我真的不知道从哪里开始。谁能告诉我我能做什么?提前致谢。
解决方案
JNA 的WindowUtils
课程在这里可能会有所帮助。该getAllWindows()
方法将返回一个List<DesktopWindow>
其中每个DesktopWindow
实例都包含标题(与您的 Chrome 进程匹配)和该HWND
窗口句柄的位置。
DesktopWindow
也有一个带有位置和大小的Rectangle
尺寸,因此您可以从桌面本身复制适当的尺寸,例如这个简单的单行:
BufferedImage screenShot = new Robot().createScreenCapture(rectangle);
这个 StackOverlow 问题的答案确定了用于截取整个窗口的多个其他选项;只需适当地替换Rectangle
您从DesktopWindow
类派生的(或使用您自己的代码与矩形的尺寸)。
或者,如果您不需要WindowUtils
类中的所有信息,您可以更直接地使用 WinAPI 的EnumWindows
函数来直接迭代窗口并仅捕获您需要的信息。这是WindowUtils
内部使用的函数,因此它的源代码将是一个很好的简化起点。
推荐阅读
- python - 解决python和numpy/scipy中的两步插值
- php - PHP逐步通过大数组进行迭代
- python - 使用 Table.read_table 比使用 pd.read_csv 有优势吗?
- java - ElasticSearch 突然死机,无法响应
- node.js - 如何在浏览器中查看我的固定 IP 的 Express 应用程序
- c++ - 使用远程工具链时,CLion 导航到错误的定义路径
- python - 如何在 python 中使用 SKLearn 对多项逻辑回归进行假设检验?
- laravel - 在 spatie/media-library 的转换中对 PNG 的透明度支持
- ios - UIView:在相同的给定方向上无限动画渐变?
- r - 当响应为多个数值时,如何处理stablelearner的函数stabletre?