2009-07-19 22 views
4

背景情報: このMFCアプリケーションはコード化されていて、ユーザーがプリントスクリーンにヒットしたときにスクリーンショットをかなり自動的に自動的に保存しています。 Alt + Print Screenキーを押します。私はWindows 7 RCを2週間使用していた今まで、Aeroに関するものを使用しています。Aero/DWMの特定のウィンドウを正確にスクリーンキャプチャする方法

問題: 標準のGetDC/BitBltメソッドを使用してウィンドウの内容をキャプチャしています。いくつかのウィンドウが開かれていても、通常のフルスクリーングラブを行っている間は、この方法で問題はありません。フォアグラウンドウィンドウ(Alt + PrintScreen)をキャプチャしようとすると、問題が発生します。

例の境界線があるべきあなたが見ることができるように2 http://indiecodelabs.com/extern/example2.jpg

、私は取得していごみ1つの http://indiecodelabs.com/extern/example1.jpg

例:ここでは2つの例です。これは上部に向かって目立つようになっています。ここでは、両方のスクリーンショットでツールバーの重複を見ることができます。

私は今これについて数え切れませんでした。私は、DWMではBitBtl/GetDCメソッドは動作しませんが、私たち(開発者) DWMで実行しているときにGoogleのアプリで同じ機能を維持できるようにする必要があります。

ご意見、ご指摘、ご鞭撻をよろしくお願い申し上げます。

+0

画像リンクの多くの謝罪は機能しません。ドメインを更新してイメージをバックアップするのを忘れたことはありません。 – enriquein

答えて

2

私が不幸にも正確な答えを知らないというのは素晴らしい質問です。私の最初のアイデアは、デスクトップ全体をつかんで興味深い部分を取り除くことでした。

私はQT 4.5のソースを掘り下げてどのように動作しているかを確認しました。 GetClientRectをGetWindowRectに切り替えてQT定型文を削除すると、必要なものが得られます。これは、しかしハックのように見えます:)参考


QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h) 
{ 
    RECT r; 
    GetClientRect(winId, &r); 
    if (w < 0) w = r.right - r.left; 
    if (h < 0) h = r.bottom - r.top; 
    // Create and setup bitmap 
    HDC display_dc = GetDC(0); 
    HDC bitmap_dc = CreateCompatibleDC(display_dc); 
    HBITMAP bitmap = CreateCompatibleBitmap(display_dc, w, h); 
    HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap); 

    // copy data 
    HDC window_dc = GetDC(winId); 
    BitBlt(bitmap_dc, 0, 0, w, h, window_dc, x, y, SRCCOPY); 

    // clean up all but bitmap 
    ReleaseDC(winId, window_dc); 
    SelectObject(bitmap_dc, null_bitmap); 
    DeleteDC(bitmap_dc); 

    QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap); 

    DeleteObject(bitmap); 
    ReleaseDC(0, display_dc); 

    return pixmap; 
} 
+0

これはうまくいくかもしれません。ありがとう、結果をフォローアップします。 – enriquein

+0

悲しいことに、状況に応じて、このアプローチは正確には機能しません。なんらかの理由で私は窓の上部の一部に欠けている。また、時々私は後ろの窓からぼかしを見ることができ、他の時には境界線を得ず、他の時は黒い境界線(デスクトップ色は黒に設定される)。 私はこのアプローチがうまくいくのは難しいと思っています。しかし、ありがとう。 – enriquein

+0

"私の最初のアイデアはデスクトップ全体をつかんで面白い部分を切り抜けることでした。"私はついにこのメソッドを試してみました。それは、既存のコードベースから3行のコードを変更することだけだったので、素晴らしい点があります。 – enriquein

