winapi中保存位图问题

Saving bitmap problems in winapi

它写入我的 BITMAP.bmp 文件,但是当我尝试在 Windows 照片查看器中查看它时,它说 "Windows Photo Viewer can't open this picture because the file appears to be damaged, corrupted, or is too large." 我知道我可能应该将函数放入头文件但是我从来没有真正深入研究过一个项目来真正制作头文件,所以我忘记了如何制作。如果有人知道 Windows 照片查看器中图片的大小限制,我将不胜感激。我从 MSDN 中获得了其中一些功能(毫不羞愧)。错误处理可能会更好,但我没有 errorhandler.h。我不完全确定所有功能是如何工作的,因为正如我所说,我使用了一些来自 MSDN 的代码。 我将非常感谢任何可以帮助我的人。 :)

#include <errorrep.h>
#include <windows.h>
#include <iostream>
using namespace std;

namespace Globals{
    HBITMAP hBitmap;
    HDC hScreen;
}
using namespace Globals;

void GetScreenShot(void)
{
    int x1, y1, x2, y2, w, h;
    LPSIZE lpSize;
    LPVOID lpvBits;
    // get screen dimensions
    x1  = GetSystemMetrics(SM_XVIRTUALSCREEN);
    x2  = GetSystemMetrics(SM_CXVIRTUALSCREEN);
    y1  = GetSystemMetrics(SM_YVIRTUALSCREEN);
    y2  = GetSystemMetrics(SM_CYVIRTUALSCREEN);
    w   = x2-x1;
    h   = y2-y1;

    // copy screen to bitmap
    hScreen = GetDC(NULL);
    HDC     hDC     = CreateCompatibleDC(hScreen);
    hBitmap = CreateCompatibleBitmap(hScreen, w, h);
    HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
    BOOL    bRet    = BitBlt(hDC, 0, 0, w, h, hScreen, x1, y1, SRCCOPY);
    GetBitmapDimensionEx(hBitmap, lpSize);
    GetBitmapBits(hBitmap, (LONG)lpSize, lpvBits);
    // save bitmap to clipboard
    OpenClipboard(NULL);
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hBitmap);
    CloseClipboard();
    // clean up
    SelectObject(hDC, old_obj);
    /*DeleteDC(hDC);
    ReleaseDC(NULL, hScreen);
    DeleteObject(hBitmap);*/
}

PBITMAPINFO CreateBitmapInfoStruct(/*HWND hwnd, */HBITMAP hBmp)
{
    BITMAP bmp;
    PBITMAPINFO pbmi;
    WORD    cClrBits;

    // Retrieve the bitmap color format, width, and height.
    if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
        //errhandler("GetObject", hwnd);
        cout << "Error: CreateBitmapInfoStruct" << endl;

    // Convert the color format to a count of bits.
    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
    if (cClrBits == 1)
        cClrBits = 1;
    else if (cClrBits <= 4)
        cClrBits = 4;
    else if (cClrBits <= 8)
        cClrBits = 8;
    else if (cClrBits <= 16)
        cClrBits = 16;
    else if (cClrBits <= 24)
        cClrBits = 24;
    else cClrBits = 32;

    // Allocate memory for the BITMAPINFO structure. (This structure
    // contains a BITMAPINFOHEADER structure and an array of RGBQUAD
    // data structures.)

     if (cClrBits < 24)
         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                    sizeof(BITMAPINFOHEADER) +
                    sizeof(RGBQUAD) * (1<< cClrBits));

     // There is no RGBQUAD array for these formats: 24-bit-per-pixel or 32-bit-per-pixel

     else
         pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                    sizeof(BITMAPINFOHEADER));

    // Initialize the fields in the BITMAPINFO structure.

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = bmp.bmWidth;
    pbmi->bmiHeader.biHeight = bmp.bmHeight;
    pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
    if (cClrBits < 24)
        pbmi->bmiHeader.biClrUsed = (1<<cClrBits);

    // If the bitmap is not compressed, set the BI_RGB flag.
    pbmi->bmiHeader.biCompression = BI_RGB;

    // Compute the number of bytes in the array of color
    // indices and store the result in biSizeImage.
    // The width must be DWORD aligned unless the bitmap is RLE
    // compressed.
    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
                                  * pbmi->bmiHeader.biHeight;
    // Set biClrImportant to 0, indicating that all of the
    // device colors are important.
     pbmi->bmiHeader.biClrImportant = 0;
     return pbmi;
 }

 void CreateBMPFile(/*HWND hwnd, */LPTSTR pszFile, PBITMAPINFO pbi,
                  HBITMAP hBMP, HDC hDC)
 {
     HANDLE hf;                 // file handle
    BITMAPFILEHEADER hdr;       // bitmap file-header
    PBITMAPINFOHEADER pbih;     // bitmap info-header
    LPBYTE lpBits;              // memory pointer
    DWORD dwTotal;              // total count of bytes
    DWORD cb;                   // incremental count of bytes
    BYTE *hp;                   // byte pointer
    DWORD dwTmp;

    pbih = (PBITMAPINFOHEADER) pbi;
    lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

    if (!lpBits)
         //errhandler("GlobalAlloc", hwnd);
        cout << "!lpBits" << endl;
    // Retrieve the color table (RGBQUAD array) and the bits
    // (array of palette indices) from the DIB.
    if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,
        DIB_RGB_COLORS))
    {
        //errhandler("GetDIBits", hwnd);
        cout << "Error 1" << endl;
    }

    // Create the .BMP file.
    hf = CreateFile(pszFile,
                   GENERIC_READ | GENERIC_WRITE,
                   (DWORD) 0,
                    NULL,
                   CREATE_ALWAYS,
                   FILE_ATTRIBUTE_NORMAL,
                   (HANDLE) NULL);
    if (hf == INVALID_HANDLE_VALUE)
        //errhandler("CreateFile", hwnd);
    hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"
    // Compute the size of the entire file.
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +
                 pbih->biSize + pbih->biClrUsed
                 * sizeof(RGBQUAD) + pbih->biSizeImage);
    hdr.bfReserved1 = 0;
    hdr.bfReserved2 = 0;

    // Compute the offset to the array of color indices.
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +
                    pbih->biSize + pbih->biClrUsed
                    * sizeof (RGBQUAD);

    // Copy the BITMAPFILEHEADER into the .BMP file.
    if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),
        (LPDWORD) &dwTmp,  NULL))
    {
       //errhandler("WriteFile", hwnd);
       cout << "!WriteFile" << endl;
    }

    // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
    if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)
                  + pbih->biClrUsed * sizeof (RGBQUAD),
                  (LPDWORD) &dwTmp, ( NULL)))
        //errhandler("WriteFile", hwnd);
        cout << "!WriteFile" << endl;

    // Copy the array of color indices into the .BMP file.
    dwTotal = cb = pbih->biSizeImage;
    hp = lpBits;
    if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))
           //errhandler("WriteFile", hwnd);
           cout << "if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))" << endl;

    // Close the .BMP file.
     if (!CloseHandle(hf))
           //errhandler("CloseHandle", hwnd);

    // Free memory.
    GlobalFree((HGLOBAL)lpBits);
}

