2013-12-16 70 views
1

我已經將一個簡單的python腳本放在一起,該腳本應該截取其名稱包含特定字符串的窗口。我使用的代碼如下,winAPI BitBlt故障捕獲窗口僅適用於某些應用程序

 

import win32gui, win32ui, win32con 
import PIL.Image 

def getWindowHandle(name):   
    windowList = [] 
    win32gui.EnumWindows(lambda hwnd, wndList: 
          wndList.append((win32gui.GetWindowText(hwnd), hwnd)), 
         windowList) 

    for pair in windowList: 
     if name in pair[0]: 
      return pair[1] 

    return None 


class Window(): 
    def __init__(self, hwnd = None): 
     if not hwnd: return 

     l, t, r, b = win32gui.GetClientRect(hwnd) 
     sl, st, _, _ = win32gui.GetWindowRect(hwnd) 
     cl, ct  = win32gui.ClientToScreen(hwnd, (l, t)) 

     self.size  = (r - l, b - t) 
     self.position = (cl - sl, ct - st) 

     hDC = win32gui.GetWindowDC(hwnd) 
     self.windowDC = win32ui.CreateDCFromHandle(hDC) 
     self.newDC = self.windowDC.CreateCompatibleDC() 

     #win32gui.ReleaseDC(hwnd, hDC) 

     self.bitmap = win32ui.CreateBitmap() 
     self.bitmap.CreateCompatibleBitmap(self.windowDC, self.size[0], self.size[1]) 
     self.newDC.SelectObject(self.bitmap) 

    def __del__(self): 
     self.newDC.DeleteDC() 
     self.windowDC.DeleteDC() 
     del self.bitmap 

    def screenshot(self, location = 'C:\\Users\\Grieverheart\\Desktop\\'): 
     self.newDC.BitBlt((0, 0), self.size, self.windowDC, self.position, win32con.SRCCOPY) 
     self.bitmap.Paint(self.newDC) 

     bmpinfo = self.bitmap.GetInfo() 
     bmpstr = self.bitmap.GetBitmapBits(True) 
     im = PIL.Image.frombuffer('RGB', self.size, bmpstr, 'raw', 'BGRX', 0, 1) 
     try: 
      im.save(location + 'test.png', 'PNG') 
     except IOError: 
      return 


def main(): 
    handle = getWindowHandle("Blender") 
    if not handle: return 

    window = Window(handle) 
    window.screenshot() 

if __name__ == "__main__": 
    main() 
 

該腳本爲我提供了一些應用程序的黑色截圖,如Blender或DOSBox。

有誰知道是什麼原因導致這個問題只有一些應用程序,我怎麼能解決它?

編輯:這似乎我的問題可能與this後,雖然我不知道我必須做什麼來解決我的問題。我還想補充一點,我也嘗試添加CAPTUREBLT標誌,沒有任何區別。

+0

嘗試添加CAPTUREBLT標誌。 – Xearinox

+0

您是否在啓用Aero的情況下使用Windows Vista/7? –

回答

2

MSDN

BitBlt的返回,如果源和目的地設備上下文表示不同的裝置的錯誤。要在不同設備的DC之間傳輸數據,請通過調用GetDIBits將內存位圖轉換爲DIB。要將DIB顯示到第二個設備,請調用SetDIBits或StretchDIBits。

這是什麼意思?簡而言之,混合DWM(即Aero)和非GDI應用程序(例如OpenGL)使得BiBlt變得不可預知/不可靠。

再從MSDN

桌面合成功能,在Windows Vista中引入,從根本上改變屏幕上的應用程序的方式顯示像素。當啓用桌面組合時,單個窗口不再像以前版本的Windows中那樣直接繪製到屏幕或主顯示設備上。相反,他們的繪圖被重定向到視頻內存中的離屏表面,然後渲染成桌面圖像並顯示在顯示器上。

由於與DWM阻擊器具有這些know issues,您可以:

  1. 嘗試使用替代技術;你有a nice list here

  2. 您可以使用DwmEnableComposition(DWM_EC_DISABLECOMPOSITION);

嘗試禁用DWM(即暫時),看看有沒有適合你。但是,AFAIK可靠地獲取使用3D渲染(DirectX或OpenGL)的應用程序的內容的唯一方法是將自己注入進程並複製出位(請參見this answer for DirectX或掛鉤wglSwapBuffers並執行用於OpenGL的回讀glReadPixels