1

I have an MFC desktop application that generates a graphics image, and I want the user to be able to copy it to the clipboard as a bitmap. I use standard clipboard API routines and they have been working fine up to now. However, I have now activated GDI Scaling (via a manifest) so that the program can run (reasonably well) on HiDPI displays, and I find that the image placed on the clipboard is just the upper-left quadrant of the actual image. This is presumably due to the internal scaling of the image - the display is running at 200%. How do I copy the whole image?

Bill Heitler
  • 187
  • 3
  • 13

1 Answers1

1

The key is given in the answer to a previous question: Saving Bitmaps on Windows 10 with GDI scaling active but it took me some time to adapt that answer to my particular problem, so I thought I'd share in case it was helpful to others. (Disclaimer - I'm no expert, so there may be better ways...)

bool CopyRectToClipboard(CWnd *pW, CRect rctCopy)
{
    if (!pW->OpenClipboard())
        return false;
    if (!EmptyClipboard())
        return false;

    CClientDC dc(pW);
    CDC dcMem;
    VERIFY(dcMem.CreateCompatibleDC(&dc));

    CBitmap bmTrial;    // need a trial bitmap to get GDI Scaled size
    VERIFY(bmTrial.CreateCompatibleBitmap(&dc, rctCopy.Width(), rctCopy.Height()));
// see https://stackoverflow.com/questions/51169846/saving-bitmaps-on-windows-10-with-gdi-scaling-active
    BITMAPINFO bi = {};
    bi.bmiHeader.biSize = sizeof(bi);
    int result = GetDIBits(dc.GetSafeHdc(), (HBITMAP)bmTrial.GetSafeHandle(), 0, 0, NULL, &bi, DIB_RGB_COLORS);

    CBitmap bm;
    VERIFY(bm.CreateCompatibleBitmap(&dc, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight));
    ASSERT(bm.m_hObject != NULL);
    CBitmap* pbmOld = dcMem.SelectObject(&bm);

    //dcMem.PatBlt(0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, WHITENESS);  // legacy
    VERIFY(dcMem.BitBlt(0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight,
        &dc, rctCopy.left - 1, rctCopy.top - 1, SRCCOPY));

    HGDIOBJ hBM = bm.Detach();
    VERIFY(::EmptyClipboard());
    VERIFY(::SetClipboardData(CF_BITMAP, hBM));
    VERIFY(::CloseClipboard());

    dcMem.SelectObject(pbmOld);
    dcMem.DeleteDC();
    return true;
}


Bill Heitler
  • 187
  • 3
  • 13