int main() {
    cout << "ScreenShot - Takes a screen shot\nScreen shot will be put in your clipboard"
    "\nThere will be 10 seconds before it takes the screen shot\n" << endl;
    string input;
    do
    {
        cin >> input;

        if(input == "ScreenShot")
        {
            /*for(int i=1; i<11; i++)
            {
                Sleep(1000);
                cout << i << endl;
                if(i == 10)
                {
                    break;
                }
            }*/
            GetScreenShot();
            PBITMAPINFO pbmi = CreateBitmapInfoStruct(hBitmap);
            CreateBMPFile("C:\Users\Owner\Desktop\BITMAP.bmp", pbmi, hBitmap, hScreen);
            cout << "ScreenShot taken!" << endl;
            cin.ignore(2);
            Sleep(3000);
            break;
        }
        else
        {
            cout << "Invalid command." << endl;
        }

    } while(true);

    return 0;
}

将未初始化的值传递给 GetBitmapDimensionExGetBitmapBits 似乎不太好,因此删除它们,因为它们似乎没有被使用。

void GetScreenShot(void)
{
    int x1, y1, x2, y2, w, h;
    // get screen dimensions
    x1  = GetSystemMetrics(SM_XVIRTUALSCREEN);
    x2  = GetSystemMetrics(SM_CXVIRTUALSCREEN);
    y1  = GetSystemMetrics(SM_YVIRTUALSCREEN);
    y2  = GetSystemMetrics(SM_CYVIRTUALSCREEN);
    w   = x2-x1;
    h   = y2-y1;

    // copy screen to bitmap
    hScreen = GetDC(NULL);
    HDC     hDC     = CreateCompatibleDC(hScreen);
    hBitmap = CreateCompatibleBitmap(hScreen, w, h);
    HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
    BOOL    bRet    = BitBlt(hDC, 0, 0, w, h, hScreen, x1, y1, SRCCOPY);
    // save bitmap to clipboard
    OpenClipboard(NULL);
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hBitmap);
    CloseClipboard();
    // clean up
    SelectObject(hDC, old_obj);
    /*DeleteDC(hDC);
    ReleaseDC(NULL, hScreen);
    DeleteObject(hBitmap);*/
}

然后,设置 hdr.bfType 即使 hf != INVALID_HANDLE_VALUE.

改变

    if (hf == INVALID_HANDLE_VALUE)
        //errhandler("CreateFile", hwnd);
    hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"

    if (hf == INVALID_HANDLE_VALUE)
    {
        //errhandler("CreateFile", hwnd);
    }
    hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"

(加上大括号)

使用 LPCTSTR 而不是 LPTSTR 作为 pszFile 的类型,这是 CreateBMPFile 的参数也很好 以避免在传递字符串文字时出现编译器警告。