Windows/Windows API
capture
aucd29
2013. 10. 1. 18:59
// 화면 캡처 프로그램
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
LPSTR lpszClass="Capture";
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
,LPSTR lpszCmdParam,int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst=hInstance;
if(!hPrevInstance) {
WndClass.cbClsExtra=0;
WndClass.cbWndExtra=0;
WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
WndClass.hInstance=hInstance;
WndClass.lpfnWndProc=(WNDPROC)WndProc;
WndClass.lpszClassName=lpszClass;
WndClass.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);
WndClass.style=0;//CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass);
}
hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
NULL,(HMENU)NULL,hInstance,NULL);
ShowWindow(hWnd,nCmdShow);
while(GetMessage(&Message,0,0,0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
// DDB를 DIB로 바꾸어 파일로 저장한다.
void DDB2DIB(HBITMAP hbit,char *Path)
{
BITMAPFILEHEADER fh;
BITMAPINFOHEADER ih;
BITMAP bit;
BITMAPINFO *pih;
int PalSize;
HANDLE hFile;
DWORD dwWritten,Size;
HDC hdc;
// 전체 화면에 대한 DC를 구한다.
hdc=GetDC(NULL);
// 비트맵 정보로부터 정보 구조체를 초기화한다.
GetObject(hbit,sizeof(BITMAP),&bit);
ih.biSize=sizeof(BITMAPINFOHEADER);
ih.biWidth=bit.bmWidth;
ih.biHeight=bit.bmHeight;
ih.biPlanes=1;
ih.biBitCount=bit.bmPlanes*bit.bmBitsPixel;
if (ih.biBitCount > 8) ih.biBitCount=24;
ih.biCompression=BI_RGB;
ih.biSizeImage=0;
ih.biXPelsPerMeter=0;
ih.biYPelsPerMeter=0;
ih.biClrUsed=0;
ih.biClrImportant=0;
// 정보 구조체 + 팔레트 크기만큼 메모리를 할당하고 이 버퍼에
// 정보 구조체를 복사한다.
PalSize=(ih.biBitCount==24 ? 0:1 << ih.biBitCount)*sizeof(RGBQUAD);
pih=(BITMAPINFO *)malloc(ih.biSize+PalSize);
pih->bmiHeader=ih;
// 비트맵의 크기를 구한다.
GetDIBits(hdc,hbit,0,bit.bmHeight,NULL,pih,DIB_RGB_COLORS);
ih=pih->bmiHeader;
// 비트맵 크기가 구해지지 않았을 경우 수작업으로 직접 계산한다.
if (ih.biSizeImage == 0) {
ih.biSizeImage=((((ih.biWidth*ih.biBitCount)+31) & ~31) >> 3) * ih.biHeight;
}
// 래스터 데이터를 읽기위해 메모를 재할당한다.
Size=ih.biSize+PalSize+ih.biSizeImage;
pih=(BITMAPINFO *)realloc(pih,Size);
// 래스터 데이터를 읽어들인다.
GetDIBits(hdc,hbit,0,bit.bmHeight,(PBYTE)pih+ih.biSize+PalSize,pih,DIB_RGB_COLORS);
// 파일 헤더를 만든다.
fh.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+PalSize;
fh.bfReserved1=0;
fh.bfReserved2=0;
fh.bfSize=Size+sizeof(BITMAPFILEHEADER);
fh.bfType=0x4d42;
// 파일을 생성하고 파일 헤더와 정보 구조체, 팔레트, 래스터 데이터를 출력한다.
hFile=CreateFile(Path,GENERIC_WRITE,0,NULL,
CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
WriteFile(hFile,&fh,sizeof(fh),&dwWritten,NULL);
WriteFile(hFile,pih,Size,&dwWritten,NULL);
ReleaseDC(NULL,hdc);
CloseHandle(hFile);
}
HBITMAP hBit=NULL; // 캡처된 비트맵
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rt;
HBITMAP hOldBitmap;
HDC hMemDC,hScrDC;
BITMAP bmp;
char str[]="핫키 F5를 사용하거나 타이머로 원하는 화면을 캡처하십시요";
OPENFILENAME OFN;
char lpstrFile[MAX_PATH]="";
switch(iMessage) {
case WM_COMMAND:
switch(LOWORD(wParam)) {
// 핫키로 캡처하기:핫키를 등록한다.
case IDM_FILE_HOTKEY:
RegisterHotKey(hWnd,0x0000,0,VK_F5);
ShowWindow(hWnd,SW_MINIMIZE);
SetActiveWindow(GetWindow(hWnd,GW_HWNDPREV));
break;
// 타이머로 캡처하기:타이머를 설치한다.
case IDM_FILE_TIMER:
SetTimer(hWnd,0,5000,NULL);
ShowWindow(hWnd,SW_MINIMIZE);
SetActiveWindow(GetWindow(hWnd,GW_HWNDPREV));
break;
// 캡쳐된 그림을 파일로 저장하기
case IDM_FILE_SAVE:
if (hBit==NULL)
break;
memset(&OFN, 0, sizeof(OPENFILENAME));
OFN.lStructSize = sizeof(OPENFILENAME);
OFN.hwndOwner=hWnd;
OFN.lpstrFilter="Bmp File(*.Bmp)\0";
OFN.lpstrFile=lpstrFile;
OFN.nMaxFile=256;
OFN.lpstrDefExt="bmp";
OFN.lpstrTitle="저장할 파일 이름을 입력하시오";
if (GetSaveFileName(&OFN)!=0) {
DDB2DIB(hBit,lpstrFile);
}
break;
}
return 0;
// 핫키를 누르거나 지정한 시간이 경과했을 때 화면을 캡처한다.
case WM_HOTKEY:
case WM_TIMER:
// 포커스를 가진 윈도우의 좌표를 조사한다.
GetWindowRect(GetForegroundWindow(),&rt);
// 캡처 대상이 화면 영역밖이 되지 않도록 한다.
rt.left=max(0,rt.left);
rt.top=max(0,rt.top);
rt.right=min(rt.right,GetSystemMetrics(SM_CXSCREEN));
rt.bottom=min(rt.bottom,GetSystemMetrics(SM_CYSCREEN));
// 전체 화면 DC와 메모리 DC를 만들고 메모리 비트맵을 선택한다.
hScrDC=CreateDC("DISPLAY",NULL,NULL,NULL);
hMemDC=CreateCompatibleDC(hScrDC);
hBit=CreateCompatibleBitmap(hScrDC,
rt.right-rt.left,rt.bottom-rt.top);
hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBit);
// 화면을 메모리 비트맵으로 복사한다.
BitBlt(hMemDC,0,0,rt.right-rt.left,rt.bottom-rt.top,
hScrDC,rt.left,rt.top,SRCCOPY);
SelectObject(hMemDC,hOldBitmap);
DeleteDC(hMemDC);
DeleteDC(hScrDC);
// 핫키를 해제하고 타이머를 없앤다.
if (iMessage == WM_HOTKEY) {
UnregisterHotKey(hWnd,0);
}
else {
KillTimer(hWnd,0);
}
ShowWindow(hWnd,SW_RESTORE);
return 0;
// 캡처된 비트맵을 작업 영역에 출력한다.
case WM_PAINT:
hdc=BeginPaint(hWnd,&ps);
if (hBit != NULL) {
hMemDC=CreateCompatibleDC(hdc);
hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBit);
GetObject(hBit,sizeof(BITMAP),&bmp);
BitBlt(hdc,0,0,bmp.bmWidth,bmp.bmHeight,hMemDC,0,0,SRCCOPY);
SelectObject(hMemDC,hOldBitmap);
DeleteDC(hMemDC);
}
else {
TextOut(hdc,50,50,str,strlen(str));
}
EndPaint(hWnd,&ps);
return 0;
// 비트맵을 파괴하고 핫키를 등록해제한다.
case WM_DESTROY:
if (hBit != NULL)
DeleteObject(hBit);
UnregisterHotKey(hWnd,0);
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
HINSTANCE g_hInst;
LPSTR lpszClass="Capture";
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance
,LPSTR lpszCmdParam,int nCmdShow)
{
HWND hWnd;
MSG Message;
WNDCLASS WndClass;
g_hInst=hInstance;
if(!hPrevInstance) {
WndClass.cbClsExtra=0;
WndClass.cbWndExtra=0;
WndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
WndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
WndClass.hInstance=hInstance;
WndClass.lpfnWndProc=(WNDPROC)WndProc;
WndClass.lpszClassName=lpszClass;
WndClass.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1);
WndClass.style=0;//CS_HREDRAW | CS_VREDRAW;
RegisterClass(&WndClass);
}
hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
NULL,(HMENU)NULL,hInstance,NULL);
ShowWindow(hWnd,nCmdShow);
while(GetMessage(&Message,0,0,0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
// DDB를 DIB로 바꾸어 파일로 저장한다.
void DDB2DIB(HBITMAP hbit,char *Path)
{
BITMAPFILEHEADER fh;
BITMAPINFOHEADER ih;
BITMAP bit;
BITMAPINFO *pih;
int PalSize;
HANDLE hFile;
DWORD dwWritten,Size;
HDC hdc;
// 전체 화면에 대한 DC를 구한다.
hdc=GetDC(NULL);
// 비트맵 정보로부터 정보 구조체를 초기화한다.
GetObject(hbit,sizeof(BITMAP),&bit);
ih.biSize=sizeof(BITMAPINFOHEADER);
ih.biWidth=bit.bmWidth;
ih.biHeight=bit.bmHeight;
ih.biPlanes=1;
ih.biBitCount=bit.bmPlanes*bit.bmBitsPixel;
if (ih.biBitCount > 8) ih.biBitCount=24;
ih.biCompression=BI_RGB;
ih.biSizeImage=0;
ih.biXPelsPerMeter=0;
ih.biYPelsPerMeter=0;
ih.biClrUsed=0;
ih.biClrImportant=0;
// 정보 구조체 + 팔레트 크기만큼 메모리를 할당하고 이 버퍼에
// 정보 구조체를 복사한다.
PalSize=(ih.biBitCount==24 ? 0:1 << ih.biBitCount)*sizeof(RGBQUAD);
pih=(BITMAPINFO *)malloc(ih.biSize+PalSize);
pih->bmiHeader=ih;
// 비트맵의 크기를 구한다.
GetDIBits(hdc,hbit,0,bit.bmHeight,NULL,pih,DIB_RGB_COLORS);
ih=pih->bmiHeader;
// 비트맵 크기가 구해지지 않았을 경우 수작업으로 직접 계산한다.
if (ih.biSizeImage == 0) {
ih.biSizeImage=((((ih.biWidth*ih.biBitCount)+31) & ~31) >> 3) * ih.biHeight;
}
// 래스터 데이터를 읽기위해 메모를 재할당한다.
Size=ih.biSize+PalSize+ih.biSizeImage;
pih=(BITMAPINFO *)realloc(pih,Size);
// 래스터 데이터를 읽어들인다.
GetDIBits(hdc,hbit,0,bit.bmHeight,(PBYTE)pih+ih.biSize+PalSize,pih,DIB_RGB_COLORS);
// 파일 헤더를 만든다.
fh.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+PalSize;
fh.bfReserved1=0;
fh.bfReserved2=0;
fh.bfSize=Size+sizeof(BITMAPFILEHEADER);
fh.bfType=0x4d42;
// 파일을 생성하고 파일 헤더와 정보 구조체, 팔레트, 래스터 데이터를 출력한다.
hFile=CreateFile(Path,GENERIC_WRITE,0,NULL,
CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
WriteFile(hFile,&fh,sizeof(fh),&dwWritten,NULL);
WriteFile(hFile,pih,Size,&dwWritten,NULL);
ReleaseDC(NULL,hdc);
CloseHandle(hFile);
}
HBITMAP hBit=NULL; // 캡처된 비트맵
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rt;
HBITMAP hOldBitmap;
HDC hMemDC,hScrDC;
BITMAP bmp;
char str[]="핫키 F5를 사용하거나 타이머로 원하는 화면을 캡처하십시요";
OPENFILENAME OFN;
char lpstrFile[MAX_PATH]="";
switch(iMessage) {
case WM_COMMAND:
switch(LOWORD(wParam)) {
// 핫키로 캡처하기:핫키를 등록한다.
case IDM_FILE_HOTKEY:
RegisterHotKey(hWnd,0x0000,0,VK_F5);
ShowWindow(hWnd,SW_MINIMIZE);
SetActiveWindow(GetWindow(hWnd,GW_HWNDPREV));
break;
// 타이머로 캡처하기:타이머를 설치한다.
case IDM_FILE_TIMER:
SetTimer(hWnd,0,5000,NULL);
ShowWindow(hWnd,SW_MINIMIZE);
SetActiveWindow(GetWindow(hWnd,GW_HWNDPREV));
break;
// 캡쳐된 그림을 파일로 저장하기
case IDM_FILE_SAVE:
if (hBit==NULL)
break;
memset(&OFN, 0, sizeof(OPENFILENAME));
OFN.lStructSize = sizeof(OPENFILENAME);
OFN.hwndOwner=hWnd;
OFN.lpstrFilter="Bmp File(*.Bmp)\0";
OFN.lpstrFile=lpstrFile;
OFN.nMaxFile=256;
OFN.lpstrDefExt="bmp";
OFN.lpstrTitle="저장할 파일 이름을 입력하시오";
if (GetSaveFileName(&OFN)!=0) {
DDB2DIB(hBit,lpstrFile);
}
break;
}
return 0;
// 핫키를 누르거나 지정한 시간이 경과했을 때 화면을 캡처한다.
case WM_HOTKEY:
case WM_TIMER:
// 포커스를 가진 윈도우의 좌표를 조사한다.
GetWindowRect(GetForegroundWindow(),&rt);
// 캡처 대상이 화면 영역밖이 되지 않도록 한다.
rt.left=max(0,rt.left);
rt.top=max(0,rt.top);
rt.right=min(rt.right,GetSystemMetrics(SM_CXSCREEN));
rt.bottom=min(rt.bottom,GetSystemMetrics(SM_CYSCREEN));
// 전체 화면 DC와 메모리 DC를 만들고 메모리 비트맵을 선택한다.
hScrDC=CreateDC("DISPLAY",NULL,NULL,NULL);
hMemDC=CreateCompatibleDC(hScrDC);
hBit=CreateCompatibleBitmap(hScrDC,
rt.right-rt.left,rt.bottom-rt.top);
hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBit);
// 화면을 메모리 비트맵으로 복사한다.
BitBlt(hMemDC,0,0,rt.right-rt.left,rt.bottom-rt.top,
hScrDC,rt.left,rt.top,SRCCOPY);
SelectObject(hMemDC,hOldBitmap);
DeleteDC(hMemDC);
DeleteDC(hScrDC);
// 핫키를 해제하고 타이머를 없앤다.
if (iMessage == WM_HOTKEY) {
UnregisterHotKey(hWnd,0);
}
else {
KillTimer(hWnd,0);
}
ShowWindow(hWnd,SW_RESTORE);
return 0;
// 캡처된 비트맵을 작업 영역에 출력한다.
case WM_PAINT:
hdc=BeginPaint(hWnd,&ps);
if (hBit != NULL) {
hMemDC=CreateCompatibleDC(hdc);
hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBit);
GetObject(hBit,sizeof(BITMAP),&bmp);
BitBlt(hdc,0,0,bmp.bmWidth,bmp.bmHeight,hMemDC,0,0,SRCCOPY);
SelectObject(hMemDC,hOldBitmap);
DeleteDC(hMemDC);
}
else {
TextOut(hdc,50,50,str,strlen(str));
}
EndPaint(hWnd,&ps);
return 0;
// 비트맵을 파괴하고 핫키를 등록해제한다.
case WM_DESTROY:
if (hBit != NULL)
DeleteObject(hBit);
UnregisterHotKey(hWnd,0);
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}