@@ -286,29 +286,42 @@ PyImaging_DisplayModeWin32(PyObject *self, PyObject *args) {
286286/* -------------------------------------------------------------------- */
287287/* Windows screen grabber */
288288
289+ typedef HANDLE (__stdcall * Func_GetWindowDpiAwarenessContext )(HANDLE );
289290typedef HANDLE (__stdcall * Func_SetThreadDpiAwarenessContext )(HANDLE );
290291
291292PyObject *
292293PyImaging_GrabScreenWin32 (PyObject * self , PyObject * args ) {
293- int x = 0 , y = 0 , width , height ;
294- int includeLayeredWindows = 0 , all_screens = 0 ;
294+ int x = 0 , y = 0 , width = -1 , height ;
295+ int includeLayeredWindows = 0 , screens = 0 ;
295296 HBITMAP bitmap ;
296297 BITMAPCOREHEADER core ;
297298 HDC screen , screen_copy ;
299+ HWND wnd ;
298300 DWORD rop ;
299301 PyObject * buffer ;
300- HANDLE dpiAwareness ;
302+ HANDLE dpiAwareness = NULL ;
301303 HMODULE user32 ;
304+ Func_GetWindowDpiAwarenessContext GetWindowDpiAwarenessContext_function ;
302305 Func_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContext_function ;
303306
304- if (!PyArg_ParseTuple (args , "|ii" , & includeLayeredWindows , & all_screens )) {
307+ if (!PyArg_ParseTuple (
308+ args , "|ii" F_HANDLE , & includeLayeredWindows , & screens , & wnd
309+ )) {
305310 return NULL ;
306311 }
307312
308313 /* step 1: create a memory DC large enough to hold the
309314 entire screen */
310315
311- screen = CreateDC ("DISPLAY" , NULL , NULL , NULL );
316+ if (screens == -1 ) {
317+ screen = GetDC (wnd );
318+ if (screen == NULL ) {
319+ PyErr_SetString (PyExc_OSError , "unable to get device context for handle" );
320+ return NULL ;
321+ }
322+ } else {
323+ screen = CreateDC ("DISPLAY" , NULL , NULL , NULL );
324+ }
312325 screen_copy = CreateCompatibleDC (screen );
313326
314327 // added in Windows 10 (1607)
@@ -317,15 +330,28 @@ PyImaging_GrabScreenWin32(PyObject *self, PyObject *args) {
317330 SetThreadDpiAwarenessContext_function = (Func_SetThreadDpiAwarenessContext
318331 )GetProcAddress (user32 , "SetThreadDpiAwarenessContext" );
319332 if (SetThreadDpiAwarenessContext_function != NULL ) {
333+ GetWindowDpiAwarenessContext_function = (Func_GetWindowDpiAwarenessContext
334+ )GetProcAddress (user32 , "GetWindowDpiAwarenessContext" );
335+ if (screens == -1 && GetWindowDpiAwarenessContext_function != NULL ) {
336+ dpiAwareness = GetWindowDpiAwarenessContext_function (wnd );
337+ }
320338 // DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = ((DPI_CONTEXT_HANDLE)-3)
321- dpiAwareness = SetThreadDpiAwarenessContext_function ((HANDLE )- 3 );
339+ dpiAwareness = SetThreadDpiAwarenessContext_function (
340+ dpiAwareness == NULL ? (HANDLE )- 3 : dpiAwareness
341+ );
322342 }
323343
324- if (all_screens ) {
344+ if (screens == 1 ) {
325345 x = GetSystemMetrics (SM_XVIRTUALSCREEN );
326346 y = GetSystemMetrics (SM_YVIRTUALSCREEN );
327347 width = GetSystemMetrics (SM_CXVIRTUALSCREEN );
328348 height = GetSystemMetrics (SM_CYVIRTUALSCREEN );
349+ } else if (screens == -1 ) {
350+ RECT rect ;
351+ if (GetClientRect (wnd , & rect )) {
352+ width = rect .right ;
353+ height = rect .bottom ;
354+ }
329355 } else {
330356 width = GetDeviceCaps (screen , HORZRES );
331357 height = GetDeviceCaps (screen , VERTRES );
@@ -337,6 +363,10 @@ PyImaging_GrabScreenWin32(PyObject *self, PyObject *args) {
337363
338364 FreeLibrary (user32 );
339365
366+ if (width == -1 ) {
367+ goto error ;
368+ }
369+
340370 bitmap = CreateCompatibleBitmap (screen , width , height );
341371 if (!bitmap ) {
342372 goto error ;
@@ -382,15 +412,23 @@ PyImaging_GrabScreenWin32(PyObject *self, PyObject *args) {
382412
383413 DeleteObject (bitmap );
384414 DeleteDC (screen_copy );
385- DeleteDC (screen );
415+ if (screens == -1 ) {
416+ ReleaseDC (wnd , screen );
417+ } else {
418+ DeleteDC (screen );
419+ }
386420
387421 return Py_BuildValue ("(ii)(ii)N" , x , y , width , height , buffer );
388422
389423error :
390424 PyErr_SetString (PyExc_OSError , "screen grab failed" );
391425
392426 DeleteDC (screen_copy );
393- DeleteDC (screen );
427+ if (screens == -1 ) {
428+ ReleaseDC (wnd , screen );
429+ } else {
430+ DeleteDC (screen );
431+ }
394432
395433 return NULL ;
396434}
0 commit comments