lengshizai 2024-04-10 21:39 采纳率: 31.7%
浏览 6
已结题

C++ 后台截屏 bug解决

目标功能:后台循环截图
遇见的问题: 控制台提示 无法获取设备上下文
实际: 代码可以 运行,没有报错 ,但是就是无法获取上下文
现目标:修改代码以实现后台截屏 并适当修改以实现后台循环截屏


#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;
}

img

  • 写回答

2条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-04-10 21:39
    关注

    引自免费微信小程序:皆我百晓生

    当然,我会尽力提供详尽的帮助和答案。不过请告诉我,为什么你在代码中遇到这个问题,并且想要通过修改什么部分来解决它?这样我才能更准确地为您提供所需的信息。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 4月10日
  • 创建了问题 4月10日

悬赏问题

  • ¥15 软件工程用例图的建立(相关搜索:软件工程用例图|画图)
  • ¥15 如何在arcgis中导出拓扑关系表
  • ¥15 处理数据集文本挖掘代码
  • ¥15 matlab2017
  • ¥15 在vxWorks下TCP/IP编程,总是connect()报错,连接服务器失败: errno = 0x41
  • ¥15 AnolisOs7.9如何安装 Qt_5.14.2的运行库
  • ¥20 求:怎么实现qt与pcie通信
  • ¥50 前后端数据顺序不一致问题,如何解决?(相关搜索:数据结构)
  • ¥15 基于蒙特卡罗法的中介效应点估计代码
  • ¥15 罗技G293和UE5.3