3

Current situation: I have a program called "NoxPlayer" which is basically an android emulator. I also have a c++ program which locates the window handle of said NoxPlayer and makes a bitmap of the current state of the window and saves it to the clipboard.

But here comes the problem.


This is how the program looks to me: NoxPlayer

And this is what it saves in the clipboard: Clipboard

But this is what i want: Image


I could have simple cut the top part of the bitmap but what i wish to try and do is get the inner part of the window as seen here Image without cutting the bitmap.

I first tried going down the window hierarchy and getting the bitmap of child windows but what i got was black bitmaps as seen here: Black window

Window hierarchy as seen from Microsoft Spy++: Hierarchy

The ones i marked around with red color are the ones i tried to get a bitmap from, since ScreenBoardClassWindow and all its children fall into this Box when checking their position by highlighting them in Microsoft Spy++


This is the code i used to create a bitmap and save it to the clipboard:

  RECT rc;
  GetClientRect(NoxHandle, &rc);

  //create
  HDC hdcScreen = GetDC(NULL);
  HDC hdc = CreateCompatibleDC(hdcScreen);
  HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen,rc.right - rc.left, rc.bottom - rc.top);
  SelectObject(hdc, hbmp);

  //Print to memory hdc
  PrintWindow(NoxHandle, hdc, PW_CLIENTONLY);

  //copy to clipboard
  OpenClipboard(NULL);
  EmptyClipboard();
  SetClipboardData(CF_BITMAP, hbmp);
  CloseClipboard();

  //release
  DeleteDC(hdc);
  DeleteObject(hbmp);
  ReleaseDC(NULL, hdcScreen);

Code is taken from here: Link


Thanks in advance


EDIT The window i use to currently get the bitmap from is the Program Parent window "NoxPlayer". When using any of the children windows I get the black bitmap problem.

  • So are you able to use Spy++ and find the right window with red highlights around it? Is it the `Child_1` window? – Barmak Shemirani Feb 18 '18 at 18:23
  • @BarmakShemirani yes i am able to use Spy++ and find the right window. But there are multiple windows at the same position and when trying to get the bitmap from them i end up with a black bitmap. However if i use the Parent window of the application i am able to get what i want, but with the need of cutting the top off –  Feb 18 '18 at 18:25
  • @BarmakShemirani Just realised i might have been unclear about a few window sizes. While the parent window covers the entire program, the others do not. The window that covers what i want are "ScreenBoardClassWindow" and "QWidgetClassWindow" since they cover this: [link](https://imgur.com/KkGlmp5) But the children of "QWidgetClassWindow" cover this: [link](https://imgur.com/tlnA5eo) –  Feb 18 '18 at 18:32

1 Answers1

2

Find the right window, example, QWidgetClassWindow then use GetWindowRect to find the coordinates in relation to desktop window. Use BitBlt instead of PrintWindow.

With this example the target application must be visible on the screen. It should not be obstructed by other windows.

RECT rc;
HWND hwnd = h_QWidgetClassWindow;
GetWindowRect(hwnd, &rc);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;

Sleep(3000);
//create
HDC hdc = GetDC(0);
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP hbmp = CreateCompatibleBitmap(hdc, w, h);
HBITMAP oldbmp = (HBITMAP)SelectObject(memdc, hbmp);

BitBlt(memdc, 0, 0, w, h, hdc, rc.left, rc.top, SRCCOPY);
SelectObject(memdc, oldbmp);

//copy to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbmp);
CloseClipboard();

//release
DeleteDC(memdc);
DeleteObject(hbmp);
ReleaseDC(0, hdc);

Also make sure your application is DPI aware, so that it gets the right coordinates.

Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • It indeed works now for some reason. I'm now interested to know why using BitBlt actually gets the correct bitmap result when using it on a child window while using PrintWindow does not. I now get [this](https://imgur.com/HGIKVTI) without any cutting done. –  Feb 18 '18 at 19:00
  • Applications made by Qt are not standard Win32 programs, Qt does it's own thing with custom controls. `BitBlt(memdc,...., hdc_desktop,...)` will copy whatever is painted on desktop, so it doesn't depend on how Qt is painting. But `BitBlt` may not work either if source DC is not desktop DC. – Barmak Shemirani Feb 18 '18 at 19:35
  • Since BitBlt copies whatever is painted on the desktop, something covering will also be shown on the bitmap. Could this be avoided? Currently i just SetForegroundWindow() before making a bitmap. –  Feb 18 '18 at 22:24
  • The only alternative is `DwmUpdateThumbnailProperties` which will draw the source window on your own top-level window, then you have to `BitBlt` the desktop DC again. So the source window is again painted on screen. But that's a lot of work with no real benefit. `SetForegroundWindow` is fine. Use `GetWindowPlacement` to restore window positions if needed. – Barmak Shemirani Feb 18 '18 at 23:10