目标功能:后台循环截图
遇见的问题: 控制台提示 无法获取设备上下文
实际: 代码可以 运行,没有报错 ,但是就是无法获取上下文
现目标:修改代码以实现后台截屏 并适当修改以实现后台循环截屏
#include <windows.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
// BMP文件头
#pragma pack(2)
typedef struct {
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
} BITMAPFILEHEADER;
// BMP信息头
typedef struct {
unsigned int biSize;
int biWidth;
int biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} BITMAPINFOHEADER;
// 颜色定义
typedef struct {
unsigned char rgbBlue;
unsigned char rgbGreen;
unsigned char rgbRed;
unsigned char rgbReserved;
} RGBQUAD;
#pragma pack()
bool SaveBMP(const char* filename, int width, int height, std::vector<RGBQUAD>& bits) {
std::ofstream outfile(filename, std::ios::out | std::ios::binary);
if (!outfile.is_open()) {
std::cerr << "Error opening file for writing: " << filename << std::endl;
return false;
}
// BMP文件头
BITMAPFILEHEADER fileHeader;
fileHeader.bfType = 0x4D42; // BM
fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (width * height * sizeof(RGBQUAD));
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
// BMP信息头
BITMAPINFOHEADER infoHeader;
infoHeader.biSize = sizeof(BITMAPINFOHEADER);
infoHeader.biWidth = width;
infoHeader.biHeight = height;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = 32;
infoHeader.biCompression = BI_RGB;
infoHeader.biSizeImage = 0; // 可以为0,因为使用的是非压缩格式
infoHeader.biXPelsPerMeter = 0;
infoHeader.biYPelsPerMeter = 0;
infoHeader.biClrUsed = 0;
infoHeader.biClrImportant = 0;
// 写入文件头和信息头
outfile.write(reinterpret_cast<char*>(&fileHeader), sizeof(BITMAPFILEHEADER));
outfile.write(reinterpret_cast<char*>(&infoHeader), sizeof(BITMAPINFOHEADER));
// 写入图像数据
for (int i = 0; i < height; ++i) {
for (int j = 0; j < width; ++j) {
// BMP格式是从左下角开始存储的,所以我们需要翻转图像
int index = (height - i - 1) * width + j;
outfile.write(reinterpret_cast<char*>(&bits[index]), sizeof(RGBQUAD));
}
}
outfile.close();
return true;
}
bool CaptureWindowToBMP(HWND hwnd, const char* filename) {
// 获取窗口的尺寸
RECT rect;
if (!GetWindowRect(hwnd, &rect)) {
std::cerr << "Error getting window rect for window handle " << hwnd << ". Error code: " << GetLastError() << std::endl;
return false;
}
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
// 创建兼容DC和位图
HDC hdcScreen = ::GetWindowDC(hwnd);
if (hdcScreen == NULL) {
std::cerr << "Error: Unable to get the device context for window (" << hwnd << "). Error code: " << GetLastError() << std::endl;
return false;
}
HDC hdcMemDC = CreateCompatibleDC(hdcScreen);
if (hdcMemDC == NULL) {
std::cerr << "Error: Unable to create a compatible device context. Error code: " << GetLastError() << std::endl;
ReleaseDC(hwnd, hdcScreen); // 纠正:应该释放与窗口关联的设备上下文
return false;
}
HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, width, height);
if (hBitmap == NULL) {
std::cerr << "Error: Unable to create a compatible bitmap. Error code: " << GetLastError() << std::endl;
DeleteDC(hdcMemDC);
ReleaseDC(hwnd, hdcScreen);
return false;
}
HGDIOBJ hOldBitmap = SelectObject(hdcMemDC, hBitmap);
if (hOldBitmap == NULL) {
std::cerr << "Error: Unable to select new bitmap into device context. Error code: " << GetLastError() << std::endl;
DeleteObject(hBitmap);
DeleteDC(hdcMemDC);
ReleaseDC(hwnd, hdcScreen);
return false;
}
// 将窗口内容拷贝到位图中
bool printSuccess = PrintWindow(hwnd, hdcMemDC, PW_CLIENTONLY);
if (!printSuccess) {
std::cerr << "Error: Failed to print window content to memory device context. Error code: " << GetLastError() << std::endl;
// 即使打印失败,仍需继续进行资源清理
}
// 保存为BMP文件
BITMAP bmp;
if (!GetObject(hBitmap, sizeof(bmp), &bmp)) {
std::cerr << "Error: Unable to retrieve bitmap information. Error code: " << GetLastError() << std::endl;
// 继续进行错误处理和资源清理
}
std::vector<RGBQUAD> bits(bmp.bmWidth * bmp.bmHeight);
BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = bmp.bmWidth;
bmi.bmiHeader.biHeight = bmp.bmHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
if (!GetDIBits(hdcMemDC, hBitmap, 0, bmp.bmHeight, &bits[0], &bmi, DIB_RGB_COLORS)) {
std::cerr << "Error getting bitmap bits. Error code: " << GetLastError() << std::endl;
// 清理资源
SelectObject(hdcMemDC, hOldBitmap); // 还原之前选中的位图
DeleteObject(hBitmap);
DeleteDC(hdcMemDC);
ReleaseDC(hwnd, hdcScreen);
return false;
}
// 保存BMP文件
if (!SaveBMP(filename, bmp.bmWidth, bmp.bmHeight, bits)) {
std::cerr << "Error saving BMP file '" << filename << "'. Error code: " << GetLastError() << std::endl;
// 清理资源
SelectObject(hdcMemDC, hOldBitmap);
DeleteObject(hBitmap);
DeleteDC(hdcMemDC);
ReleaseDC(hwnd, hdcScreen);
return false;
}
// 恢复原始位图并清理资源
SelectObject(hdcMemDC, hOldBitmap);
DeleteObject(hBitmap);
DeleteDC(hdcMemDC);
ReleaseDC(hwnd, hdcScreen);
return true;
}
int main() {
// 示例:捕获当前活动窗口并保存为BMP
HWND hwnd = GetForegroundWindow(); // 获取当前活动窗口句柄
if (hwnd == NULL) {
std::cerr << "No active window found." << std::endl;
return 1;
}
const char* filename = "capture.bmp";
if (!CaptureWindowToBMP(hwnd, filename)) {
std::cerr << "Failed to capture window to BMP." << std::endl;
return 1;
}
std::cout << "Window captured successfully to " << filename << std::endl;
return 0;
}