비활성 윈도우 화면 캡처하는 방법

Study/C# 2016. 2. 24. 14:06 by Somnus

Intro

템 파밍을 위해 잠수를 하는데, 젠이 됐는지 안됐는지 계속 확인하는게 비효율적이었다. 화면을 주기적으로 캡처하고 몹이 인식되면 알림을 띄우기 위해 이러한 삽질을 하게 되었다. 사실 캡처 자체는 문제가 아니었는데, 캡처할 대상이 '비활성 window'에다가 게임은 DiretX로 렌더링 되는 화면이었고, 이는 캡처 시 검은 화면만을 표시한다.

Try#1

사실 WinAPI를 이용한 프로그래밍 조차 처음이었고, 당연히 구글링부터 시작했다. 일단 이 글을 참고했다. 프로그래머라면 일단 Copy&Paste가 기본이 아닌가.[각주:1]

되지 않으리라 예상은 했지만, 컴파일조차 되지 않을 줄은 정말 몰랐다. RECT라는 구조체부터 빨간 밑줄이 표시되었다. 도대체 WinUserApi란 무엇인가. 어쩔 수 없이 본문을 읽어보았고, 본문 첫 줄에 PrintWindow라는 단서를 얻을 수 있었다. MSDN으로 연결되었고, 예제는 C++였다. 작성자는 왜 C#으로 답변을 해주었는가?

Try#2

여러 의문을 남겨둔 채, PrintWindow함수에 대해 검색을 하였다. C#으로 작성된 코드를 이용하여야 하므로 관련된 검색을 했고 여기에서 해답을 찾을 수 있었다.

<Try#1>의 WinUserApiuser32.dll을 말하는 것임을 알 수 있게 되었다. 똑같이 gdi32.dll이 그러하다. 이제 RECTPixelFormat을 찾아주면 된다. RECT의 이름이나 쓰임새로 보아선 Rectangle의 약자인 것 같다. 구글에 검색하자, MSDN Rectangle 구조체 문서가 최상단에 노출되었다. PixelFormat 문서도 쉽게 찾을 수 있었다.

자, 빨간 밑줄을 모두 없애 주었고, 두근거리는 마음으로 컴파일하고 실행을 했지만 런타임 에러가 발생하였다. GetWindowRect라는 놈이 문제였는데, 이 함수의 용도는 window 크기 정보를 알아내는게 전부였다. 단순 구조체라고 생각했던 RECT가 생각만큼 단순한 녀석이 아니었나 보다. 크기 정보를 얻을 수 있는 다른 방법이 없는가 알아보던 중, Graphics 클래스 문서에서 HWND로 정보를 가져올 수 있는 메소드를 찾았다.

Try#3

아주 좋다. Window 메뉴바도 함께 찍히는데, 필요한 정보가 아니므로, MSDN 문서에 의하면, 12번 줄의 LParam값으로 PW_CLIENTONLY주면 클라이언트 화면만 캡쳐한다. 현재는 정의된 값이 아니므로, 0x1로 하였다.

하지만 StackOverflow글의 본문에도 적혀있듯이, DirectX 렌더링 화면은 캡쳐하지 못하는것을 확인하였다. 하지만 답글에 달린 댓글에 놀라운 정보가 있었다.

Solved

"it works with pretty much every window except for Direct X / WPF windows." - New flag may help. According to Dave Anderson's comment (msdn.microsoft.com/en-us/library/dd162869.aspx), the PW_RENDERFULLCONTENT flag on Win8.1+ works with "windows that use DirectX or DirectComposition".

Dwayne Robinson Jun 19 '15 at 7:41

링크를 따라가봤지만, PW_RENDERFULLCONTENT같은 플래그는 없었다. 혹시나 싶어 플래그로 0x2, 0x3을 넣어봤는데, DirectX 렌더링 화면이 매우 잘 캡쳐되었다!

  1. 아닌가? [본문으로]
Nav