일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Tips프로그래밍강좌
- VS ERROR
- 리뷰
- 백준
- 함수
- c++
- CS
- c#
- Tips강좌
- Windows
- Javascript
- 배열
- 문법
- Direct2D
- 프로그래밍
- tipssoft
- c
- 연산자
- 알고리즘
- Kotlin
- 이지스퍼블리싱
- 지식나눔강좌
- Desktop
- 티스토리
- 김성엽
- doit코틀린프로그래밍
- Visual Studio
- Programming
- Win32
- 포인터
- Yesterday
- Today
- Total
F.R.I.D.A.Y.
다중 모니터 위치 파악하기 본문

Index
- 모니터 위치 지정
- EnumDisplayMonitors
- lpfnEnum
- 바탕화면에 그리기
- WorkerW
- 좌표 계산하기
- 결과 확인
모니터 위치 지정copy^
Windows에서는 여러 개의 모니터를 사용할 때 각 모니터의 위치를 정할 수 있다.




나의 경우에는 1번 모니터를 메인으로 위에 2번 모니터가 존재하는 방식으로 사용한다. 이런 상황에서, 멀티 모니터 프로그래밍을 하려면 각 모니터의 위치를 찾아야하는 문제가 있다.
그러나 바탕화면을 담당하는 WorkerW 프로세스의 영역을 구하면 다음과 같다.


각 모니터 모두 FHD 해상도에 세로로 이어 붙인 상황이기 때문에 크기는 1920×2160이 맞다. 그러나 이를 Windows 좌표로 분석하면 다른 값이 노출된다.


위 두 장의 사진은 생성한 윈도우위 좌표를 윈도우 안에 출력해주는 코드이다. 메인으로 사용하고 있는 1번[1] 모니터의 좌-상 위치는 (0, 0)이지만, 서브 모니터로 연결한 좌-상 위치는(0, -1080)이다.
이 출력으로 Windows 좌표계에선 무조건 메인 모니터의 좌-상 위치가 (0, 0)으로 고정됨을 확인 했다.
때문에 단순히 GetClientRect나 GetWindowRect 함수로 좌표계 범위를 구하기엔 한계가 있다. 그러면 어떤 방식으로 찾아야 하는가?
이미 관련 함수를 WIN API에서 제공하고 있다.
EnumDisplayMonitorscopy^
다음 함수는 아래의 원형을 가진다.
EnumDisplayMonitors(HDC hdc, LPCRECT lprcClip, MONITORENUMPROC lpfnEnum, LPARAM dwData);
모든 모니터[2]를 순회한다. 모니터의 범위를 구하기 위함이므로 우리는 첫 번째와 두 번째 값에 nullptr을 전달하고 때에 따라서 마지막 값에도 nullptr을 넣어도 된다.
각 모니터를 순회하면서 세 번째 인자로 넘긴 함수를 실행하는데, 그 함수 원형은 다음과 같다.
lpfnEnumcopy^
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdc, LPRECT monitorRect, LPARAM data);
bool 타입 아니고 BOOL 타입
C99 이상 및 C++에서 제공하는 bool 타입이 아니라 int 타입이 typedef로 BOOL로 선언되었다. 때문에 원론적으로 가면 bool !== BOOL이기 때문에 함수를 BOOL로 사용하지 않으면 함수 원형이 다르다는 문제가 발생할 것이다.
각 인자는 앞에서부터 현재 접근한 모니터의 핸들, DC 핸들, 현재 모니터의 좌표값, <EnumDisplayMonitors>에서 전달한 네 번째 인자가 들어간다.
여기에서 중요한 점은, 세번째 인자인 LPRECT monitorRect, 혹은 모니터 핸들로 GetMonitorInfo 함수로 불러들이 데이터는 기준 모니터[3]가 아니라면 값이 음수를 가질 수 있다. 즉, 기준 모니터 좌측이나 상부에 위치하도록 설정을 한 경우에는 음수를 가지게 된다는 말이다.
바탕화면에 그리기copy^
원래 계획인 바탕화면에 (아이콘 뒤에) 그리기 작업은 WorkerW 프로세스에 그리는 것으로 한다. WorkerW 프로세스 영역은 디스플레이가 연결 될 때마다 업데이트가 이루어진다.[4]
WorkerWcopy^
WorkerW는 각 방향에서 가장 값이 큰 모니터의 값을 기반으로 구역이 생성된다. 만일 아래와 같은 방식으로 모니터를 구현하면


WorkerW는 3번 모니터의 Left 값, 4번 모니터의 Top값, 2번 모니터의 Right 및 Bottom 값을 기반으로 크기가 정해진다.
Windows상의 기준 좌표는 1번 모니터(Left, Top)를 (0, 0)으로 구성해 처리한다. 그러나 WorkerW 내부의 좌표는 3번 모니터의 Left값, 4번 모니터의 Top값이 (0, 0)으로 동작한다.
좌표 계산하기copy^
그럼 이렇게 차이가 나는 부분을 그릴 때마다 직접 다 계산을 해서 넣어주어야 하는가 하면, 그건 또 아니다. 다행스럽게도 이런 문제는 MS팀에서 이미 파악을 하고 있으니, ScreenToClient 라는 함수를 제공한다. Screen은 Windows 좌표계를 따르고, Client는 Window 좌표계를 따르는데, 이 함수가 Windows 좌표계를 윈도우 좌표계로 전환해준다. 따라서 이 함수를 이용하면 원하는 모니터에 바탕화면에 이미지를 그리는 등의 행위를 할 수 있다.
결과 확인copy^
다음 이미지를 통해 잘 동작함을 확인했다.

주 모니터에는 0, 부 모니터에는 1이 적혀 있다.
'DEV > C C++' 카테고리의 다른 글
C++ 레퍼런스 타입 (0) | 2021.10.07 |
---|---|
printf 이진수 출력(사용자 지정 서식지정자 구현) (0) | 2021.09.14 |
PC 카카오톡 AD 제거 (0) | 2021.06.25 |
회전 사각형을 외접하는 사각형 (0) | 2021.05.26 |
템플릿 클래스를 상속하는 템플릿 클래스 (0) | 2021.05.21 |