
- •Содержание
- •Управление памятью: хорошо, плохо и ужасно
- •Сегментированная память
- •Промежуточные решения
- •И, наконец, 32 бита
- •Выделение памяти
- •Библиотечные функции C
- •Фундаментальное выделение памяти в Windows 95
- •Перемещаемая память
- •Удаляемая память
- •Другие функции и флаги
- •Хорошо ли это?
- •Функции работы с "кучей"
- •Файловый ввод/вывод
- •Старый путь
- •Отличия Windows 95
- •Ввод/вывод с использованием файлов, проецируемых в память
- •Режимы многозадачности
- •Многозадачность в DOS
- •Невытесняющая многозадачность
- •Решения, использующие многопоточность
- •Многопоточная архитектура
- •Коллизии, возникающие при использовании потоков
- •Преимущества Windows
- •Новая программа! Усовершенствованная программа! Многопоточная!
- •Многопоточность в Windows 95
- •И снова случайные прямоугольники
- •Задание на конкурсе программистов
- •Решение с использованием многопоточности
- •О пользе использования функции Sleep
- •Синхронизация потоков
- •Критический раздел
- •Объект Mutex
- •Программа BIGJOB1
- •Объект Event
- •Локальная память потока
- •Печать, буферизация и функции печати
- •Контекст принтера
- •Формирование параметров для функции CreateDC
- •Измененная программа DEVCAPS
- •Вызов функции PrinterProperties
- •Проверка возможности работы с битовыми блоками (BitBlt)
- •Программа FORMFEED
- •Печать графики и текста
- •Каркас программы печати
- •Прерывание печати с помощью процедуры Abort
- •Реализация процедуры прерывания
- •Добавление диалогового окна печати
- •Добавление печати к программе POPPAD
- •Обработка кодов ошибок
- •Техника разбиения на полосы
- •Разбиение на полосы
- •Реализация разбиения страницы на полосы
- •Принтер и шрифты
- •Глава 16 Буфер обмена
- •Простое использование буфера обмена
- •Стандартные форматы данных буфера обмена
- •Передача текста в буфер обмена
- •Получение текста из буфера обмена
- •Открытие и закрытие буфера обмена
- •Использование буфера обмена с битовыми образами
- •Метафайл и картина метафайла
- •Более сложное использование буфера обмена
- •Использование нескольких элементов данных
- •Отложенное исполнение
- •Нестандартные форматы данных
- •Соответствующая программа просмотра буфера обмена
- •Цепочка программ просмотра буфера обмена
- •Функции и сообщения программы просмотра буфера обмена
- •Простая программа просмотра буфера обмена
- •Основные концепции
- •Приложение, раздел и элемент
- •Типы диалогов
- •Символьные строки и атомы
- •Программа сервер DDE
- •Программа DDEPOP1
- •Сообщение WM_DDE_INITIATE
- •Оконная процедура ServerProc
- •Функция PostDataMessage программы DDEPOP1
- •Сообщение WM_DDE_ADVISE
- •Обновление элементов данных
- •Сообщение WM_DDE_UNADVISE
- •Сообщение WM_DDE_TERMINATE
- •Программа-клиент DDE
- •Инициирование диалога DDE
- •Сообщение WM_DDE_DATA
- •Сообщение WM_DDE_TERMINATE
- •Управляющая библиотека DDE
- •Концептуальные различия
- •Реализация DDE с помощью DDEML
- •Элементы MDI
- •Windows 95 и MDI
- •Пример программы
- •Три меню
- •Инициализация программы
- •Создание дочерних окон
- •Дополнительная информация об обработке сообщений в главном окне
- •Дочерние окна документов
- •Освобождение захваченных ресурсов
- •Сила оконной процедуры
- •Основы библиотек
- •Библиотека: одно слово, множество значений
- •Пример простой DLL
- •Разделяемая память в DLL
- •Библиотека STRLIB
- •Точка входа/выхода библиотеки
- •Программа STRPROG
- •Работа программы STRPROG
- •Разделение данных между экземплярами программы STRPROG
- •Некоторые ограничения библиотек
- •Динамическое связывание без импорта
- •Библиотеки, содержащие только ресурсы
- •Глава 20 Что такое OLE?
- •Основы OLE
- •Связь с библиотеками OLE
- •Расшифровка кода результата
- •Интерфейсы модели составного объекта (COM-интерфейсы)
- •Услуги интерфейса IUnknown
- •Является ли OLE спецификацией клиент/сервер?
- •Сервер закрытого компонента
- •IMALLOC.DLL
- •Теперь о макросах
- •Услуги, предоставляемые интерфейсом IUnknown
- •Клиент закрытого компонента
- •Сервер открытого компонента
- •Назначение реестра
- •Способы генерации и использования идентификаторов CLSID
- •Компонент фабрика классов
- •Управление временем жизни сервера
- •Клиент открытого компонента
- •Заключение

