画面キャプチャプログラム

ふと思い立ってスクリーンキャプチャプログラムの作り方を調べたい気分になり、作成。

画面をファイルに保存するところはちょっと面倒くさいが、RegisterHotkeyの使い方が分かれば案外簡単?


#include
#include

int SaveImage(HWND hwnd, HDC hdc, char* fileName) {
int i;
RECT rect;
UINT width, height;
BYTE* line;
UINT sLine;
FILE* fp;
HDC hmdc;
HBITMAP hbmp, hbmpOld;
BITMAPINFO bi;
BYTE bfh[14] = { 0x42, 0x4d, 0,0,0,0, 0,0, 0,0, 0x36,0,0,0 };

GetWindowRect(hwnd, &rect);
width = rect.right - rect.left;
height = rect.bottom - rect.top;

hmdc = CreateCompatibleDC(hdc);
hbmp = CreateCompatibleBitmap(hdc, width, height);

hbmpOld = SelectObject(hmdc, hbmp);
BitBlt(hmdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
SelectObject(hmdc, hbmpOld);

sLine = width*3;
sLine += (sLine%4 != 0 ? 4 - sLine%4 : 0);
line = malloc(sLine);

fp = fopen(fileName, "wb");

*( (DWORD*)(&bfh[2])) = 0x36 + sLine * height;
fwrite(bfh, sizeof bfh, 1, fp);

ZeroMemory(&bi, sizeof bi);
bi.bmiHeader.biSize = sizeof bi.bmiHeader;
bi.bmiHeader.biWidth = width;
bi.bmiHeader.biHeight = height;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 24;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = sLine * height;
fwrite(&(bi.bmiHeader), sizeof bi.bmiHeader, 1, fp);

for (i = 0; i < height; i++) {
GetDIBits(hmdc, hbmp, i, 1, line, &bi, DIB_RGB_COLORS);
fwrite(line, sLine, 1, fp);
}

fclose(fp);
free(line);
DeleteObject(hbmp);
DeleteDC(hmdc);
return 0;
}


int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
LPSTR lpsCmdLine, int nCmdShow)
{
MSG msg;
char fileName[1<<16];
HWND hwnd;
HDC hdc;
int n = 0;

// Print Screen キーでデスクトップ全体をキャプチャ
RegisterHotKey(NULL, 1, 0, 0x2C);
// Ctrl+PrtScrでフォアグランドウィンドウのみをキャプチャ
RegisterHotKey(NULL, 2, MOD_ALT, 0x2C);
// Ctrl+Alt+PrtScrでプログラム終了
RegisterHotKey(NULL, 99, MOD_CONTROL | MOD_ALT, 0x2C);

while (GetMessage(&msg, NULL, 0, 0)) {
if (msg.message == WM_HOTKEY) {
switch (msg.wParam) {
case 1:
hwnd = GetDesktopWindow();
hdc = GetDC(NULL);
sprintf(fileName, "%s%03d.bmp", lpsCmdLine, n);
n++;
SaveImage(hwnd, hdc, fileName);
ReleaseDC(NULL, hdc);
break;
case 2:
hwnd = GetForegroundWindow();
hdc = GetWindowDC(hwnd);
sprintf(fileName, "%s%03d.bmp", lpsCmdLine, n);
n++;
SaveImage(hwnd, hdc, fileName);
ReleaseDC(hwnd, hdc);
break;
case 99:
PostQuitMessage(0);
}
}
}
return msg.wParam;
}

プログラムは24bpsビットマップしか出力しない、256色モードのときの挙動が何か変。
・・まあ、今時256色の画面なんて使わねーしいいか。

Windows Server 2008で動作することは確認したが、VistaのAeroで動くかどうかは不明。

(追記)Vista/Aeroでも動作する