3
BOOL CaptureWindow(const CString& filename) 
{ 
    HWND hWnd = NULL; 
    hWnd = ::GetForegroundWindow(); 
    if(!hWnd) 
    { 
     return FALSE; 
    } 
    CRect rect; 
    GetWindowRect(hWnd, &rect); 
    rect.NormalizeRect(); 
    return DoCapture(CPoint(rect.left, rect.top), CSize(rect.Width(), rect.Height()), filename); 
} 

BOOL DoCapture(const POINT& coords, const SIZE& areaSize, const CString& filename) 
{ 
    CDC dc; 
    HDC hdc = GetDC(NULL); // <-- We use this instead of GetWindowDC. 
          // This is the only thing I had to change other than 
          // getting the window coordinates in CaptureWindow() 
    dc.Attach(hdc); 

    // Create a memory DC into which the bitmap will be captured 
    CDC memDC; 
    memDC.CreateCompatibleDC(&dc); 

    // If there is already a bitmap, delete it as we are going to replace it 
    CBitmap bmp; 
    bmp.DeleteObject(); 

    ICONINFO info; 
    GetIconInfo((HICON)::GetCursor(), &info); 

    CURSORINFO cursor; 
    cursor.cbSize = sizeof(CURSORINFO); 
    GetCursorInfo(&cursor); 

    bmp.CreateCompatibleBitmap(&dc, areaSize.cx, areaSize.cy); 
    CBitmap * oldbm = memDC.SelectObject(&bmp); 

    // Before we copy the image in, we blank the bitmap to 
    // the background fill color 
    memDC.FillSolidRect(&CRect(0,0,areaSize.cx, areaSize.cy), RGB(255,255,255)); 

    // Copy the window image from the window DC into the memory DC 
    memDC.BitBlt(0, 0, areaSize.cx, areaSize.cy, &dc, coords.x, coords.y, SRCCOPY|CAPTUREBLT); 

    // This part captures the mouse cursor and paints it on the image. 
    if(programSettings.bWantCursor) 
    {  
     int osVersion = OSCheck::GetMajorOSVersion(); // For some reason cursor icons in 
                 // versions older than Vista are not 
                 // top-aligned. So we compensate. 
     int offsetX = (osVersion >= 6) ? 0 : 10; 
     int offsetY = (osVersion >= 6) ? 0 : 10;   

     CPoint cursorOffset(cursor.ptScreenPos.x - coords.x - offsetX, cursor.ptScreenPos.y - coords.y - offsetY); 

     // Now draw the image of the cursor that we captured during 
     // the mouse move. DrawIcon will draw a cursor as well. 
     memDC.DrawIcon(cursorOffset, (HICON)cursor.hCursor); 
    } 
    memDC.SelectObject(oldbm); 

    Bitmap outputBitMap(bmp, NULL); 

    // Optionally copy the image to the clipboard. 
    if(programSettings.bWantClipboard) 
    { 
     if(OpenClipboard(NULL)) 
     { 
      EmptyClipboard(); 
      SetClipboardData(CF_BITMAP, bmp); 
      CloseClipboard(); 
     } 
    } 

    BOOL success = DumpImage(&outputBitMap, filename); 

    DeleteObject(bmp.Detach()); 
    DeleteDC(dc.Detach()); 
    DeleteDC(memDC.Detach()); 
    return success; 
} 

:DumpImageはかなりGDI ::ビットマップのSaveメソッドを使用しています。例に関連しないアプリ固有のコードがいくつかあるため、省略されています。また、あなたのscreengrabにカーソルを含める方法が不思議だったら、コードもそこにあるということに加えて、追加のボーナスがあります。それが役に立てば幸い。また、伝統的なアプローチとは対照的に、キャプチャされたウィンドウの上に重ねて表示されるウィンドウも含まれます。また、フルスクリーンキャプチャにこのコードを使用する場合は、ビデオゲームのウィンドウをキャプチャしないことに注意してください。私は実際にDirectXに頼らずに正しく行う方法を考えています。これは、Aeroモードで動作している場合にのみWindows Vista/7に影響します。

関連する問題