0

Why should taking a screenshot give a black window, particularly if it's visible? That's a short way to pose this question

I glued together some other python recipes in SO to take a screenshot of just the visible window of a particular process. For instance, if I wanted to capture a dos prompt I would pass the string command, and if I wanted to capture SO in a chrome browser i would pass a string like stack. Whilst this worked for most applications I tried, for Google Chrome I just had a black screen returned. So I checked to see if it had a visible child window... it did but capturing this didn't work either, I don't understand at all why this failed. Can anyone help out? If I'm using the underlying windows API I am lost as to why it should fail.

import win32gui
import win32ui
import win32con
import time
import sys
from PIL import Image
from PIL import ImageChops

hw = []
bm = []
abc = 'abcdefghijklmnopqrstuvwxyz'
pos = 0
target = sys.argv[1]
print('target:',target)
baby = 0

def screenshot(hwnd):
  print ( hex( hwnd ), win32gui.GetWindowText( hwnd ) )
  l,t,r,b=win32gui.GetWindowRect(hwnd)
  h=b-t
  w=r-l
  hDC = win32gui.GetWindowDC(hwnd)
  myDC=win32ui.CreateDCFromHandle(hDC)
  newDC=myDC.CreateCompatibleDC()

  amap = win32ui.CreateBitmap()
  amap.CreateCompatibleBitmap(myDC, w, h)

  newDC.SelectObject(amap)

  win32gui.SetForegroundWindow(hwnd)
  time.sleep(0.05)
  newDC.BitBlt((0,0),(w, h) , myDC, (0,0), win32con.SRCCOPY)
  amap.Paint(newDC)
  amap.SaveBitmapFile(newDC, abc[pos] + '.bmp')
  return 1

def winEnumHandler( hwnd, ctx ):
  if win32gui.IsWindowVisible( hwnd ):
    if len( win32gui.GetWindowText( hwnd ) ) > 2:
      print ( hex( hwnd ), win32gui.GetWindowText( hwnd ) )
      hw.append(hwnd)

def winEnumHandlerStrict( hwnd, ctx ):
  if win32gui.IsWindowVisible( hwnd ):
    if target.lower() in win32gui.GetWindowText( hwnd ).lower() :
      print ( hex( hwnd ), win32gui.GetWindowText( hwnd ) )
      hw.append(hwnd)
    l,t,r,b=win32gui.GetWindowRect(hwnd)
    print(str(l),str(t),str(r),str(b))

def enumBebe(hwnd, ctx ):
  if win32gui.IsWindowVisible( hwnd ):
    print('visible child', hwnd)
    baby = hwnd
    print ( hex( hwnd ), win32gui.GetWindowText( hwnd ) )
    l,t,r,b=win32gui.GetWindowRect(hwnd)
    print(str(l),str(t),str(r),str(b))

  else:
    print('invisible child', hwnd)
win32gui.EnumWindows( winEnumHandlerStrict, None )

print('\n---\n',hw)

win32gui.EnumChildWindows(hw[1],enumBebe,None)

print(time.time())
for x in range(0,10):
  #pos = pos + screenshot(hw[1]) # command line is always first process to contain name of string we pass in
  pos = pos + screenshot(baby)
print(time.time())

image_one = Image.open( abc[0] + '.bmp' )
image_two = Image.open( abc[6] + '.bmp' )

diff = ImageChops.difference(image_one, image_two)
print( len(set(ImageChops.difference(image_one , image_two ).getdata()) ))
InSync
  • 4,851
  • 4
  • 8
  • 30
SlightlyKosumi
  • 701
  • 2
  • 8
  • 24
  • 2
    There was a question about this just a few days ago and the problem seems to be with BitBlt not being able to capture hardware-accelerated windows. See [this question](https://stackoverflow.com/questions/76373625/pywin32-cannot-capture-certain-windows-giving-black-screen-python-windows) – Squarish Jun 04 '23 at 17:25
  • That looks very promising, will give it a try soon – SlightlyKosumi Jun 04 '23 at 17:33
  • That does indeed work. Thanks squarish. – SlightlyKosumi Jun 05 '23 at 09:52

0 Answers0