159
Для поддержки MDI в Windows 95 имеется один класс окна, пять функций, две структуры данных и двенадцать сообщений. О классе окна MDICLIENT и структурах данных CLIENTCREATESTRUCT и MDICREATESTRUCT
уже упоминалось. Две из пяти функций заменяют в приложениях MDI функцию DefWindowProc: вместо вызова функции DefWindowProc для всех необрабатываемых сообщений, оконная процедура главного окна вызывает функцию DefFrameProc, а оконная процедура дочернего окна вызывает функцию DefMDIChildProc. Другая характерная функция MDI TranslateMDISysAccel используется также, как функция TranslateAccelerator, о которой рассказывалось в главе 10. В Windows 3 добавлена функция ArrangeIconicWindows, но одно из специальных сообщений MDI делает ее использование не нужным в программах MDI.
Если в дочерних окнах MDI выполняются какие-то протяженные во времени операции, рассмотрите возможность их запуска в отдельных потоках. Это позволит пользователю покинуть "задумавшееся" дочернее окно и продолжить работу в другом окне, пока первое дочернее окно решает свою задачу в фоновом режиме. В Windows 95 специально для этой цели имеется новая функция CreateMDIWindow. Поток вызывает функцию CreateMDIWindow для создания дочернего окна MDI; таким образом окно действует исключительно внутри контекста потока. В программе, имеющей один поток, для создания дочернего окна функция CreateMDIWindow не требуется, поскольку то же самое выполняет сообщение WM_MDICREATE.
Подошло время для примера однопотоковой программы, в которой будет показано девять из двенадцати сообщений MDI. (Оставшиеся три обычно не требуются.) Эти сообщения имеют префикс WM_MDI. Главное окно посылает одно из этих сообщений окну-администратору для выполнения какой-либо операции над дочерним окном или для получения информации о дочернем окне. (Например, главное окно посылает сообщение WM_MDICREATE окну-администратору для создания дочернего окна.) Исключение составляет сообщение WM_MDIACTIVATE: в то время, как главное окно может послать это сообщение окну-администратору для активизации одного из дочерних окон, окно-администратор также посылает сообщение тем дочерним окнам, которые будут активизированы и тем, которые потеряют активность, чтобы проинформировать их о предстоящем изменении.
Пример программы
Программа MDIDEMO, представленная на рис. 18.2, иллюстрирует основы написания приложения MDI.
MDIDEMO.MAK
#------------------------
# MDIDEMO.MAK make file
#------------------------
mdidemo.exe : mdidemo.obj mdidemo.res
$(LINKER) $(GUIFLAGS) -OUT:mdidemo.exe mdidemo.obj mdidemo.res $(GUILIBS)
mdidemo.obj : mdidemo.c mdidemo.h $(CC) $(CFLAGS) mdidemo.c
mdidemo.res : mdidemo.rc mdidemo.h $(RC) $(RCVARS) mdidemo.rc
MDIDEMO.C
/*-------------------------------------------------------- |
|
MDIDEMO.C -- |
Multiple Document Interface Demonstration |
|
(c) Charles Petzold, 1996 |
-------------------------------------------------------- |
*/ |
#include <windows.h> #include <stdlib.h> #include "mdidemo.h"
LRESULT CALLBACK FrameWndProc (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK CloseEnumProc(HWND, LPARAM);
LRESULT CALLBACK HelloWndProc (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK RectWndProc (HWND, UINT, WPARAM, LPARAM);
// structure for storing data unique to each Hello child window
typedef struct tagHELLODATA
{
UINT iColor;

160
COLORREF clrText;
}
HELLODATA, *LPHELLODATA;
// structure for storing data unique to each Rect child window
typedef struct tagRECTDATA
{
short cxClient; short cyClient;
}
RECTDATA, *LPRECTDATA;
// global variables
char |
szFrameClass[] |
= |
"MdiFrame"; |
char |
szHelloClass[] |
= |
"MdiHelloChild"; |
char |
szRectClass[] |
= "MdiRectChild"; |
|
HINSTANCE |
hInst; |
|
|
HMENU |
hMenuInit, hMenuHello, hMenuRect; |
||
HMENU |
hMenuInitWindow, hMenuHelloWindow, hMenuRectWindow; |
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{ |
|
HACCEL |
hAccel; |
HWND |
hwndFrame, hwndClient; |
MSG |
msg; |
WNDCLASSEX |
wndclass; |
hInst = hInstance;
if(!hPrevInstance)
{
// Register the frame window class
wndclass.cbSize |
= sizeof(wndclass); |
wndclass.style |
= CS_HREDRAW | CS_VREDRAW; |
wndclass.lpfnWndProc |
= FrameWndProc; |
wndclass.cbClsExtra |
= 0; |
wndclass.cbWndExtra |
= 0; |
wndclass.hInstance |
= hInstance; |
wndclass.hIcon |
= LoadIcon(NULL, IDI_APPLICATION); |
wndclass.hCursor |
= LoadCursor(NULL, IDC_ARROW); |
wndclass.hbrBackground |
=(HBRUSH)(COLOR_APPWORKSPACE + 1); |
wndclass.lpszMenuName |
= NULL; |
wndclass.lpszClassName |
= szFrameClass; |
wndclass.hIconSm |
= LoadIcon(NULL, IDI_APPLICATION); |
RegisterClassEx(&wndclass);
// Register the Hello child window class
wndclass.cbSize |
= sizeof(wndclass); |
wndclass.style |
= CS_HREDRAW | CS_VREDRAW; |
wndclass.lpfnWndProc |
= HelloWndProc; |
wndclass.cbClsExtra |
= 0; |
wndclass.cbWndExtra |
= sizeof(HANDLE); |
wndclass.hInstance |
= hInstance; |
wndclass.hIcon |
= LoadIcon(NULL, IDI_APPLICATION); |
wndclass.hCursor |
= LoadCursor(NULL, IDC_ARROW); |
wndclass.hbrBackground |
=(HBRUSH) GetStockObject(WHITE_BRUSH); |
wndclass.lpszMenuName |
= NULL; |
wndclass.lpszClassName |
= szHelloClass; |
wndclass.hIconSm |
= LoadIcon(NULL, IDI_APPLICATION); |

161
RegisterClassEx(&wndclass);
// Register the Rect child window class
wndclass.cbSize |
= sizeof(wndclass); |
wndclass.style |
= CS_HREDRAW | CS_VREDRAW; |
wndclass.lpfnWndProc |
= RectWndProc; |
wndclass.cbClsExtra |
= 0; |
wndclass.cbWndExtra |
= sizeof(HANDLE); |
wndclass.hInstance |
= hInstance; |
wndclass.hIcon |
= LoadIcon(NULL, IDI_APPLICATION); |
wndclass.hCursor |
= LoadCursor(NULL, IDC_ARROW); |
wndclass.hbrBackground |
=(HBRUSH) GetStockObject(WHITE_BRUSH); |
wndclass.lpszMenuName |
= NULL; |
wndclass.lpszClassName |
= szRectClass; |
wndclass.hIconSm |
= LoadIcon(NULL, IDI_APPLICATION); |
RegisterClassEx(&wndclass);
}
// Obtain handles to three possible menus & submenus
hMenuInit = LoadMenu(hInst, "MdiMenuInit");
hMenuHello = LoadMenu(hInst, "MdiMenuHello");
hMenuRect = LoadMenu(hInst, "MdiMenuRect");
hMenuInitWindow = GetSubMenu(hMenuInit, INIT_MENU_POS);
hMenuHelloWindow = GetSubMenu(hMenuHello, HELLO_MENU_POS);
hMenuRectWindow = GetSubMenu(hMenuRect, RECT_MENU_POS);
// Load accelerator table
hAccel = LoadAccelerators(hInst, "MdiAccel");
// Create the frame window
hwndFrame = CreateWindow(szFrameClass, "MDI Demonstration", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, hMenuInit, hInstance, NULL);
hwndClient = GetWindow(hwndFrame, GW_CHILD); ShowWindow(hwndFrame, iCmdShow); UpdateWindow(hwndFrame);
// Enter the modified message loop
while(GetMessage(&msg, NULL, 0, 0))
{
if(!TranslateMDISysAccel(hwndClient, &msg) &&
!TranslateAccelerator(hwndFrame, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Clean up by deleting unattached menus
DestroyMenu(hMenuHello);
DestroyMenu(hMenuRect);
return msg.wParam;
}

162
LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{ |
|
static HWND |
hwndClient; |
CLIENTCREATESTRUCT |
clientcreate; |
HWND |
hwndChild; |
MDICREATESTRUCT |
mdicreate; |
switch(iMsg)
{
case WM_CREATE : // Create the client window
clientcreate.hWindowMenu = hMenuInitWindow; clientcreate.idFirstChild = IDM_FIRSTCHILD;
hwndClient = CreateWindow("MDICLIENT", NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE, 0, 0, 0, 0, hwnd,(HMENU) 1, hInst, (LPSTR) &clientcreate);
return 0;
case WM_COMMAND : |
|
switch(wParam) |
|
{ |
|
case IDM_NEWHELLO : |
// Create a Hello child window |
mdicreate.szClass |
= szHelloClass; |
mdicreate.szTitle |
= "Hello"; |
mdicreate.hOwner |
= hInst; |
mdicreate.x |
= CW_USEDEFAULT; |
mdicreate.y |
= CW_USEDEFAULT; |
mdicreate.cx |
= CW_USEDEFAULT; |
mdicreate.cy |
= CW_USEDEFAULT; |
mdicreate.style |
= 0; |
mdicreate.lParam |
= 0; |
hwndChild =(HWND) SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT) &mdicreate);
return 0; |
|
case IDM_NEWRECT : |
// Create a Rect child window |
mdicreate.szClass |
= szRectClass; |
mdicreate.szTitle |
= "Rectangles"; |
mdicreate.hOwner |
= hInst; |
mdicreate.x |
= CW_USEDEFAULT; |
mdicreate.y |
= CW_USEDEFAULT; |
mdicreate.cx |
= CW_USEDEFAULT; |
mdicreate.cy |
= CW_USEDEFAULT; |
mdicreate.style |
= 0; |
mdicreate.lParam |
= 0; |
hwndChild =(HWND) SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT) &mdicreate);
return 0;
case IDM_CLOSE : // Close the active window
hwndChild =(HWND) SendMessage(hwndClient, WM_MDIGETACTIVE, 0, 0);
if(SendMessage(hwndChild, WM_QUERYENDSESSION, 0, 0)) SendMessage(hwndClient, WM_MDIDESTROY,

163
(WPARAM) hwndChild, 0);
return 0;
case IDM_EXIT : |
// Exit the program |
SendMessage(hwnd, WM_CLOSE, 0, 0); return 0;
// messages for arranging windows case IDM_TILE :
SendMessage(hwndClient, WM_MDITILE, 0, 0); return 0;
case IDM_CASCADE :
SendMessage(hwndClient, WM_MDICASCADE, 0, 0); return 0;
case IDM_ARRANGE :
SendMessage(hwndClient, WM_MDIICONARRANGE, 0, 0); return 0;
case IDM_CLOSEALL : // Attempt to close all children
EnumChildWindows(hwndClient, &CloseEnumProc, 0); return 0;
default : // Pass to active child...
hwndChild =(HWND) SendMessage(hwndClient, WM_MDIGETACTIVE, 0, 0);
if(IsWindow(hwndChild)) SendMessage(hwndChild, WM_COMMAND,
wParam, lParam);
break; |
// ...and then to DefFrameProc |
} |
|
break; |
|
case WM_QUERYENDSESSION : |
|
case WM_CLOSE : |
// Attempt to close all children |
SendMessage(hwnd, WM_COMMAND, IDM_CLOSEALL, 0);
if(NULL != GetWindow(hwndClient, GW_CHILD)) return 0;
break; // I.e., call DefFrameProc
case WM_DESTROY : PostQuitMessage(0); return 0;
}
// Pass unprocessed messages to DefFrameProc(not DefWindowProc)
return DefFrameProc(hwnd, hwndClient, iMsg, wParam, lParam);
}
BOOL CALLBACK CloseEnumProc(HWND hwnd, LPARAM lParam)
{
if(GetWindow(hwnd, GW_OWNER)) // Check for icon title return 1;
SendMessage(GetParent(hwnd), WM_MDIRESTORE,(WPARAM) hwnd, 0); if(!SendMessage(hwnd, WM_QUERYENDSESSION, 0, 0))

164
return 1;
SendMessage(GetParent(hwnd), WM_MDIDESTROY,(WPARAM) hwnd, 0); return 1;
}
LRESULT CALLBACK HelloWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static COLORREF clrTextArray[] = { RGB(0, 0, 0), RGB(255, 0, 0), RGB(0, 255, 0), RGB( 0, 0, 255), RGB(255, 255, 255) };
hwndClient, hwndFrame; hdc;
hMenu;
lpHelloData;
ps;
rect;
switch(iMsg)
{
case WM_CREATE :
// Allocate memory for window private data
lpHelloData =(LPHELLODATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HELLODATA));
lpHelloData->iColor = IDM_BLACK; lpHelloData->clrText = RGB(0, 0, 0); SetWindowLong(hwnd, 0,(long) lpHelloData);
// Save some window handles
hwndClient = GetParent(hwnd); hwndFrame = GetParent(hwndClient); return 0;
case WM_COMMAND : switch(wParam)
{
case IDM_BLACK : case IDM_RED : case IDM_GREEN : case IDM_BLUE : case IDM_WHITE :
// Change the text color
lpHelloData =(LPHELLODATA) GetWindowLong(hwnd, 0);
hMenu = GetMenu(hwndFrame); CheckMenuItem(hMenu, lpHelloData->iColor,
MF_UNCHECKED); lpHelloData->iColor = wParam; CheckMenuItem(hMenu, lpHelloData->iColor,
MF_CHECKED);
lpHelloData->clrText = clrTextArray[wParam - IDM_BLACK];
InvalidateRect(hwnd, NULL, FALSE);
}
return 0;
case WM_PAINT :
// Paint the window

165
hdc = BeginPaint(hwnd, &ps);
lpHelloData =(LPHELLODATA) GetWindowLong(hwnd, 0); SetTextColor(hdc, lpHelloData->clrText);
GetClientRect(hwnd, &rect);
DrawText(hdc, "Hello, World!", -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps); return 0;
case WM_MDIACTIVATE :
// Set the Hello menu if gaining focus
if(lParam ==(LPARAM) hwnd) SendMessage(hwndClient, WM_MDISETMENU,
(WPARAM) hMenuHello,(LPARAM) hMenuHelloWindow);
// Check or uncheck menu item
lpHelloData =(LPHELLODATA) GetWindowLong(hwnd, 0); CheckMenuItem(hMenuHello, lpHelloData->iColor,
(lParam ==(LPARAM) hwnd) ? MF_CHECKED : MF_UNCHECKED);
// Set the Init menu if losing focus
if(lParam !=(LPARAM) hwnd)
SendMessage(hwndClient, WM_MDISETMENU,(WPARAM) hMenuInit,
(LPARAM) hMenuInitWindow);
DrawMenuBar(hwndFrame); return 0;
case WM_QUERYENDSESSION : case WM_CLOSE :
if(IDOK != MessageBox(hwnd, "OK to close window?", "Hello", MB_ICONQUESTION | MB_OKCANCEL))
return 0;
break; // I.e., call DefMDIChildProc
case WM_DESTROY :
lpHelloData =(LPHELLODATA) GetWindowLong(hwnd, 0); HeapFree(GetProcessHeap(), 0, lpHelloData); return 0;
}
// Pass unprocessed message to DefMDIChildProc
return DefMDIChildProc(hwnd, iMsg, wParam, lParam);
}
LRESULT CALLBACK RectWndProc(HWND hwnd, UINT iMsg, WPARAM wParam,
LPARAM lParam)
{ |
|
static HWND |
hwndClient, hwndFrame; |
HBRUSH |
hBrush; |
HDC |
hdc; |
LPRECTDATA |
lpRectData; |
PAINTSTRUCT |
ps; |
int |
xLeft, xRight, yTop, yBottom; |
short |
nRed, nGreen, nBlue; |

166
switch(iMsg)
{
case WM_CREATE :
// Allocate memory for window private data
lpRectData =(LPRECTDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RECTDATA));
SetWindowLong(hwnd, 0,(long) lpRectData);
//Start the timer going
SetTimer(hwnd, 1, 250, NULL);
//Save some window handles
hwndClient = GetParent(hwnd); hwndFrame = GetParent(hwndClient); return 0;
case WM_SIZE : // If not minimized, save the window size if(wParam != SIZE_MINIMIZED)
{
lpRectData =(LPRECTDATA) GetWindowLong(hwnd, 0);
lpRectData->cxClient = LOWORD(lParam); lpRectData->cyClient = HIWORD(lParam);
}
break; |
// WM_SIZE must be processed by DefMDIChildProc |
case WM_TIMER : // Display a random rectangle
lpRectData =(LPRECTDATA) GetWindowLong(hwnd, 0);
xLeft |
= rand() % lpRectData->cxClient; |
xRight |
= rand() % lpRectData->cxClient; |
yTop |
= rand() % lpRectData->cyClient; |
yBottom |
= rand() % lpRectData->cyClient; |
nRed |
= rand() & 255; |
nGreen |
= rand() & 255; |
nBlue |
= rand() & 255; |
hdc = GetDC(hwnd);
hBrush = CreateSolidBrush(RGB(nRed, nGreen, nBlue));
SelectObject(hdc, hBrush);
Rectangle(hdc, min(xLeft, xRight), min(yTop, yBottom), max(xLeft, xRight), max(yTop, yBottom));
ReleaseDC(hwnd, hdc); DeleteObject(hBrush); return 0;
case WM_PAINT : |
// Clear the window |
InvalidateRect(hwnd, NULL, TRUE); hdc = BeginPaint(hwnd, &ps); EndPaint(hwnd, &ps);
return 0;
case WM_MDIACTIVATE : // Set the appropriate menu if(lParam ==(LPARAM) hwnd)
SendMessage(hwndClient, WM_MDISETMENU,(WPARAM) hMenuRect,

167
(LPARAM) hMenuRectWindow);
else
SendMessage(hwndClient, WM_MDISETMENU,(WPARAM) hMenuInit,
(LPARAM) hMenuInitWindow);
DrawMenuBar(hwndFrame); return 0;
case WM_DESTROY :
lpRectData =(LPRECTDATA) GetWindowLong(hwnd, 0); HeapFree(GetProcessHeap(), 0, lpRectData); KillTimer(hwnd, 1);
return 0;
}
// Pass unprocessed message to DefMDIChildProc
return DefMDIChildProc(hwnd, iMsg, wParam, lParam);
}
MDIDEMO.RC
/*----------------------------
MDIDEMO.RC resource script
----------------------------*/ |
|
#include <windows.h> |
|
#include "mdidemo.h" |
|
MdiMenuInit MENU |
|
{ |
|
POPUP "&File" |
|
{ |
|
MENUITEM "New &Hello", |
IDM_NEWHELLO |
MENUITEM "New &Rectangles", |
IDM_NEWRECT |
MENUITEM SEPARATOR |
|
MENUITEM "E&xit", |
IDM_EXIT |
} |
|
} |
|
MdiMenuHello MENU |
|
{ |
|
POPUP "&File" |
|
{ |
|
MENUITEM "New &Hello", |
IDM_NEWHELLO |
MENUITEM "New &Rectangles", |
IDM_NEWRECT |
MENUITEM "&Close", |
IDM_CLOSE |
MENUITEM SEPARATOR |
|
MENUITEM "E&xit", |
IDM_EXIT |
} |
|
POPUP "&Color" |
|
{ |
|
MENUITEM "&Black", |
IDM_BLACK |
MENUITEM "&Red", |
IDM_RED |
MENUITEM "&Green", |
IDM_GREEN |
MENUITEM "B&lue", |
IDM_BLUE |
MENUITEM "&White", |
IDM_WHITE |
} |
|
POPUP "&Window" |
|
{ |
|
MENUITEM "&Cascade\tShift+F5", |
IDM_CASCADE |
MENUITEM "&Tile\tShift+F4", |
IDM_TILE |
MENUITEM "Arrange &Icons", |
IDM_ARRANGE |
MENUITEM "Close &All", |
IDM_CLOSEALL |
} |
|
} |
|
MdiMenuRect MENU

