Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting screenshot via printwindow not redrawing if laptop screen off

My goal is to take screenshots off an application while the laptop screen is off, but instead the screenshot will always be the same as just before turning off the screen. It does not redraw itself once the screen is off, and remains frozen.

I'm obtaining a screenshot using printwindow from Python (using method described here: Python Screenshot of inactive window PrintWindow + win32gui

This method works nicely as long as I have my laptop screen on, but if I turn it off, it simply returns the last image before the screen turned off. I've tried using win32gui.RedrawWindow, hoping that this would force a redraw, but I haven't gotten it to work, even trying all the different flags. I've also tried getting screenshots via pyautogui, but this also has the same problem. Is there any way to redraw the application while the laptop screen is off?

like image 217
Nulinspiratie Avatar asked Mar 11 '18 07:03

Nulinspiratie


Video Answer


1 Answers

It would be nice if there were a straightforward way to do what you want to do, but unfortunately it's just not possible without some convoluted low-level work.

In the underlying WinAPI, native windows redraw themselves only when they receive WM_PAINT messages, and they only receive WM_PAINT messages if they are visible. They don't get the messages if they're behind another window, or if they're dragged off screen, or minimized, or their visibility is set to False. They also aren't visible when the screen is off. Since they aren't visible, they simply never get told to redraw themselves. That's why the screen capture image doesn't change after the screen is turned off.

There is no command you can issue that will override this -- it is implemented as a fundamental part of the windowing paradigm.

One solution is to have the application paint itself in something that's not a window (e.g., a dialog box) and capture that rather than capturing the screen. You could also modify the application by overriding OnPaint and using a timer to invalidate and call your OnPaint function periodically (since WM_PAINT messages won't be received).

If it were me I'd override OnPaint, make my application draw itself to a background context bitmap rather than the normal window, then use a timer to invalidate and redraw periodically and just take the bitmap of the background context whenever I wanted to capture the output.

If you don't own the code for the applications that are running, you may still be able to get applications to redraw themselves by running everything in a virtual machine. I've done that successfully for headless computing in the past, but it was many OS versions ago and things may be different now, so YMMV...

Information on manual screenshots under VMWare is here.

Information on programmatic screenshots under Hyper-V is here.

like image 67
Craig.Feied Avatar answered Sep 27 '22 22:09

Craig.Feied