Поддержка мультиоконного режима в операционной системе семейства Windows

в 19:53, , рубрики: Песочница, метки: ,

В статье рассказывается, как осуществить поддержку мультиоконного режима в операционной системе семейства Windows.

Перед тем, как приступить к работе с множеством мониторов необходимо их перечислить. Для этого можно воспользоваться функцией EnumDisplayMonitors. Эта функция позволит получить описатели ( HMONITOR ) всех мониторов из, которых можно достать необходимую информацию.

BOOL EnumDisplayMonitors(
__in  HDC hdc,
__in  LPCRECT lprcClip,
__in  MONITORENUMPROC lpfnEnum,
__in  LPARAM dwData);

Для перечисления мониторов в системе все параметры, кроме функции обратного вызова, достаточно установить в NULL. Для удобства можно сложить информацию о мониторах в вектор, который будет заполняться по мере вызова CALLBACK- функции.

BOOL CALLBACK EnumMonitorsProc(HMONITOR hMonitor, HDC, LPRECT rect, LPARAM lParam)
{
m_vectAllMonitors.push_back( hMonitor );
return true;
}


Хочу заметить, что при первом вызове этой функции мы получаем описатель первичного (основного) монитора.
Информацию о координатах относительно первичного монитора и названий мониторов можно узнать с помощью функции:

BOOL GetMonitorInfo(
  __in   HMONITOR hMonitor,
  __out  LPMONITORINFO lpmi);

Первый параметр – описатель монитора.
Второй параметр – структура данных с информацией о мониторе.
Расмотрим структуру MONITORINFO:

typedef struct tagMONITORINFO {
  DWORD cbSize;
  RECT  rcMonitor;
  RECT  rcWork;
  DWORD dwFlags;
} MONITORINFO, *LPMONITORINFO;

cbSize — размер структуры в байтах.
rcMonitor – определяет RECT монитора, выраженные в виртуальных экранных координатах. Если монитор не является основным монитором, некоторые из координат монитора могут быть отрицательными.
rcWork – определяет рабочей область монитора, выраженные в виртуальных экранных координатах. Если монитор не является основным, некоторые из координат монитора могут быть отрицательными.
dwFlags — атрибуты монитора. MONITORINFOF_PRIMARY – первичный монитор.
Имеется расширенная структура данных MONITORINFOEX, из которой можно узнать имя монитора.
Имея координаты областей различных мониторов, можно осуществлять работу с ними.

Рассмотрим пример. Необходимо создать окно на два монитора, каждую область окна ( соответствующую области отдельного монитора )залить разным цветом и вывести имя дисплея. Для реализации поставленной задачи необходимо сделать окно размер, которого будет соответствовать двум мониторам. Используя методы описанные выше можно узнать координаты двух мониторов и создать окно по их крайним значениям.

hwndCover = ::CreateWindowEx(0, TEXT("Static"), TEXT("Window"), SS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, lpmi1.rcWork.left, lpmi1.rcWork.top , lpmi2.rcWork.right ,lpmi2.rcWork.bottom, ss.fHideIcons?hBack:hSysLvw, NULL, NULL, NULL);

Здесь lpmi1 и lpmi2 – структуры типа MONITORINFO в которых хранится информация о первом и втором мониторе.
Отрисовка областей окна будет реализована через функцию Rectangle с использованием кисти. Благодаря тому, что мы имеем описатели мониторов, мы можем узнать необходимые координаты, соответствующие координатам мониторов, для заливки областей окна и вывода текста.

case WM_PAINT:
   {
   hdc = BeginPaint(hWnd, &ps);
   RECT rcWorck;
   GetClientRect( hWnd, &rcWorck );
   int nCorrectX =  (m_veclpmi[1].rcWork.right - rcWorck.right) / 2; // correct size for left window border
 
   // Draw first rectangle on first Monitor
   HBRUSH hbrushFirstMonitor;
   hbrushFirstMonitor = CreateSolidBrush( RGB( 0, 255, 0) );
   SelectObject( hdc, hbrushFirstMonitor );
   int nsize = 0;
   while( m_veclpmi[0].szDevice[nsize] != '' )
      nsize++;
   Rectangle( hdc, m_veclpmi[0].rcWork.left,  m_veclpmi[0].rcWork.top, m_veclpmi[0].rcWork.right - nCorrectX, m_veclpmi[0].rcWork.bottom );
   TextOut( hdc, (m_veclpmi[0].rcWork.right - nCorrectX) / 2, m_veclpmi[0].rcWork.bottom /2 ,  m_veclpmi[0].szDevice, nsize);
   DeleteObject( hbrushFirstMonitor );
 
   // Draw first rectangle on secod Monitor
   HBRUSH hbrushSecondMonitor;
   hbrushSecondMonitor = CreateSolidBrush( RGB( 0, 255, 255 ) );
   SelectObject( hdc, hbrushSecondMonitor );
   nsize = 0;
   while( m_veclpmi[0].szDevice[nsize] != '' )
   nsize++;
   Rectangle( hdc, m_veclpmi[1].rcWork.left - nCorrectX,  m_veclpmi[1].rcWork.top, m_veclpmi[1].rcWork.right , m_veclpmi[1].rcWork.bottom );
   TextOut( hdc,  (m_veclpmi[1].rcWork.right - nCorrectX) / 2  + (m_veclpmi[0].rcWork.right - nCorrectX) / 2, m_veclpmi[1].rcWork.bottom / 2,  m_veclpmi[1].szDevice, nsize);
   DeleteObject( hbrushSecondMonitor );
 
 
     EndPaint(hWnd, &ps);
   }
break;

image

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js