본문 바로가기

API

API로 구현한 전체화면 캡쳐 소스

728x90
반응형

오늘은 API로 전체화면을 캡쳐하는 방법을 공부할 것인데요. 저같은 아무것도 모르는 초보가 하기에는 살짝 어려운듯 했지만 삽질의 연속으로 겨우 성공을 하게 되었네요.

화면캡쳐에는 DC가 꼭 필요합니다. 그래서 어제 DC를 먼저 공부해 보았던 것이고요. 그럼 어제 DC에 대한 것과 화면캡쳐에 필요한 함수들을 살펴보도록 하지요. 간단한 소스와 함께 알아보도록 하죠.

#include <windows.h>

 

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

HBITMAP ScreenCapture(HWND);

HINSTANCE g_hInst;

LPCTSTR lpszClass=TEXT("ScreenCapturTest");

HBITMAP hBit = NULL;

 

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)

{

  HWND hWnd;

  MSG Message;

  WNDCLASS WndClass;

  g_hInst = hInstance;

 

  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;

  WndClass.lpszClassName = lpszClass;

  WndClass.lpszMenuName = NULL;

  WndClass.style = 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, NULL, 0, 0))

  {

    TranslateMessage(&Message);

    DispatchMessage(&Message);

  }

  return (int)Message.wParam;

}

 

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)

{

  HDC hdc;

  PAINTSTRUCT ps;

  HDC hScrDC, hMemDC;

  HBITMAP hOldBitmap;

  BITMAP bmp;

 

  switch(iMessage)

  {

  case WM_CREATE:

    CreateWindow(TEXT("button"), TEXT("화면캡쳐"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20,20, 100, 25, hWnd, (HMENU)0, g_hInst, NULL);

    return 0;

  case WM_COMMAND:

    switch(LOWORD(wParam))

    {

    case 0:

      hBit = ScreenCapture(hWnd);

      break;

    }

    return 0;

  case WM_PAINT:

    hdc = BeginPaint(hWnd, &ps);

    if(hBit != NULL)

    {

      hMemDC = CreateCompatibleDC(hdc);

      SelectObject(hMemDC, hBit);

      GetObject(hBit, sizeof(BITMAP), &bmp);

      BitBlt(hdc, 0, 0, bmp.bmWidth, bmp.bmHeight, hMemDC, 0, 0, SRCCOPY);

 

      DeleteDC(hMemDC);

    }

    else

    {

 

    }

    EndPaint(hWnd, &ps);

    return 0;

  case WM_DESTROY:

    if(hBit != NULL)

    {

      DeleteObject(hBit);

    }

    PostQuitMessage(0);

    return 0;

  }

  return(DefWindowProc(hWnd, iMessage, wParam, lParam));

}

 

HBITMAP ScreenCapture(HWND hWnd)

{

  int ScreenWidth = GetSystemMetrics(SM_CXSCREEN);

  int ScreenHeight = GetSystemMetrics(SM_CYSCREEN);

  HDC hScrDC, hMemDC;

  HBITMAP hBitmap;

 

  hScrDC=CreateDC("DISPLAY",NULL,NULL,NULL);

  hMemDC = CreateCompatibleDC(hScrDC);

  hBitmap = CreateCompatibleBitmap(hScrDC, ScreenWidth, ScreenHeight);

  SelectObject(hMemDC, hBitmap);

 

  BitBlt(hMemDC, 0, 0, ScreenWidth, ScreenHeight, hScrDC, 0, 0, SRCCOPY);

 

  DeleteDC(hMemDC);

  DeleteDC(hScrDC);

  InvalidateRect(hWnd, NULL, TRUE);

  return hBitmap;

}

다른것 보다도 ScreenCapture함수를 보도록 하겠습니다. 우선 전체 화면을 캡쳐할 것이기 때문에 GetSystemMetrics함수로 모니터 해상도의 가로, 세로의 길이를 가져오게 됩니다. DC를 받을 두개의 변수와 BITMAP를 받을 두개의 변수를 생성을 하죠. CreateDC()함수는 지정된 디바이스의 디바이스 콘텍스트를 받아오는 것이지요. 첫번째 인수는 드라이버명을 뜻하는데요 지금은 DISPYAY는 전체 화면의 DC를 받아올수 있게 됩니다. 순서대로 드라이버명, 디바이스명, NULL, 드라이버의 데이터 이렇게 넣는데 두번째 인수부터는 NULL를 입력하게 되어 있습니다.
그다음 CreateCompatibleDC()함수는 인수로 주어진 hdc와 호환되는 메모리 DC를 생성하는 함수입니다. 여기서 호환된다는 뜻은 색상 포맷이 같다는 뜻이며 색상 포맷이 같은 DC끼리는 비트맵을 전송할 수 있습니다. 이렇게 메모리 DC를 생성하고나면 이제 비트맵을 작성하게 됩니다. CreateCompatibleBitmap()함수가 바로 비트맵을 생성하는 함수입니다. 첫번째 dc인자에 호환되는 비트맵을 생성하게됩니다. 두번째, 세번째는 당연히 비트맵의 사이즈를 나타내고요.
SelectObject()함수는 그리기에 사용할 오브젝트를 변경하는 함수로써 hBitmap를 그리기에 사용하겠다라는 것입니다. BitBlt()함수가 여기서 중요한 함수일것같습니다. 바로 해당 비트맵을 다른 비트맵으로 복사하는 녀석이거든요. hMemDC인수에 hScrDC의 비트맵을 복사해서 넣게 되는 것입니다. 그리고 만들었던 DC는 확실하게 지워줘야겠죠 ^ㅡ^
InvalidateRect()함수를 통해서 바로 화면을 지웠다 다시 살려주게 합니다. 이로써 버튼을 클릭했을 때 바로 캡쳐한 화면이 윈도우에 출력되게 되는것입니다.
그리고 마지막으로 WM_PAINT 메시지 루틴의 GetObject로 해당 비트맵이 실제로 출력되게 되는 것입니다. 그럼 출력 화면을 보겠습니다.


이화면은 화면 캡처를 여러번 눌렀을 때 나오는 화면입니다. 4번 클릭을 한거죠 ㅎ

어떠신가요? 함수 자체는 많이 쓰이지 않았지만 저는 처음인지라 개념 자체가 아직 덜 이해가 갔는데요. 포스팅을 하면서 더 많은 공부를 하게 된거 같네요 ㅎ
다음에는 마우스로 영역을 잡은 곳을 캡쳐 하는 것과 포커스를 가진 윈도우를 캡쳐하는 것을 봐보도록 하겠습니다.

감사합니다 ^ㅡ^

출처 : www.winapi.co.kr

728x90
반응형

'API' 카테고리의 다른 글

1초에 한번씩 캡쳐 화면 파일로 저장하기  (0) 2010.03.27
디렉토리 생성  (0) 2010.03.27
Win API Timer  (0) 2010.03.21
캡쳐 화면 BMP로 저장하기  (0) 2010.03.14
메뉴의 단축키, 액셀러레이터 생성  (0) 2010.03.12
메뉴 만들기  (1) 2010.03.11
포커스가 있는 윈도우 캡쳐  (0) 2010.03.10
DC 구조체에 관해....  (1) 2010.03.09
버튼 생성  (0) 2010.03.06
API의 첫 시작  (0) 2010.03.05