Windows 7 и ScreenShot.cpp GDI + PNG проблема - PullRequest
2 голосов
/ 25 мая 2011

долгое время пользовался XP без проблем. переключился на 7 и попытка сделать снимки экрана с моим ранее работающим кодом больше не работает. простая концепция и относительно общий код ... просто найдите окно, которое я вызываю, и сохраните его как .png. какие-нибудь идеи, что могло заставить этого плохого мальчика бежать снова? не могу отладить мою текущую настройку, но она делает это полностью и выдает сообщение об ошибке после bmp-> save (...) ... не может сохранить файл изображения edit: также файл создается / сохраняется, но он пустой и не записывается. возможно, битовая кодировка или GDI облажались?

bool CScreenShot::Snap(CString wintitle, CString file, CString& ermsg)
{
    ermsg = ""; // no error message

    // create screen shot bitmap
    EnumWinProcStruct prm = {0, (LPSTR)(LPCTSTR)wintitle, 0};

    // Find the descriptor of the window with the caption wintitle
    EnumDesktopWindows(0, EnumWindowsProc, (LPARAM)&prm);
    if(!prm.hwnd)
    {
        ermsg.Format("couldn't find window \"%s\"", wintitle);
        return false;
    }

    // Make the window the topmost window
    SetWindowPos(prm.hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    Sleep(300);

    // Get device context for the top-level window and client rect
    HDC hDC = GetDC(prm.hwnd);
    RECT rc;
    GetClientRect(prm.hwnd, &rc);

    HDC memDC = CreateCompatibleDC(hDC);

    // Set the size and color depth for the screen shot image
    BITMAPINFO bmpInfo;
    memset(&bmpInfo, 0, sizeof(bmpInfo));
    bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
    bmpInfo.bmiHeader.biWidth = rc.right - rc.left;
    bmpInfo.bmiHeader.biHeight = rc.bottom - rc.top;
    bmpInfo.bmiHeader.biPlanes = 1;
    bmpInfo.bmiHeader.biBitCount = 24;
    bmpInfo.bmiHeader.biCompression = BI_RGB;
    bmpInfo.bmiHeader.biSizeImage = bmpInfo.bmiHeader.biWidth * bmpInfo.bmiHeader.biHeight * 3;

    // Create memory buffer and perform a bit-block transfer of the color data from the window to the memory
    LPVOID  addr;
    HBITMAP memBM   = CreateDIBSection(memDC, &bmpInfo, DIB_RGB_COLORS, &addr, 0, 0);

    HGDIOBJ stdBM   = SelectObject(memDC, memBM);
    BOOL    OK      = BitBlt(memDC, 0, 0, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight, hDC, 0, 0, SRCCOPY);
    ReleaseDC(prm.hwnd, hDC);

    SetWindowPos(prm.hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);

    // Initialize GDI+.
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR           gdiplusToken;
    if(GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) != Ok)
    {
        ermsg.Format("couldn't start GDI+");
        return false;
    }

    // Create a Bitmap object for work with images defined by pixel data from the GDI HBitmap and the GDI HPalette.
    Bitmap* bmp = ::new Bitmap(memBM, DIB_RGB_COLORS);
    SelectObject(memDC, stdBM);
    DeleteObject(memBM);
    DeleteDC(memDC);

    // Find the encoder for "image/png" mime type
    CLSID encoderClsid;
    EncoderParameters encoderParameters;

    GetEncoderClsid(L"image/png", &encoderClsid);

    encoderParameters.Count = 0;

    // Convert file name to Unicode (wide-char) string.
    WCHAR   fn[_MAX_PATH];
    MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, file, file.GetLength() + 1, fn, _MAX_PATH);
    // Save the screen shot into the specified file using image encoder with the mime style "image/png"
    if(bmp->Save(fn, &encoderClsid, &encoderParameters) != Ok)
    {
        ermsg.Format("couldn't save image file \"%s\"", file);
        return false;
    }

    ::delete bmp;
    GdiplusShutdown(gdiplusToken);

    return true;
}

Ответы [ 2 ]

1 голос
/ 25 мая 2011

Сообщение об ошибке означает, что вы пытаетесь сохранить файл в папку, к которой у вас нет разрешения на запись. Многие папки, такие как Program Files, теперь защищены. Поскольку вы не включили путь в свой пример кода, я не могу определить, является ли это реальной проблемой.

Редактировать: Другая возможность состоит в том, что растровое изображение создано неправильно, что приводит к сбою сохранения. Второй параметр конструктора должен быть дескриптором палитры, я думаю, что DIB_RGB_COLORS здесь будет недопустимым, и вам следует использовать NULL. Также есть несколько предостережений, отмеченных в документации Microsoft , и, возможно, различные версии ОС реагируют по-разному, когда вы нарушаете правила:

Вы несете ответственность за удаление растрового изображения GDI и палитры GDI. Однако не следует удалять растровое изображение GDI или палитру GDI до тех пор, пока объект GDI + Bitmap :: Bitmap не будет удален или выйдет из области видимости.

Не передавайте в конструктор GDI + Bitmap :: Bitmap растровое изображение GDI или палитру GDI, которые в настоящее время (или ранее) были выбраны в контексте устройства.

0 голосов
/ 24 сентября 2012

win7 по какой-то причине не будет принимать encoderParameters.Count == 0. Установите это == 1, и все должно быть готово.

вы, вероятно, также можете просто удалить этот параметр из Save () (перегружен)

...