Программирование для Windows NT

       

Создание нового дочернего окна


При выборе из меню File строки New создается новое дочернее MDI-окно и задача для него. Первое действие выполняется с помощью функции CreateMDIWindow, специально созданной для мультизадачных MDI-приложений. Задача создается при помощи функции CreateThread. Рассмотрим процесс создания дочернего окна подробнее.

Параметры фукнции CreateMDIWindow являются комбинацией значений, сохраняемых в структуре MDICREATESTRUCT полюс идентификатор окна Client Window. Напомним, что адрес этой структуры передается через второй параметр сообщения WM_MDICREATE, предназначенного для создания дочерних MDI-окон в однозадачных приложениях. Вот как создается такое окно в нашем приложении:

hwndChild = CreateMDIWindow(

  LPSTR)szChildClassName,        // класс окна

  "MDI Child Window",            // заголовок окна

  0,                             // дополнительные стили

  CW_USEDEFAULT, CW_USEDEFAULT,  // размеры окна

  CW_USEDEFAULT, CW_USEDEFAULT,  //    Document Window

  hwndClient,            // идентификатор окна Client Window

  hInst,                         // идентификатор приложения

  0);                            // произвольное значение

Вы можете сравнить это со способом, описанным нами в 17 томе “Библиотеки системного программиста” в разделе “Создание и уничтожение окна Document Window”.

Для каждого дочернего окна мы создаем и инициализируем структуру типа CHILD_WINDOW_TAG, содержащую такие значения, как идентификатор задачи, запущенной для окна, признак активности задачи и критическую секцию. Память для структуры мы получаем простейшим способом - с помощью функции malloc:



lpTag = malloc(sizeof(CHILD_WINDOW_TAG));

Далее в процессе инициализации этой структуры мы устанавливаем начальное знзачение для признака активности и выполняем инициализацию критической секции:

lpTag->fActive = 1;

InitializeCriticalSection(&(lpTag->csChildWindowPaint));

Это нужно сделать обязательно до запуска задачи, которая будет пользоваться критической секцией и проверять флаг активности.


Адрес структуры мы сохраняем в области данных окна, используя для этого функцию SetWindowLong:

SetWindowLong(hwndChild, GWL_USERDATA, (LONG)lpTag);

Впоследствии этот адрес будет извлечен функцией задачи.

На следующем шаге мы выполняем создание задачи для дочернего MDI-окна, которая будет заниматься рисованием произвольных эллипсов. Для запуска используется функция CreateThread:

hThread = CreateThread(NULL, 0,

  (LPTHREAD_START_ROUTINE)ThreadRoutine,

  (LPVOID)hwndChild, 0,(LPDWORD)&dwIDThread);

В качестве третьего параметра мы передаем этой функции адрес функции задачи ThreadRoutine, а в качестве четвертого - идентификатор дочернего MDI-окна, который необходим для выполенния рисования.

Заметим, что мы могли бы передать через четвертый параметр функции CreateThread адрес структуры CHILD_WINDOW_TAG, дополнив эту структуру полем для хранения идентификатора дочернего MDI-окна. При этом функция задачи получила бы доступ ко всем необходимым ей параметрам. Однако в нашем приложении мы продемонстрировали оба способа, связанных с использованием параметра функции задачи и памяти окна.

После того как задача создана, ее идентификатор сохраняется в структуре CHILD_WINDOW_TAG:

lpTag->hThread = hThread;

В дальнейшем это значение будет использовано для управления задачей - для ее приостановки, возобновления выполнения, изменения относительного приоритета и так далее.

На заключительном шаге в заголовке дочернего MDI-окна отображается системный номер задачи, который записывается функцией CreateThread в переменную dwIDThread:

sprintf(szBuf, "Thread ID = %lX", dwIDThread);

SetWindowText(hwndChild, szBuf);

Напомним, что системный номер задачи и ее идентификатор - разные по смыслу и значению величины.


Содержание раздела