I am using WinAPI to capture the windows in Java.
public static BufferedImage capture(Pointer hWnd2, String wText) {
HWND hWnd = new HWND(hWnd2);
boolean success;
if(User32Extra.INSTANCE.IsIconic(hWnd))
{
success= User32Extra.INSTANCE.ShowWindow(hWnd, 4);
System.err.println(success);
System.err.println(wText+Native.getLastError());
}
HDC hdcWindow2 = User32.INSTANCE.GetDC(hWnd);
HDC hdcMemDC = GDI32.INSTANCE.CreateCompatibleDC(hdcWindow2);
success = User32Extra.INSTANCE.PrintWindow(hWnd,hdcWindow2,1);
RECT bounds = new RECT();
RECT bounds1 = new RECT();
User32Extra.INSTANCE.GetWindowRect(hWnd, bounds);
User32Extra.INSTANCE.GetClientRect(hWnd, bounds1);
int extraGap = (bounds.right-bounds.left-bounds1.right);
int width = bounds.right-bounds.left-extraGap;
int height = bounds.bottom-bounds.top-extraGap ;
HBITMAP hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcWindow2, width, height);
HANDLE hOld = GDI32.INSTANCE.SelectObject(hdcMemDC, hBitmap);
GDI32Extra.INSTANCE.BitBlt(hdcMemDC,0, 0, width, height, hdcWindow2, bounds.left+bounds1.right-bounds.right+extraGap, bounds.top+bounds1.bottom-bounds.bottom+extraGap, WinGDIExtra.SRCCOPY);
GDI32.INSTANCE.SelectObject(hdcMemDC, hOld);
BITMAPINFO bmi = new 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(hdcWindow2, hBitmap, 0, height, buffer, bmi, WinGDI.DIB_RGB_COLORS);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
GDI32.INSTANCE.DeleteObject(hBitmap);
GDI32.INSTANCE.DeleteDC(hdcMemDC);
User32.INSTANCE.ReleaseDC(hWnd, hdcWindow2);
return image;
}
This code captures the HWND specified window. But if the user opens the context menu or menu bar options. Those are not being captured.
How to capture context menu of the window?
I would use
GetDesktopWindow()
to capture entire screen, then pass window coordinates toBitBlt
to copy only target window with all overlays (including context menu)This method, however, will capture other window if it is overlapping our target window. It is probably sufficient if you know that window is active or have context menu opened (because it will enforce it to be foreground) .
Another approach is a bit hacky, but it works for other scenarios. We can check if there are any windows with class name
#32768
(class for popup menus). If there is, we check whether our target window is foreground one, and then we can copy it to our target bitmap on top of our window.For EnumWindows you have to add following import:
and definition: