#include <stdio.h>
#include <Windows.h>
#pragma warning(disable: 4996) // 关闭fopen, scanf等库函数的_s警告
// 为指定大小的位图分配内存
LPBYTE AllocateBits(int nWidth, int nHeight, int nBitcCount, int *pSize)
{
*pSize = (int)((nWidth * nBitcCount + 31) / 32) * 4 * nHeight;
if (*pSize < 0)
*pSize = -*pSize;
return (LPBYTE)malloc(*pSize);
}
int main(void)
{
BITMAPFILEHEADER fileheader;
BITMAPINFOHEADER infoheader; // 由于BITMAPINFO结构体中有一个没用的调色板, 所以不使用那个结构体
FILE *fp;
HBITMAP hbmp; // DDB句柄
HDC hdc, hdcMem;
int width, height;
int size;
PBYTE pBits; // DIB数据
/* 获取屏幕分辨率 */
width = GetSystemMetrics(SM_CXSCREEN);
height = GetSystemMetrics(SM_CYSCREEN);
printf("屏幕分辨率: %dx%d\n", width, height);
/* 创建设备有关位图(DDB)及其DC, 并把屏幕上的内容复制到该位图上 */
hdc = GetDC(NULL); // 获取屏幕DC
hbmp = CreateCompatibleBitmap(hdc, width, height);
hdcMem = CreateCompatibleDC(hdc); // 创建内存DC
SelectObject(hdcMem, hbmp);
BitBlt(hdcMem, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
ReleaseDC(NULL, hdc);
/* 填写设备无关位图(DIB)的结构体 */
ZeroMemory(&infoheader, sizeof(infoheader));
infoheader.biSize = sizeof(infoheader);
infoheader.biPlanes = 1;
infoheader.biBitCount = 24;
infoheader.biWidth = width;
infoheader.biHeight = height;
/* 为设备无关位图分配内存, 然后把设备有关位图转换为设备无关位图 */
pBits = AllocateBits(width, height, infoheader.biBitCount, &size);
GetDIBits(hdcMem, hbmp, 0, height, pBits, (BITMAPINFO *)&infoheader, DIB_RGB_COLORS); // DDB -> DIB
/* 填写设备无关位图文件的结构体 */
fileheader.bfReserved1 = fileheader.bfReserved2 = 0;
fileheader.bfSize = sizeof(fileheader) + sizeof(infoheader) + size;
fileheader.bfType = *(PWORD)"BM";
fileheader.bfOffBits = sizeof(fileheader) + sizeof(infoheader);
/* 打开位图文件并写入 */
fp = fopen("file.bmp", "wb");
if (fp != NULL)
{
fwrite(&fileheader, sizeof(fileheader), 1, fp);
fwrite(&infoheader, sizeof(infoheader), 1, fp);
fwrite(pBits, size, 1, fp);
fclose(fp);
}
else
puts("打开文件失败");
/* 释放内存 */
free(pBits);
DeleteObject(hbmp);
DeleteDC(hdcMem);
}