ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 화면 캡쳐와 Printwindow 함수
    Windows 프로그래밍 2019. 1. 2. 17:16


    현재 띄워져 있는 모든 창의 화면을 캡쳐해오고 싶었다.


    많은 함수로 시도해 봤지만 내가 잘못한 건진 모르겠는데 잘 되지 않았다. 그 때 Printwindow라는 함수를 찾게 되었다.

    Printwindow는 캡쳐를 원하는 창의 핸들과 DC, 그리고 옵션 이렇게 3가지의 인수를 넘기면 해당 창을 캡쳐한 비트맵의 핸들을 반환한다.


    MSDN : https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-printwindow


    프로세스의 핸들 값만 넘기면 캡쳐본의 비트맵 핸들을 반환해 주는 함수를 만들어 보았다.

    HBITMAP Capture(HWND hTargetWnd) { HDC hDC = ::GetDC(hTargetWnd); HDC hdcBitmap = ::CreateCompatibleDC(hDC); CRect rct, DsRct; if (hTargetWnd) { ::GetWindowRect(hTargetWnd, &rct); ::GetWindowRect(::GetDesktopWindow(), &DsRct); } else return FALSE; HBITMAP hBitmap = NULL; BOOL bSuccess = FALSE; BOOL ckFull = FALSE; RECT a, b; ::GetWindowRect(hTargetWnd, &a); ::GetWindowRect(::GetDesktopWindow(), &b); HDC hMemDC = ::CreateCompatibleDC(hDC); hBitmap = ::CreateCompatibleBitmap(hDC, rct.Width(), rct.Height()); if (!hBitmap) return FALSE; ::SelectObject(hMemDC, hBitmap); if (!::PrintWindow(hTargetWnd, hMemDC, 2)) bSuccess = FALSE; else { if ((rct.left + 8 == DsRct.left || rct.left + 8 == DsRct.left + DsRct.right) && (rct.top + 8 == DsRct.top || rct.top + 8 == DsRct.top + DsRct.bottom) && (rct.right - 8 == DsRct.right || rct.right - 8 == DsRct.right * 2) && (rct.bottom + 32 == DsRct.bottom || rct.bottom + 32 == DsRct.bottom * 2)) { // 전체화면 StretchBlt(hMemDC, -8, -8, rct.right - rct.left + 8, rct.bottom - rct.top + 8, hMemDC, 0, 0, rct.right - rct.left - 8, rct.bottom - rct.top - 8, SRCCOPY); // 캡쳐 시 여백을 없애기 위해 8픽셀을 가감 } else { // 창모드 StretchBlt(hMemDC, -7, 0, rct.right - rct.left + 7, rct.bottom - rct.top, hMemDC, 0, 0, rct.right - rct.left - 7, rct.bottom - rct.top - 7, SRCCOPY); // 캡쳐 시 여백을 없애기 위해 7픽셀을 가감 } bSuccess = TRUE; } return hBitmap; }

    코드 아래쪽을 보면 전체화면과 창모드를 비교해 비트맵의 일부를 편집하는 모습을 볼 수 있다.

    Printwindow를 이용해 캡쳐할 시에는 약 8px정도의 검은 색 테두리가 포함된 채로 캡쳐되기 때문에 이를 잘라내기 위해서이다. 그 테두리가 뭐냐면

    요고다. 창 크기를 조절할 때 쓰이는 저 양쪽 화살표 모양 포인터를 구현하기 위해 Microsoft가 Windows 개발 시에 창이 차지하는 범위를 조금 크게 잡아놓은 것이다.


    위 코드에서 가장 중요한 부분이 있다. Printwindow의 3번째 옵션이다.

    3번째 옵션은 플래그인데, Windows 버전에 따라 다르게 하면 된다. 위 코드처럼 2번 플래그를 줄 시에는 DirectX11을 이용해 렌더링 하는 화면이 캡쳐가 가능해 진다.

    Windows 10을 사용하는 경우에는 2번 플래그를 주어야 캡쳐가 가능하다.


    저 플래그 값 때문에 일주일 정도 고생한 것 같다. MSDN에는 나와있지 않은 옵션이다. 이 글을 보는 여러분은 나같은 고생은 하지 않길 바란다.

    'Windows 프로그래밍' 카테고리의 다른 글

    Volatile 변수란?  (2) 2019.01.07
    Service 프로세스에서 winlogon.exe  (0) 2019.01.03
    OnTimer 함수  (0) 2019.01.03
    Mutex와 Semaphore의 차이점과 사용방법  (0) 2019.01.03
    뮤텍스란?  (2) 2019.01.02

    댓글

Designed by Tistory.