본문 바로가기

말랑말랑한 이야기

WM_DISPLAYCHANGE 메시지는 중첩 될 수 있다.

윈도우 해상도가 변경되거나 칼라비트가 변경되면 모든 Top-Level 윈도우에 해당 메시지가 전송됩니다. 이때 wParam에는 칼라비트가 그리고 lParam에는 변경된 해상도 값이 인자로 넘어옵니다. 윈도우7에서 테스트해보니 wParam, lParam에 항상 0가 오더군요. 아무튼 이때 GetSystemMetric() 함수로 해상도나 비트 값을 얻어서 사용하면 되기 때문에 큰 문제는 아닙니다. 문제는 이 메시지가 중첩되서 오는 경우가 있다는 겁니다. 즉 해당 메시지를 처리하는 로직이 끝나기도 전에 다시 해당 메시지가 들어오는 경우가 있습니다. 전체화면 모드 게임 실행중에 Alt+Tab 키를 눌렀을때가 이에 해당합니다. 프로그래밍을 하다보면 로직 처리에 대한 어려움보다 이러한 동기화적인 문제로 발생하는 버그를 찾는데 엄청나게 많은 시간을 빼앗기곤 합니다. 타이밍적인 문제이기 때문에 에러 발생이 일관적이지 않죠.
이해하기 쉽게 예를들어보죠. 해상도가 변경되면 변경된 해상도에 따라 아이콘 위치를 정렬하는 기능이 있다고하죠. 해상도 마다 위치할 아이콘의 위치 정보를 담은 파일이 있습니다. 해상도 변경 이벤트를 감지하면 파일을 읽고 적용할 위치 정보를 vector에다가 넣어둡니다. 그리고 벡터를 차례대로 순회하면서 실제 아이콘의 위치를 정렬합니다. 이때 벡터 순회중에 다시 해상도 변경 이벤트가 들어옵니다. 그럼 순회중이던 백터는 참조를 잃게되고 알수 없는 버그로 이어집니다. 디버깅이 매우 어려워지는 상황이죠. 요점은 이렇습니다. 해당 메시지를 처리하기 위해선 처리 로직이 끝나기전까지 재진입하지 않도록 플래그 변수를 두시거나, 아니면 사용자 정의 메시지를 만들어서 메시지큐에 Post하시기 바랍니다.