سؤال

معلومات أساسية: لدي تطبيق MFC هذا مشفورا واستخدمه لفترة طويلة تحفظ بسرعة تلقائيا لقطات الشاشة على القرص الثابت عندما يضرب المستخدم على شاشة الطباعة / مفتاح الشاشة بالطباعة. لقد تم إيقافه باستخدام أي شيء يتعلق ب Aero حتى الآن أنني كنت أستخدم Windows 7 RC لبضعة أسابيع.

المشكلة: أنا أستخدم طريقة GetDC / Bitblt القياسية لالتقاط محتويات النافذة. ليس لدي أي مشاكل في هذه الطريقة أثناء القيام بالاستيلاء على الشاشة العادية (بغض النظر عن عدد النوافذ، إلخ). تنشأ المشكلة عندما أحاول التقاط نافذة المقدمة (ALT + PRINTSCREEN). فيما يلي مثالان:

مثال 1http://indiecodelabs.com/extern/example1.jpg.

مثال 2http://indiecodelabs.com/extern/example2.jpg.

كما ترون، أحصل على القمامة حيث يجب أن تكون الحدود. هذا هو أكثر وضوحا نحو الأعلى، حيث يمكننا أن نرى بعض الازدواجية في شريط الأدوات في كل من Screenshots.

لقد كنت googling حول هذا لساعات الآن وكل ما يمكنني أن أجده هي مقالات تقول إنها تحت DWM، لن تعمل طريقة BitBTL / GetDC، ولكن لا يمكنك العثور على واحد واحد يشرح ما يجب أن يفعلناه (المطورون) قادرة على الحفاظ على نفس الوظيفة في تطبيقاتنا عند تشغيلها على DWM.

أي مساعدة ومؤشرات، ستكون الاقتراحات موضع تقدير كبير.

هل كانت مفيدة؟

المحلول

إنه سؤال ممتاز لم أكن أعرف أن الإجابة الدقيقة ل. كانت فكرتي الأولى هي الاستيلاء على سطح المكتب بأكملها وقطع جزءا مثيرا للاهتمام منه.

لقد حفرت في مصادر QT 4.5 لمعرفة كيف يفعلون ذلك، ووجدت شيئا كهذا. إذا قمت بتبديل GetClientRect إلى GetWindowRect وشريط COMP Code Code، يجب أن تحصل على ما تريد. يبدو وكأنه اختراق على الرغم من :)


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;
}

نصائح أخرى

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 Orem There GDI :: طريقة حفظ BITMAP. تم حذفها لأنه يحتوي على بعض التعليمات البرمجية الخاصة بالتطبيقات غير ذات الصلة بالمثال. أيضا مكافأة إضافية هي أنه إذا كنت تتساءل كيفية تضمين المؤشر في Screengrab الخاص بك، فإن الرمز هو أيضا هناك. آمل أن يساعد. تجدر الإشارة أيضا إلى ما هو مخالف للنهج التقليدي، وسيتضمن ذلك أيضا أي نوافذ مفرطة قد يكون لديك أعلى النافذة الملتقطة. أيضا، إذا كنت تستخدم هذا الرمز لالتقاط ملء الشاشة، فسيتم تحذيرها من أنها لن تلتقط Windows Game Windows. أنا في الواقع أتساءل كيفية القيام بذلك بشكل صحيح دون الحاجة إلى اللجوء إلى DirectX. يؤثر هذا فقط على نظام التشغيل Windows Vista / 7 عند تشغيله في وضع Aero.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top