- •Содержание
- •Управление памятью: хорошо, плохо и ужасно
- •Сегментированная память
- •Промежуточные решения
- •И, наконец, 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
- •Компонент фабрика классов
- •Управление временем жизни сервера
- •Клиент открытого компонента
- •Заключение
144
Инициирование диалога DDE
Впрограмме SHOWPOP1 диалог инициируется после вызова в WinMain функции UpdateWindow путем отправки из WndProc асинхронного, определяемого пользователем сообщения WM_USER_INITIATE. Как правило клиент инициирует диалог с помощью команды меню.
Вответ на это, определяемое пользователем сообщение, WndProc вызывает функцию GlobalAddAtom для создания атомов для имени приложения сервера ("DdePop1") и имени раздела ("US_Population"). WndProc посылает широковещательное асинхронное сообщение WM_DDE_INITIATE с помощью вызова функции SendMessage с
описателем окна HWND_BROADCAST.
Как мы знаем, сервер, который ищет совпадения атомов приложения и раздела, должен отправить клиенту ответное асинхронное сообщение WM_DDE_ACK. Поскольку это сообщение асинхронное, то есть оно посылается функцией SendMessage, а не PostMessage, то клиент получит сообщение WM_DDE_ACK раньше, чем завершится исходный вызов функции SendMessage для посылки сообщения WM_DDE_INITIATE. WndProc обрабатывает сообщение WM_DDE_ACK, сохраняя описатель окна сервера в переменной hwndServer, и удаляя атомы, сопутствующие сообщению.
Если клиент рассылает широковещательное сообщение WM_DDE_INITIATE с именами приложения и раздела равными NULL, он должен быть готов к получению нескольких сообщений WM_DDE_ACK от каждого сервера, который может удовлетворить его запрос. В этом случае клиент должен решить, услугами какого сервера ему воспользоваться. Остальным нужно отправить синхронные сообщения WM_DDE_TERMINATE для завершения диалога.
Возможна ситуация, когда hwndServer будет равным NULL и после вызова функции SendMessage для посылки сообщения WM_DDE_INITIATE. Это означает, что программа DDEPOP1 не запущена в системе. В этом случае WndProc пытается запустить программу DDEPOP1, используя для этого вызов функции WinExec. Вызов функции WinExec для загрузки программы DDEPOP1 ищет ее в текущем каталоге и в каталогах, указанных в переменной окружения PATH. Затем WndProc снова рассылает асинхронное сообщение WM_DDE_INITIATE. Если hwndServer по-прежнему равен NULL, то WndProc выводит на экран окно сообщений, извещающее пользователя о наличии ошибки.
Далее, для каждого штата, из перечисленных в структуре pop, WndProc с помощью вызова функции GlobalAlloc выделяет структуру DDEADVISE. Флагу fAckReq присваивается значение TRUE (означающее, что сервер должен послать синхронное сообщение WM_DDE_DATA с полем fAckReq структуры DDEDATA равным NULL). Флагу fDeferUpd ("отсроченное обновление — deferred update") присваивается значение FALSE (означающее не теплую связь, а горячую), и полю cfFormat присваивается значение CF_TEXT. Функция GlobalAddAtom добавляет атом для двухбуквенной аббревиатуры штата.
Эта структура и атом передаются серверу, когда программа SHOWPOP1 отправляет ему синхронное сообщение WM_DDE_ADVISE. Если вызов функции PostMessage неудачен (что может случиться, если программа DDEPOP1 внезапно завершилась), то программа SHOWPOP1 освобождает блок памяти, удаляет атом и покидает цикл. В противном случае программа SHOWPOP1 ожидает сообщения WM_DDE_ACK, используя для этого функцию PeekMessage. Как сказано в документации по DDE, клиент удаляет атом, сопутствующий сообщению, и, если сервер отвечает негативным подтверждением, освобождает также блок памяти.
Вполне вероятно, что за сообщением WM_DDE_ACK от сервера последует сообщение WM_DDE_DATA для элемента данных. По этой причине, программа SHOWPOP1 вызывает функцию PeekMessage и функцию DispatchMessage для извлечения сообщений DDE из очереди сообщений и передачи их в WndProc.
Сообщение WM_DDE_DATA
Следом за сообщениями WM_DDE_ADVISE WndProc будет получать от сервера сообщения WM_DDE_DATA, содержащие обновленные данные о населении. Как ранее отмечалось, lParam является объектом памяти, в котором находятся описатель блока памяти со структурой DDEDATA и атом, идентифицирующий элемент данных. Эта информация извлекается из сообщения функцией UnpackDDElParam.
Программа SHOWPOP1 проверяет, равно ли поле cfFormat структуры DDEDATA значению CF_TEXT. (Нам конечно известно, что в программе DDEPOP1 используется только формат CF_TEXT, но для завершенности программы такая проверка необходима.) Затем с помощью функции GlobalGetAtomName она получает текстовую строку, соответствующую атому элемента. Эта текстовая строка представляет собой двухбуквенную аббревиатуру штата.
Используя цикл for программа SHOWPOP1 просматривает список штатов в поисках совпадения. Если таковое обнаруживается, она копирует данные о населении из структуры DDEDATA в массив szPopulation, преобразуя его в длинное целое с помощью функции языка С atol, сохраняет его в структуре pop и делает окно недействительным.
Теперь осталось только освободить захваченные ресурсы. Если от клиента требуется подтверждение сообщения WM_DDE_DATA, WndProc его посылает. Если подтверждения не требуется (или вызов функции PostMessage