- •Содержание
- •Управление памятью: хорошо, плохо и ужасно
- •Сегментированная память
- •Промежуточные решения
- •И, наконец, 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
- •Компонент фабрика классов
- •Управление временем жизни сервера
- •Клиент открытого компонента
- •Заключение
92
AbortDoc(hdcPrn);
else
if(EndPage(hdcPrn))
EndDoc(hdcPrn);
}
if(!bUserAbort)
{
EnableWindow(hwnd, TRUE);
DestroyWindow(hDlgPrint);
}
DeleteDC(hdcPrn);
return bError || bUserAbort;
}
Рис. 15.13 Программа PRINT4
Программа PRINT4 отличается от программы PRINT3 только несколькими особенностями. Обратите внимание, что вместо прямоугольника, проходящего по границе страницы в целом, функция Rectangle печатает его для каждой полосы. Это позволяет вам увидеть то, как для конкретного принтера реализуется разбиение на полосы. Структура кода, выполняющего печать, такова:
if(StartDoc(hdcPrn, &di) > 0 && StartPage(hdcPrn) > 0 &&
ExtEscape(hdcPrn, NEXTBAND, 0, NULL, sizeof(rect),(LPSTR) &rect) > 0)
{
while(!IsRectEmpty(&rect) && !UserAbort)
{
[вызовы функций GDI]
if(ExtEscape(hdcPrn, NEXTBAND, 0, NULL, sizeof(rect),(LPSTR)&rect) < 0)
{ |
// если ошибка, установить флаг и |
bError = TRUE; |
|
break; |
// выйти из цикла |
} |
|
}
}
else
bError = TRUE;
Цикл while выполняется только в том случае, если прямоугольник не пуст и, если пользователь не отказался от печати в окне диалога. Программа PRINT4 должна проверять возвращаемое значение каждого вызова функции ExtEscape с параметром подфункции NEXTBAND и устанавливать флаг bError, если это возвращаемое значение отрицательно. Если ни один вызов функции ExtEscape не возвратит ошибки, то задание на печать должно быть закончено либо с помощью вызова функции EndDoc, либо прервано с помощью вызова функции AbortDoc. Этот код представлен ниже:
if(!bError)
{
if(bUserAbort)
AbortDoc(hdcPrn);
else
if(EndPage(hdcPrn))
EndDoc(hdcPrn);
}
Принтер и шрифты
В главе 4 имеется программа JUSTIFY, в которой для вывода на экран отформатированного текста используются шрифты GDI. Программы, которые работают с форматированным текстом на экране, обычно имеют возможность печати этого текста. Действительно, в программах обработки текстов и настольных издательских системах экран используется главным образом только для предварительного просмотра выводимых на печать данных.
Шрифты типа TrueType предоставляют простейший путь точного представления текста на экране так, как если бы он был напечатан. Этот подход ограничивает возможности программы использованием только шрифтов типа True Type. Если выбор шрифта осуществляется с помощью функции EnumFontFamilies, то вы можете установить бит
93
TRUETYPE_FONTTYPE параметра iFontType функции обратного вызова. В этом случае будет использоваться окно списка только тех шрифтов, у которых установлен бит TRUETYPE_FONTTYPE.
Если в программе предоставить пользователю возможность выбора шрифта в диалоговом окне, которое отображается при вызове функции ChooseFont из библиотеки диалоговых окон общего пользования (как показано в программе JUSTIFY в главе 4), то для ограничения списка шрифтов только шрифтами типа TrueType можно включить в поле Flags структуры CHOOSEFONT флаг CF_TTONLY.
Однако, ограничение возможности выбора шрифта только шрифтами типа TrueType может не удовлетворить тех пользователей, кто вложил деньги в дополнительные принтерные шрифты, загружаемые или на картриджах. Такие шрифты не будут перечислены в предлагаемом пользователю списке. Для того, чтобы такие шрифты оказались в окне диалога, созданном с помощью функции ChooseFont, необходимо включить в поле Flags структуры
CHOOSEFONT константу CF_PRINTERFONTS.
Необходимо также установить поле hDC структуры CHOOSEFONT равным описателю контекста принтера. Тогда список шрифтов, выводимых в окне списка будет ограничен внутренними шрифтами принтера, шрифтами типа TrueType и векторными шрифтами. (Чтобы исключить появление в списке векторных шрифтов, используйте флаг
CF_NOVECTORFONTS.)
Если пользователю дается возможность выбора принтерных шрифтов, то вид шрифтов на экране будет только примерно соответствовать тому, что будет напечатано. Например, если для принтера предлагается 15-точечный шрифт Zapf Chancery, он может быть апроксимирован 15-точечным шрифтом типа TrueType, но при этом ширина символа шрифта типа TrueType будет отличаться от ширины символа шрифта Zapf Chancery. Даже для шрифтов типа TrueType ширина символа на экране и принтере может отличаться на величину ошибки округления, возникающую из-за отличий экрана и принтера.
Короче говоря, при написании программы, в которой на экране должен выводиться отформатированный текст, предназначенный для печати, придется сделать дополнительные усилия. Вот несколько указаний для начала.
При выводе отформатированного текста на экране желательно, чтобы текст выглядел так, как он в конце концов будет напечатан. Для определения размера бумаги и размера области печати можно использовать функции GetDeviceCaps и DeviceCapabilities. Например, если ширина бумаги равна 8,5 дюймов, и пользователь задает размер левого и правого отступов по одному дюйму, то желательно выводить текст в область экрана шириной 6,5 дюймов. Для такого вывода подходит режим отображения "logical twips", о котором говорилось в главе 4. Однако, будьте осторожны. Если пользователь выбирает 15-точечный шрифт, который поддерживает принтер, этот шрифт пришлось бы приспособить к ширине области экрана и подобрать вместо него, скажем, 14-точечный экранный шрифт, но такой 14-точечный шрифт нельзя использовать для определения того, сколько может занять одна напечатанная 15-точечным шрифтом строка. Это надо определять на основе принтерного шрифта. Подобным образом принтерный шрифт необходимо использовать для определения количества строк на странице.
Для форматирования текста на экране понадобится описатель контекста экрана и описатель информационного контекста принтера. До того, как фактически начать печатать, описатель контекста принтера не нужен. Проделайте следующие шаги:
1. В структуру логического шрифта объедините имя шрифта, его размер и выбранные пользователем атрибуты, и этот логический шрифт выберите в информационный контекст принтера.
2.Для определения действительных размера и характеристик выбранного шрифта для принтера используйте вызов функции GetTextMetrics. Для получения имени шрифта используйте вызов функции GetTextFace.
3.Информацию, полученную на втором шаге, используйте для создания другой структуры логического шрифта, основанного на размере и характеристиках принтерного шрифта, выберите этот логический шрифт в контекст экрана. Теперь шрифт, выбранный в контексте экрана, приблизительно соответствует шрифту, выбранному в информационном контексте принтера.
4.При отображении текста на экране следуйте общей схеме, которая использовалась в функции Justify программы JUSTIFY. Однако, при этом выполните функции GetTextExtent и SetTextJustification, используя информационный контекст принтера, но остановитесь перед функцией TextOut. Такой подход позволяет определить количество символов в строке и число строк на странице.
5.Когда для принтера сформирована каждая строка текста, то вызовите функцию GetTextExtent и (возможно) SetTextJustification, используя контекст экрана. Затем, для вывода строки на экран используйте вызов функции TextOut.
Для печати текста вы, вероятно, будете использовать код, похожий на код из файла POPPRINT.C в сочетании с логикой функции Justify файла JUSTIFY.С. Получите контекст принтера и снова выполните функции GetTextExtent и SetTextJustification, на этот раз для печати каждой строки, используя функцию TextOut.
Часть V
Связи и обмен данными