168
{ |
|
|
POPUP "&File" |
|
|
{ |
|
|
MENUITEM "New &Hello", |
IDM_NEWHELLO |
|
MENUITEM "New &Rectangles", |
IDM_NEWRECT |
|
MENUITEM "&Close", |
IDM_CLOSE |
|
MENUITEM SEPARATOR |
|
|
MENUITEM "E&xit", |
IDM_EXIT |
|
} |
|
|
POPUP "&Window" |
|
|
{ |
|
|
MENUITEM "&Cascade\tShift+F5", |
IDM_CASCADE |
|
MENUITEM "&Tile\tShift+F4", |
IDM_TILE |
|
MENUITEM "Arrange &Icons", |
IDM_ARRANGE |
|
MENUITEM "Close &All", |
IDM_CLOSEALL |
|
} |
|
|
} |
|
|
MdiAccel ACCELERATORS |
|
|
{ |
|
|
VK_F5, IDM_CASCADE, VIRTKEY, SHIFT |
|
|
VK_F4, IDM_TILE, |
VIRTKEY, SHIFT |
|
} |
|
|
MDIDEMO.H |
|
|
/*----------------------- |
|
|
MDIDEMO.H header file |
|
|
----------------------- |
*/ |
|
#define EXPORT |
__declspec(dllexport) |
|
#define INIT_MENU_POS |
0 |
|
#define HELLO_MENU_POS |
2 |
|
#define RECT_MENU_POS |
1 |
|
#define IDM_NEWHELLO |
10 |
|
#define IDM_NEWRECT |
11 |
|
#define IDM_CLOSE |
12 |
|
#define IDM_EXIT |
13 |
|
#define IDM_BLACK |
20 |
|
#define IDM_RED |
21 |
|
#define IDM_GREEN |
22 |
|
#define IDM_BLUE |
23 |
|
#define IDM_WHITE |
24 |
|
#define IDM_TILE |
30 |
|
#define IDM_CASCADE |
31 |
|
#define IDM_ARRANGE |
32 |
|
#define IDM_CLOSEALL |
33 |
|
#define IDM_FIRSTCHILD 100
Рис. 18.2 Текст программы MDIDEMO
Программа MDIDEMO поддерживает два типа предельно простых окон документов: в одном в центре рабочей области выводится фраза "Hello, World!", а во втором отображается последовательность случайных прямоугольников. (В листингах исходных текстов программы и именах идентификаторов они упоминаются как документ Hello и документ Rect.) С каждым из этих двух типов окон документов связано свое меню. Окно документа, в котором выводятся слова "Hello, World!", имеется меню, дающее возможность изменять цвет символов.