On-Line Библиотека www.XServer.ru - учебники, книги, статьи, документация, нормативная литература.
       Главная         В избранное         Контакты        Карта сайта   
    Навигация XServer.ru








 

4. Справочная система Windows Help

4.1. Элементы справочной системы

4.2. Создание справочной системы

4.3. Графические изображения

4.4. Макрокоманды

4.5. Функция WinHelp

4.6. Встроенное окно

4.7. Другие возможности

Ни одно приложение Windows, созданное на профессиональном уровне, не обходится без справочной системы, предназначенной для пользователя. До сих пор меню "Help" наших приложений в лучшем случае содержало строку "About...", выбрав которую вы могли полюбоваться на номер версии приложения и фамилию разработчиков. Однако пользователь вправе ожидать большего. И вы не должны разочаровать его, обеспечив свое приложение удобной справочной системой, содержащей всю информацию, необходимую как для начинающих, так и для опытных операторов персонального компьютера.

Какими же возможностями должна обладать справочная система?

Как минимум, она должна содержать информацию о том, для чего предназначено приложение, как использовать меню и диалоговые панели. Необходимо описать методику выполнения различных процедур, таких как копирование в Clipboard, редактирование документов или аналогичных. Хорошо спроектированная справочная система должна содержать глоссарий, систему поиска информации по контексту и графические иллюстрации.

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

Впрочем, не будем утомлять вас перечнем всего того, что должно содержаться в справочной системе, ибо вам доступно множество различных готовых справочных систем, встроенных в стандартные приложения Windows, а также в такие приложения, как Microsoft Word for Windows или Borland C++ for Windows. Просто посмотрите на них внимательно - это и есть примеры хорошо спроектированных справочных систем.

Даже не очень пристальный взгляд на то, что появляется на экране при работе с меню "Help" текстового процессора Microsoft Word for Windows наводит на размышления о необычайной сложности справочной системы. Однако не думайте, что создание таких систем доступно только избранным. Очень скоро вы научитесь делать подобные вещи или даже более мощные.

Схожесть внешнего вида справочных систем различных приложений наводит на мысль, что для их создания было использовано одно и то же средство. Это так и есть на самом деле.

Для создания справочных систем используется специальный help-компилятор, входящий в состав SDK и других продуктов Microsoft, предназначенных для разработки приложений, например, Microsoft FoxPro for Windows или Microsoft Visual Basic.

Пользователь работает со справочной системой при помощи приложения winhelp.exe, которое поставляется вместе с Windows. Программист также имеет доступ к средствам отображения справочной информации. В его распоряжении имеется функция WinHelp, которая входит в программный интерфейс Windows.

Можно сказать, что средства создания и просмотра справочных систем встроены в операционную систему Windows. И это очень хорошо, так как пользователю достаточно лишь один раз научиться работать со справочной системой какого-либо одного стандартного приложения, и он без труда сможет работать со справочными системами всех других приложений Windows.

К сожалению, некоторые приложения имеют нестандартные справочные системы, выполненные без помощи специально предназначенных для этого средств. Для примера можно привести картографическую систему MapInfo for Windows. "Самодельные" справочные системы дезориентируют пользователя, лишая его привычного способа "добывания" нужной информации. К тому же, внешний вид таких систем, информационное содержание и удобство использования обычно оставляют желать лучшего. И это не смотря на то, что разработка такой справочной системы может отнять много времени и сил.

Что же предлагает Microsoft для тех, кому нужно снабдить свое приложение справочной системой?

Прежде всего, такое удобное средство, как текстовый процессор Microsoft Word for Windows версий 2.0 и 6.0. Именно с помощью этого текстового процессора выполняется начальная подготовка текстовых и графических данных, которые будут содержаться в справочной системе.

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

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

Строго говоря, для создания заготовки будущей справочной системы в формате RTF вы можете использовать помимо Word for Windows и другие текстовые процессоры. Однако в этом случае Microsoft не гарантирует, что все будет хорошо. Поэтому если вы собираетесь создавать справочные системы для Windows, лучше сразу обзавестись текстовым процессором Microsoft Word for Windows.

На следующем этапе исходный текст справочной системы преобразуется из формата RTF в hlp-файл. Для выполнения этой процедуры вам потребуется компилятор Microsoft Help Compiler. Он есть в составе SDK и поставляется в составе практически всех систем разработки приложений Windows, таких как Borland C++ for Windows и Microsoft Visual C++.

После завершения процесса компиляции справочная система готова к использованию. Вы можете работать с ней при помощи приложения winhelp.exe или при помощи функции WinHelp, вызываемой из вашего приложения.

4.1. Элементы справочной системы

В этом разделе мы опишем элементы справочной системы, доступные пользователю (о том, как работать с приложением winhelp.exe, вы можете также прочитать в руководстве пользователя Windows или в нашей книге "Операционная система Microsoft Windows. Руководство пользователя", которая вышла вторым томом в составе серии "Персональный компьютер - шаг за шагом").

Разделы

Основной "атомарный" элемент справочной системы - раздел (topic). Раздел представляет собой фрагмент справочной системы, отображаемый в окне приложения winhelp.exe. Он может содержать как текст, так и графические изображения (рис. 4.1).

4.1. Раздел справочной системы Microsoft Word for Windows

Если размер окна недостаточен для отображения раздела целиком, у окна появляется горизонтальная или вертикальная полоса просмотра (либо сразу и горизонтальная, и вертикальная полоса просмотра).

Помимо основного окна, приложение winhelp.exe способно создавать вторичные перекрывающиеся окна и временные окна. В этих окнах также отображается содержимое разделов справочной системы.

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

Создавая исходный текст справочной системы в текстовом процессоре Microsoft Word for Windows, вы создаете разделы в виде групп обычных параграфов текста. Каждая группа должна начинаться с новой страницы и содержать в первом параграфе заголовок, идентификатор, ключевые поля и другие атрибуты в виде подстрочных сносок. Как мы уже говорили, вы можете включить в текст графические изображения или таблицы.

Перекрестные ссылки

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

Разработчик справочной системы может создать ссылку на другой раздел, либо на временное (pop-up) окно. Можно также создать ссылку на раздел, отобразив его во вторичном окне.

В первом и третьем случае в окне приложения winhelp.exe ссылка выглядит как фрагмент текста, подчеркнутый сплошной линией, во втором - пунктирной. Например, на рис. 4.1 строка "Control menu commands" подчеркнута сплошной линией и представляет собой ссылку на другой раздел. Если выбрать мышью эту строку, в окне появится содержимое раздела "Control Menus" (рис. 4.2).

4.2. Раздел "Control Menus"

Обратите внимание на то, что в этом разделе есть ссылки на другие разделы, например, "Restore", "Move" и т. д.

Если выбрать мышью ссылку в виде строки, подчеркнутой пунктирной линией, на экране появится временное окно (рис. 4.3).

4.3. Временное окно

Временное окно обычно используется для пояснения термина. В нашем случае во временном окне объясняется понятие "application window".

Оглавление

Каждая книга имеет оглавление, пользуясь которым читатель без труда находит нужный ему раздел. Справочная система также должна иметь оглавление.

Как сделать оглавление?

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

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

В древовидном оглавлении один раздел выполняет роль корневого раздела. Он содержит ссылки на несколько разделов, отвечающих за различные темы (рис. 4.4).

4.4. Корневой раздел справочной системы приложения Microsoft Anti Virus

Если в корневом разделе справочной системы выбрать строку "Commands", на экране появится одноименный раздел, представляющий собой следующий иерархический уровень оглавления (рис. 4.5).

4.5. Раздел "Commands"

Иногда в оглавлении используются пиктограммы (рис. 4.6).

4.6. Пиктограммы в оглавлении

Пользователь может нажать на пиктограмму левой клавишей мыши, при этом на экране появится оглавление следующего уровня или раздел, на который сделана ссылка. Пиктограммы улучшают внешний вид и привлекательность справочной системы.

Органы управления

Приложение winhelp.exe имеет в своем главном окне меню и окно Toolbar, содержащее кнопки с различными надписями и обозначениями (рис. 4.7).

4.7. Органы управления приложения winhelp.exe

С помощью меню "File" пользователь может открыть новый hlp-файл (т. е. приступить к работе с новой справочной системой), выбрать принтер и распечатать содержимое текущего раздела, отображаемого в главном окне приложения winhelp.exe. К сожалению, возможность полной распечатки содержимого всей справочной системы отсутствует, что является серьезным недостатком приложения winhelp.exe.

Меню "Edit" предназначено для копирования всего текущего раздела или любого его фрагмента в Clipboard (рис. 4.8). При этом копируется только неформатированный текст без графических изображений (хотя можно было бы предоставить пользователю возможность скопировать все как есть в формате, например, текстового редактора Write, входящего в поставку Windows).

4.8. Копирование содержимого раздела в Clipboard

Тем не менее, возможность копирования информации из справочной системы в Clipboard даже в неформатированном виде является весьма ценной, так как позволяет, например, вставлять в исходный текст программы готовые фрагменты, взятые из примеров применения функций.

Строка "Annotate..." из меню "Edit" предназначена для добавления комментария к разделу (рис. 4.9).

4.9. Добавление комментария к разделу справочной системы

Меню "Bookmark" позволяет "вставить" в справочную систему закладку, как в обычную книгу (рис. 4.10). Такая закладка иногда называется маркером.

4.10. Создание закладок

По умолчанию для имени закладки выбирается заголовок раздела, однако пользователь может указать любое другое имя.

И, наконец, с помощью меню "Help" пользователь может узнать о том, как работать с приложением winhelp.exe, а также сделать главное окно этого приложения "непотопляемым", т. е. расположенным всегда над другими окнами (выбрав строку "Always on Top").

Окно Toolbar содержит несколько кнопок, предназначенных для выполнения самых нужных функций.

С помощью кнопки "Contents" можно отобразить раздел, содержащий оглавление загруженного hlp-файла.

Нажав на кнопку "Search", пользователь получит возможность выполнить поиск информации по ключевому слову (рис. 4.11).

4.11. Поиск информации по ключевому слову

Напомним, что список ключевых слов определяется для тех разделов, к которым необходимо предоставить доступ по ключевым словам. Например, справочная система приложения Borland C++ for Windows позволяет найти описание функции по ключевому слову - имени функции.

Кнопка "Back" позволяет вернуться к просмотру раздела, который отображался в окне приложения winhelp.exe в прошлый раз.

При помощи кнопки "History" пользователь может получить доступ к списку названий просмотренных ранее разделов (рис. 4.12). Он может выбрать из этого списка любой раздел и вызвать его на экран двойным щелчком левой клавиши мыши.

4.12. Список названий просмотренных ранее разделов

Как правило, окно Toolbar содержит кнопки со значками и , причем одна или обе такие кнопки могут быть заблокированы. Эти кнопки предназначены для последовательного просмотра логически следующих друг за другом разделов, соответственно, в прямом и обратном направлении.

Разработчик справочной системы (то есть исходного файла справочной системы, попадающего на вход компилятора Microsoft Help Compiler) с помощью специальных макрокоманд может изменить состав органов управления приложения winhelp.exe при отображении данного файла. Например, он может добавить меню или новую кнопку.

Однако при выборе состава органов управления для вашей справочной системы следует учитывать, что непривычные названия и органы управления иногда затрудняют работу пользователя и, как следствие, ухудшают общее впечатление от приложения.

4.2. Создание справочной системы

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

Подготовка разделов

Как мы уже говорили, исходный текст справочной системы, поступающий на вход компилятора Help Compiler, должен быть сохранен в формате RTF (Rich Text Format). Этот формат описан в документации, которая поставляется вместе с SDK, но мы не знаем пока еще никого, подготовившего исходный текст справочной системы в этом формате. Приведем здесь небольшой фрагмент текста в формате RTF. Просто взгляните на него, и вам станет понятно, почему этим форматом трудно пользоваться:

{\rtf1\ansi \deff0\deflang1024{\fonttbl{\f0\froman Times New Roman;}{\f1\froman Symbol;}{\f2\fswiss Arial;}{\f3\fswiss Sans Serif PS;}{\f4\fmodern Courier;}{\f5\fmodern Sans Serif 20cpi;}{\f6\fmodern Roman Cyrillic;}
{\f7\fmodern Courier Cyrillic;}{\f8\fswiss Helv Cyrillic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255;

К счастью, текстовый процессор Microsoft Word for Windows позволит вам создать справочную систему в режиме "почти WYSIWYG", когда внешний вид редактируемых разделов почти совпадает с тем, что увидит пользователь, запустивший справочную систему.

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

Атрибуты разделов

Перечислим атрибуты, которые может иметь раздел справочной системы. Только один из них должен быть указан всегда (контекст), остальные являются необязательными.

Атрибут разделаОписание
КонтекстТекстовая строка, однозначно идентифицирующая раздел. Используется для ссылки на раздел. Это обязательный атрибут
ЗаголовокЗаголовок, под которым раздел появляется при поиске с помощью кнопки "Search" приложения winhelp.exe. Этот атрибут необязательный
Список ключевых словПользователь может искать разделы по ключевым словам. Для каждого раздела можно задать несколько ключевых слов (но можно не задавать ни одного, в этом случае раздел не будет иметь доступ по ключевым словам). Справочная система может содержать несколько списков ключевых слов. Необязательный атрибут
Номер в последовательности просмотраНекоторые разделы могут иметь логическую последовательную связь. Данный атрибут позволяет задать положение раздела в последовательности просмотра. О последовательностях просмотра мы расскажем позже. Необязательный атрибут
МакрокомандаДля каждого раздела можно указать одну или несколько макрокоманд, запускаемых при отображении раздела. Макрокоманды мы рассмотрим позже
Тег компиляцииАтрибут, который позволяет включать или не включать раздел в справочную систему в зависимости от параметров компиляции. Необязательный атрибут

В справочной системе не может быть двух разделов с одинаковым контекстом. Если же по ошибке вы сделаете такие разделы, компилятор Help Compiler выведет сообщение об ошибке.

Для строки контекста (context string) вы можете использовать алфавитно-цифровые символы от A до Z, числа от 0 до 9, точку и знак подчеркивания (но не символы пробела). Максимальная длина строки - 255 символов, но не увлекайтесь длинными названиями, так как они создают дополнительные трудности при вводе текста.

Заголовок раздела (title of the topic) появляется в окне поиска и просмотра закладок, поэтому в хорошей справочной системе все разделы имеют заголовок. Максимальная длина текстовой строки заголовка составляет 128 символов.

Что же касается ключевых слов (keyword), то здесь вы можете использовать для каждого ключевого слова максимально 255 символов. Если для раздела используется несколько ключевых слов, их нужно разделить символом точка с запятой ";".

Теперь займемся последовательностями просмотра (browse sequences).

Для того чтобы вам было понятнее, что такое последовательность просмотра, рассмотрим пример справочной системы, описывающей меню приложения. Главное меню приложения состоит из нескольких временных меню, в каждом из которых, в свою очередь, имеется несколько строк. Для главного меню, для каждого временного меню и для каждой строки нужно создать отдельный раздел в справочной системе. Организуем эти разделы следующим образом (рис. 4.13).

4.13. Номера последовательностей просмотра

На рис. 4.13 определены четыре последовательности просмотра. Первая имеет отношение к главному меню. В ней находятся три раздела, которые описывают, соответственно, временные меню "File", "Edit" и "Help". Нажимая кнопки со значками и , пользователь сможет последовательно переходить к просмотру описаний этих меню.

Для каждого временного меню определена своя последовательность просмотра, так как, изучая меню, пользователь, скорее всего, захочет последовательно ознакомится со всеми строками этого меню.

Обозначение номера последовательности меню состоит из имени и числа, разделенного символом двоеточия ":". Каждому имени соответствует отдельная последовательность просмотра. Что же касается чисел, то можно использовать любые целые значения, причем они не обязательно должны идти подряд. Более того, для облегчения вставки в последовательность новых разделов рекомендуется нумеровать их с некоторым интервалом, как когда-то нумеровались строки в программе на языке Бейсик.

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

Тегом компиляции (build tag) отмечаются разделы, которые включаются или не включаются в справочную систему на этапе компиляции в зависимости от содержимого одного из разделов файла проекта справочной системы (файл проекта будет рассмотрен позже). Тег компиляции удобно использовать при отладке.

Назначение атрибутов разделам справочной системы

Для назначения атрибутов разделам справочной системы вам необходимо освоить технику вставки подстрочных сносок в текстовом процессоре Microsoft Word for Windows.

О том, как работать с текстовым процессором Microsoft Word for Windows вы можете прочитать в нашей книге "Введение в MS-DOS, MS Windows, MS Word for Windows", которая вышла первым томом в серии "Персональный компьютер - шаг за шагом". Здесь мы приведем лишь самые минимальные сведения, необходимые для работы со сносками.

Подстрочная сноска - это текст, который располагается в нижней части страницы и обычно отделяется от основного текста горизонтальной чертой. В тексте сноска оформляется в виде специального символа, такого как "*", или числа.

Для вставки сноски вы должны выбрать из меню "Insert" текстового процессора Word for Windows строку "Footnote...". На экране появится диалоговая панель "Footnote" (рис. 4.14).

4.14. Вставка сноски

В появившейся диалоговой панели в поле "Custom Footnote Mark" можно ввести символ, который будет использоваться для сноски, а можно использовать автоматическую нумерацию сносок.

При создании исходного текста справочной системы для назначения атрибутов используются сноски в виде символов, причем для каждого атрибута применяется свой символ:

Атрибут разделаСимвол
Контекст#
Заголовок$
Список ключевых словK
Номер в последовательности просмотра+
Макрокоманда, получающая управление при отображении раздела !
Тег компиляции*

В процессе назначения атрибута вам нужно вставить сноску, указав в поле "Custom Footnote Mark" (рис. 4.14) нужный символ.

Как только вы вставите сноску, экран текстового процессора окажется разделен на две части - в нижней части появится окно редактирования сносок, озаглавленное "Footnotes" (рис. 4.15).

4.15. Окно редактирования сносок

Текст сноски (в нашем случае это атрибут раздела) вводится после соответствующего символа в окне редактирования сносок. Между строкой и символом сноски должен быть только один символ пробела.

При помощи кнопки "Close" вы можете закрыть окно редактирования сносок. Для того чтобы вновь открыть это окно, выберите из меню "View" строку "Footnotes".

Создание перекрестных ссылок

Справочная система, созданная с использованием компилятора Help Compiler, имеет вид гипертекста, состоящего из разделов, связанных между собой ссылками. Ссылки создаются непосредственно в тексте раздела, для чего используется соответствующее шрифтовое оформление - перечеркнутый или двукратно подчеркнутый текст, однократно подчеркнутый текст и скрытый текст.

Любая ссылка состоит из двух частей. Первая часть - это текст, который виден пользователю и отображается, как правило, зеленым цветом с подчеркиванием сплошной или пунктирной линией. Для выполнения перехода пользователь должен сделать щелчок левой клавишей мыши по выделенному таким образом тексту. Вторая часть не видна пользователю. Это строка контекста раздела, на который выполняется переход.

Если выполняется переход на обычный раздел, в исходном тексте справочной системы первая часть ссылки оформляется как перечеркнутая или подчеркнутая двойной чертой строка текста. Если же выполняется переход во временное окно (рис. 4.3), используется однократное подчеркивание.

Строка контекста всегда оформляется скрытым текстом.

На рис. 4.16 показан фрагмент окна текстового процессора Word for Windows, в котором видны две ссылки.

4.16. Ссылки на временное окно и обычный раздел

Строка "графических изображений" содержит ссылку на раздел с контекстом "graphics". Обратите внимание, что первая часть ссылки подчеркнута одной чертой, а вторая оформлена скрытым текстом (показан как подчеркнутый линией, состоящей из точек). Так как строка "графических изображений" подчеркнута один раз, это ссылка на временное окно.

Вторая ссылка состоит из строк "Описание команд" и "cmd". Здесь мы видим ссылку на обычный раздел, имеющий контекст "cmd".

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

Для того чтобы выделить строку текста подчеркиванием или оформить как скрытый текст, используйте строку "Character" меню "Format" текстового процессора Word for Windows.

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

При создании ссылки на раздел можно указать, что его содержимое должно отображаться во вторичном окне. Для этого после строки контекста в тексте ссылки необходимо расположить символ > и имя окна:

SmartPadedit_wnd>edwindow

Ссылка на другой hlp-файл

Можно создать ссылку на раздел, расположенный в другом hlp-файле. Для этого после строки контекста, оформленной скрытым текстом, надо расположить символ @ и сразу вслед за ним путь к файлу:

SmartPadcontents@c:\windows\smartpad.hlp

В этой строке все символы, расположенные после строки "SmartPad" необходимо оформить скрытым текстом.

Раздел, отображаемый при помощи ссылки на другой файл, можно показать во вторичном окне:

SmartPadcontents@c:\windows\smartpad.hlp>contwindow

Создание исходного текста для файла hlpfile.hlp

Закрепим полученные знания на практике. Нашей задачей будет создание разделов простейшей справочной системы.

Запустите текстовый процессор Microsoft Word for Windows. Вы можете использовать версию 2.0 или 6.0, но мы будем рассматривать приемы использования Microsoft Word for Windows версии 2.0.

Если вы приобрели дискету, которая продается вместе с книгой, загрузите из каталога hlpfile файл hlpfile.rtf, содержащий готовый исходный текст справочной системы (рис. 4.17). Если у вас нет дискеты, вам придется набрать исходный текст самостоятельно. Рассмотрим этот процесс.

Вначале создайте новый документ. Сразу после создания документ будет содержать одну строку, имеющую стиль Normal. Наберите в этой строке заголовок первого раздела, а именно, раздела оглавления справочной системы. На рис. 4.17 это строка "Текстовый редактор".

Выберите шрифтовое оформление заголовка. Учтите, что приложение winhelp.exe при отображении текста в системе пользователя подберет наиболее подходящий шрифт из числа установленных шрифтов. Для достижения максимального соответствия старайтесь выбирать только те шрифты, которые входят в стандартную поставку Windows. При этом следует также учесть, что не во всех шрифтах есть символы кириллицы.

После завершения оформления выделите весь первый параграф и в списке стилей выберите стиль "heading 1", изменив его по вашему образцу. Теперь вы сможете использовать этот стиль для оформления всех заголовков справочной системы и тогда все заголовки будут выглядеть одинаково.

Если вам нужно, чтобы в процессе просмотра раздела заголовок всегда оставался на видном месте, задайте для стиля "heading 1" атрибут оформления параграфа "Keep With Next" (располагать строки параграфа на одной странице со следующей строкой). В этом случае в верхней части окна просмотра раздела образуется дополнительное окно, содержащее заголовок.

4.17. Первые два раздела справочной системы

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

Для того чтобы задать контекст, выполните следующие шаги:

расположите текстовый курсор в начале строки заголовка (в нашем случае курсор должен находится в начале первой строки)

вставьте подстрочную сноску (footnote) с идентификатором #

наберите в качестве текста сноски строку контекста

Затем, после определения контекста, укажем заголовок раздела, под которым он будет появляться при поиске (для поиска используется кнопка "Search", расположенная в окне Toolbar приложения winhelp.exe).

Заголовок раздела задается точно также, как и строка контекста, но в качестве идентификатора сноски следует использовать символ $.

Задайте список ключевых слов, по которым пользователь сможет найти раздел. Список ключевых слов задается как сноска с идентификатором K. Вы можете задать несколько ключевых слов, разделив их символом точка с запятой.

В заключение задайте номер последовательности просмотра как сноску с идентификатором +, указав строку "cont:010".

Окно сносок для первого и второго разделов должно выглядеть следующим образом:

$ Редактор текста Small Edit
# cont
+ cont:010
K оглавление
$ Описание команд
# cmd
+ cont:020
K команды

Аналогичным образом подготовьте остальные разделы справочной системы (рис. 4.18 и 4.19).

4.18. Третий, четвертый и пятый разделы справочной системы

4.19. Шестой, седьмой, восьмой и девятый разделы справочной системы

В окне редактирования сносок для разделов с третьего по девятый должны быть определены следующие сноски:

$ Использование клавиатуры
# key
+ cont:030
K клавиатура
$ Работа с мышью
# mouse
+ cont:040
K мышь
$ Графические изображения
# graphics
K графика;битовые изображения
$ Меню File
# file
+ cmd:010
K File; загрузка документа
$ Меню Edit
# edit
+ cmd:020
K edit; редактирование
$ Меню View
# view
+ cmd:030
K view
$ Отсутствующий раздел
# missing

Подготовив текст, сохраните его в формате RTF. Для этого из меню "File" выберите строку "Save as..." и в появившейся диалоговой панели в списке "Save File as Type" выберите строку "Rich Text Format (*.rtf)".

Затем вы можете сохранить файл и в естественном формате Word for Windows, хотя это и не обязательно.

Создание файла проекта справочной системы

Итак, на данный момент вы создали (или, что лучше и быстрее, переписали с дискеты) файл hlpfile.rtf, содержащий исходный текст разделов справочной системы. Следующим шагом будет подготовка файла проекта hlpfile.hpj, необходимого для работы компилятора Help Compiler.

Готовый файл hlpfile.hpj вы можете найти на дискете, которая продается вместе с книгой. Если дискеты нет, наберите файл самостоятельно, пользуясь листингом 4.1.

Для набора файла проекта вы можете выбрать любой текстовый редактор, сохраняющий файл без шрифтового оформления. Подойдет редактор Notepad или редактор, входящий в систему разработки Borland C++ for Windows. Можно использовать даже встроенный в Norton Commander текстовый редактор или аналогичное средство MS-DOS. И пусть вас не смущает, что вы не сможете использовать символы кириллицы из-за различий в кодировке для MS-DOS и Windows, так как... вы не сможете их использовать в любом случае. В файле проекта символы кириллицы недопустимы.


Листинг 4.1. Файл hlpfile/hlpfile.hpj


[OPTIONS]
errorlog = hlpfile.err
title = Text Editor Help
contents = cont
compress = 1
warning = 3
report = 1

[FILES]
hlpfile.rtf

[WINDOWS]
main = "Text Editor Help",,,, (255,255,192 )

[CONFIG]
BrowseButtons()

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

Рассмотрим назначение секций файла проекта нашей справочной системы.

OPTIONS

Параметры, определенные в этой секции, управляют процессом создания справочной системы на этапе компиляции. Секция OPTIONS должна быть определена в файле проекта первой.

Перечислим некоторые параметры, значения которых задаются в секции OPTIONS:

ПараметрОписание
CONTENTSСтрока контекста, соответствующая разделу справочной системы, выполняющей функции оглавления
TITLEТекст заголовка окна приложения winhelp.exe при работе с данной справочной системой. Можно использовать только латинские буквы
COPYRIGHTСтрока, содержащая сведения о разработчиках данной справочной системы. Будет добавлена в диалоговую панель приложения winhelp.exe, которая выводится на экран при выборе строки "About..." меню "Help"
BMROOTПуть к каталогу, содержащему графические bmp-файлы, включаемые в проект справочной системы
BUILDПараметр позволяет исключать из справочной системы разделы, имеющие заданные атрибуты тега компиляции (build tag)
COMPRESSОпределяет степень компрессии данных при создании hlp-файла. Возможны следующие значения:NO, FALSE или 0 - компрессия не используется;MEDIUM - средняя степень компрессии;YES, TRUE, HIGH или 1 - максимальная компрессия
ERRORLOGПуть к файлу, в который будут записаны сообщения о найденных в исходном тексте ошибках
FORCEFONTПри использовании этого параметра для отображения hlp-файла будет использован только один шрифт, имя которого указано в параметре FORCEFONT
ICONЭтот параметр позволяет указать пиктограмму, которая будет отображаться при сворачивании главного окна приложения winhelp.exe, если отображается данный hlp-файл
OPTCDROMОптимизация hlp-файла, предназначенного для записи на компакт-диск, заключается в выравнивании границ разделов на границу блока данных.Указывается следующим образом:OPTCDROM=YESВместо "YES" можно указать также TRUE, ON и 1
REPORTВключение режима отображения сообщений во время компиляции. Указывается следующим образом:REPORT=ON
ROOTПуть к каталогу, содержащему файлы, входящие в проект. Эта секция может отсутствовать
WARNINGУровень сообщений об ошибках:1 - выводятся сообщения только о самых серьезных ошибках;2 - выводится среднее количество сообщений об ошибках;3 - выводятся все сообщения и предупреждения

FILES

В этой секции перечисляются файлы разделов *.rtf, из которых создается справочная система. В простейшем случае все разделы могут находиться в одном rtf-файле, однако для сложных и разветвленных справочных систем такой подход затрудняет процесс отладки.

WINDOWS

Параметры секции определяют внешний вид окон приложения winhelp.exe.

Характеристики окна определяются следующим образом:

wndname="caption",(horizposition,vertposition,width,height),
  sizing,(clientRGB),(nonscrollingRGB),topmost

Для определения характеристик главного окна приложения winhelp.exe в качестве wndname следует указать строку "main":

main = "Text Editor Help",,,, (255,255,192 )

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

Параметр caption задает заголовок окна.

Параметры horizposition, vertposition, width и height предназначены, соответственно, для определения горизонтального положения, вертикального положения, ширины и высоты окна. При этом следует использовать значения в диапазоне от 0 до 1024. Действительные размеры окна будут пересчитаны в соответствии с текущим разрешением экрана.

С помощью параметра sizing можно указать начальные размеры вторичного окна при его появлении на экране. Если этот параметр указан как 1, устанавливаются максимальные размеры окна. Если же значение параметра равно 0, размеры окна определяются параметрами horizposition, vertposition, width и height.

Параметры (clientRGB) и (nonscrollingRGB) задаются как тройки чисел, разделенных запятыми. Эти числа определяют, соответственно, красную, зеленую и голубую компоненту цвета для внутренней области главного окна приложения winhelp.exe и для несворачиваемого окна заголовка раздела, располагающегося в верхней части главного окна.

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

Неиспользуемые параметры можно не указывать, однако в строке параметров должны присутствовать все запятые до последнего указанного параметра.

CONFIG

Эта секция нужна в том случае, если разработчик справочной системы использовал дополнительные возможности приложения winhelp.exe, такие как дополнительные кнопки, макрокоманды, вызовы функций из внешних DLL-библиотек и т. п.

В частности, для того чтобы в окне Toolbar появились кнопки просмотра последовательностей разделов со значками и , необходимо добавить в строку CONFIG имя макрокоманды BrowseButtons, создающей указанные кнопки:

BrowseButtons()

Компиляция исходных файлов проекта

Последний шаг на пути к созданию hlp-файла - компиляция исходных файлов, описанных в файле проекта *.hpj. Это самый простой шаг, который сводится к вызову компилятора Help Compiler:

hc31 helpprj

где helpprj - имя файла проекта справочной системы (расширение имени .hpj можно не указывать).

Для того чтобы у вас не было проблем с нехваткой оперативной памяти и совместимостью с Windows версии 3.1, используйте компилятор Windows Help Compiler версии 3.10.504 или более свежей версии. Лучше всего запускать компилятор из DOS-окна в среде Windows, так как в этом случае ему будет доступна расширенная память.

Сделайте текущим каталог hlpfile и запустите компилятор hc31.exe, передав ему в качестве параметра имя файла hlpfile.hpj. В результате работы компилятора при условии отсутствия грубых ошибок в исходных файлах будет создан файл справочной системы hlpfile.hlp.

Запустите приложение winhelp.exe и выберите при помощи меню "File" только что созданный файл hlpfile.hlp. Вы увидите раздел оглавления справочной системы (рис. 4.20).

4.20. Раздел оглавления файла hlpfile.hlp

Проверьте работу кнопок просмотра последовательностей разделов и ссылки, убедившись в том, что все работает правильно. Если что-то не так, скорее всего, вы допустили ошибку при подготовке исходных файлов.

4.3. Графические изображения

Встроенная в Windows справочная система позволяет использовать 16-цветные графические изображения (битовые и метафайлы) как для иллюстрации, так и в качестве средства организации ссылок на разделы.

Непосредственная вставка изображения

Самый простой способ включения графического изображения был использован в примере файла hlpfile.rtf. Мы подготовили изображение в графическом редакторе Paintbrush и вставили его через Clipboard непосредственно в текст, пользуясь текстовым процессором Microsoft Word for Windows.

Этот способ хорош в тех случаях, когда одно и то же изображение вставляется в текст справочной системы один-два раза. Дело в том, что сколько раз вы вставите в текст одну и ту же картинку, столько раз соответствующей ей массив данных будет записан в hlp-файл. Еще одно ограничение заключается в том, что вы можете вставить изображение только как символ в текстовую строку. При этом невозможно добиться эффекта "обтекания" изображения текстом.

Однако несомненное преимущество непосредственной вставки графики в исходный текст справочной системы заключается в том, что внешний вид исходного текста будет больше соответствовать результату компиляции.

Вставка с помощью ссылки

Чаще для вставки графических файлов в исходный текст раздела справочной системы используется косвенная ссылка следующего вида:

{bmc check1.bmp}
{bml check2.bmp}
{bmr check3.bmp}

Здесь приведены три ссылки на файлы check1.bmp, check2.bmp и check3.bmp, содержащие графические изображения. Перед именем файла необходимо указать одну из трех команд вставки (есть две разновидности каждой команды, см. ниже). В зависимости от выбранной команды будет использован один из трех способов взаимного расположения текста и графического изображения в окне раздела:

КомандаСпособ расположения
bmc,bmcwdГрафическое изображение будет вставлено в строку как символ. При этом оформление параграфа (например, высота строки) будет применяться и к изображению
bml,bmlwdГрафическое изображение выравнивается по левой границе, текст располагается справа от графического изображения
bmr,bmrwdГрафическое изображение выравнивается по правой границе, текст располагается слева от графического изображения

Если вы создаете справочную систему, предназначенную для записи на компакт-диск, в некоторых случаях удобнее использовать команды bmcwd, bmlwd, bmrwd. При использовании этих команд графические данные располагаются на диске рядом с окружающим их текстом, что значительно ускоряет процесс отображения.

Если на один и тот же графический файл будет сделано несколько ссылок, при использовании команд bmc, bml и bmr в hlp-файле будет храниться только один экземпляр графических данных. Если же изображения вставлены командами bmcwd, bmlwd и bmrwd, для одного и того же изображения графические данные будут вставлены в hlp-файл столько раз, сколько имеется ссылок.

Использование изображений для ссылок на раздел

Ранее мы рассмотрели способ организации гипертекстовых ссылок между разделами с использованием специальным образом выделенных текстовых строк. Однократно или двукратно подчеркнутая строка в сочетании со строкой контекста, оформленной скрытым текстом, служит в качестве чувствительной точки (hot spot). При выборе такого изображения мышью произойдет переход к другому разделу (или временному окну).

В качестве такой чувствительной точки можно использовать графическое изображение, вставленное при помощи ссылки на имя bmp-файла:


В данном примере битовое изображение logo.bmp используется для организации гипертекстового перехода к разделу с контекстом "missing".

Гиперграфика

Нельзя не упомянуть о возможности создания нескольких чувствительных точек в одном графическом изображении. Такое изображение называется гиперграфическим.

Для создания гиперграфического изображения используется специальный редактор Microsoft Hotspot Editor (приложение shed.exe, поставляется в составе практически всех средств разработки приложений Windows). Получая на входе файл с битовым изображением или метафайлом, этот редактор создает файл с расширением имени shg, содержащий кроме изображения описание размеров и расположения чувствительных зон и соответствующих им строк контекста.

Так как практически гиперграфика используется достаточно редко, ради экономии места в книге мы оставим этот материал на самостоятельное изучение. Всю необходимую информацию вы сможете получить в руководстве Help Compiler Guide, которое поставляется в составе SDK (а также из справочной системы редактора Microsoft Hotspot Editor).

Как учесть разрешение монитора

Разработчики приложений Windows работают на мощных компьютерах, оснащенных современными 17-дюймовыми мониторами и видеоконтроллерами, способными работать при разрешении, скажем, 1280х1024 пикселов (ну хорошо, не все разработчики так хорошо живут, но многие). И вот, подготовив в одном из режимов работы монитора с высоким разрешением прекрасное битовое изображение, они вставляют его в справочную систему и поставляют пользователям. А у тех обычно техника выглядит поскромнее.

Запустив такую справочную систему на компьютере с монитором EGA (что еще не самый плохой вариант!), пользователи сталкиваются с искажениями графических изображений. Рисунки, подготовленные в режиме с высоким разрешением, не помещаются на экране компьютера!

Для выхода из подобной ситуации Microsoft разработал специальный формат файла, в котором предусмотрено хранение нескольких битовых изображений с разным разрешением в одном файле.

Компилятор Microsoft Windows Multiple Resolution Bitmap Compiler (файл mrbc.exe) может объединить несколько bmp-файлов, подготовленных в режимах с разным разрешением, в один файл с расширением имени mrb.

Если такой файл вставить в исходный текст справочной системы при помощи ссылки (команды bmc, bml, bmr и т. п.), при отображении будет использоваться то изображение, разрешение которого соответствует текущему разрешению монитора.

Мы рассмотрим самый простой способ использования компилятора mrbc.exe - пакетный (есть и другой, интерактивный).

Подготовьте 4 варианта одного и того же графического изображения (в формате DIB) в режимах CGA, EGA, VGA и 8514. Вы должны создать 4 bmp-файла.

Затем измените расширение имени файла так, чтобы первая буква расширения указывала на использованное при подготовке файла разрешение:

Первая буква расширения имениРазрешение Пример имени файла
cCGAnicebmp.cga
eEGAnicebmp.ega
vVGAnicebmp.vga
88514nicebmp.854

Затем запустите компилятор в пакетном режиме:

mrbc /s nicebmp.cga nicebmp.ega nicebmp.vga nicebmp.854

Получившийся в результате файл nicebmp.mrb можно использовать для ссылки в исходном тексте справочной системы.

4.4. Макрокоманды

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

Компилятор Help Compiler распознает значительное количество встроенных в справочную систему макрокоманд, с помощью которых можно модифицировать меню и Toolbar, добавляя или удаляя строки меню и кнопки, выполнять переходы между разделами и поиск разделов, запускать произвольные приложения Windows и вызывать функции из внешних DLL-библиотек.

Макрокоманда имеет имя и параметры, указанные в скобках. Параметр может быть текстовой строкой или числом (десятичным или шестнадцатиричным, в последнем случае перед числом должны находится символы 0x). Каждый параметр, заданный в виде текстовой строки, должен быть взят в кавычки:

ExecProgram("testapp.exe",0)

Допустимы вложенные вызовы макрокоманд, однако в этом случае для внутренних макрокоманд вместо обычных кавычек следует использовать символы (`) и ('):

CreateButton("start","&Start App","ExecProgram(`app.exe',0)")

Символ (`) находится на той же клавише, где и символ (~) ("тильда"). Эта клавиша находится возле клавиши <Tab>. Символ (') вы сможете найти на той клавише, где расположен символ двойной кавычки (").

Если вам нужно вставить в текстовую строку параметра макрокоманды символы ("), (`), ('), (\), то перед ними необходимо расположить символ (\).

Вызов макрокоманды

Как вызвать макрокоманду?

Для этого существует несколько способов.

Во-первых, можно вызвать одну или несколько макрокоманд при загрузке hlp-файла. Такие макрокоманды могут выполнять инициализирующие функции, нужные для работы со всеми разделами справочной системы. Примером может послужить вызов макрокоманды BrowseButtons в разделе CONFIG файла проекта справочной системы hlpfile.hpj:

[CONFIG]
BrowseButtons()

В разделе CONFIG можно указывать сразу несколько макрокоманд.

Во-вторых, можно запускать одну или несколько макрокоманд при отображении раздела справочной системы. Для этого имя макрокоманды необходимо оформить как подстрочную ссылку с идентификатором "!":

! BrowseButtons()

Для запуска нескольких макрокоманд их надо разделить символом ";":

! BrowseButtons();SaveMark("Key Assignment")

В-третьих, можно сделать так, чтобы макрокоманда запускалась при выборе чувствительной точки, созданной при помощи подчеркнутого текста или ссылки на битовое изображение:


Здесь при выборе строки "Запустить часы" будет исполнена макрокоманда ExecProgram, предназначенная для запуска приложений. В данном случае будет запущено приложение clock.exe.

Список встроенных макрокоманд

В этом разделе мы приведем краткий справочник по встроенным макрокомандам справочной системы Windows.

About()

Отображение диалоговой панели "About...".

AddAccelerator(key, shift, "macro")

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

Алиас: AA.

Параметры:

ПараметрОписание
keyВиртуальный код клавиши ускоренного запуска макрокоманды
shiftИспользование дополнительных клавиш сдвига:0 клавиши сдвига не используются;1 <Shift>2 <Ctrl>3 <Shift+Ctrl>4 <Alt>5 <Alt+Shift>6 <Alt+Ctrl>7 <Shift+Alt+Ctrl>
macroИмя макрокоманды, которая будет выполнена после того как пользователь нажмет комбинацию клавиш, заданную первыми двумя параметрами

Annotate()

Вывод на экран диалоговой панели "Annotate".

AppendItem("menuid", "itemid", "itemname", "macro")

Добавление строки к меню, созданному макрокомандой InsertMenu.

Параметры:

ПараметрОписание
menuidИмя меню, использованное в макрокоманде InsertMenu
itemidИмя, идентифицирующее строку меню
itemnameТекстовая строка, отображаемая в добавляемой строке меню
macroИмя макрокоманды, которая будет выполнена после того как пользователь выберет из меню добавленную макрокомандой AppendItem строку

Back()

Отображение предыдущего раздела (в списке просмотренных разделов).

BookmarkDefine()

Отображение диалоговой панели "Bookmark Define".

BookmarkMore()

Отображение диалоговой панели "More", отображаемой при выборе строки "More..." из меню "Bookmark" приложения winhelp.exe.

BrowseButtons()

Добавление в окно Toolbar приложения winhelp.exe кнопок последовательного просмотра разделов с обозначениями и (по умолчанию эти кнопки не создаются).

ChangeButtonBinding("buttonid", "buttonmacro")

С помощью этой макрокоманды можно закрепить за кнопкой "Help" указанную макрокоманду.

Алиас: CBB.

Параметры:

ПараметрОписание
buttonidИдентификатор кнопки, использованный при ее создании макрокомандой CreateButton, или один из встроенных идентификаторов стандартных кнопок: btn_contents, btn_search, btn_back, btn_history, btn_previous, btn_next
buttonmacroИмя макрокоманды, которая будет выполнена, когда пользователь нажмет на кнопку

ChangeItemBinding("itemid", "itemmacro")

Эта команда предназначена для закрепления макрокоманды за заданной строкой меню.

Алиас: CIB.

Параметры:

ПараметрОписание
itemidИдентификатор строки меню, присвоенный макрокомандой AppendItem
itemmacroИмя макрокоманды, которая будет выполнена, когда пользователь выберет указанную строку

CloseWindow("windowname")

Макрокоманда закрывает окно с именем windowname, которое может быть как основным окном приложения winhelp.exe, так и вторичным.

Contents()

Переход к разделу, выполняющему функции оглавления справочной системы.

CopyDialog()

Отображение на экране диалоговой панели "Copy", предназначенной для копирования всего раздела или его фрагмента в Clipboard.

CopyTopic()

Копирование текущего (отображаемого в главном окне) раздела в Clipboard.

CreateButton("buttonid", "name", "macro")

Создание новой кнопки в окне Toolbar приложения winhelp.exe.

Алиас: CB.

Параметры:

ПараметрОписание
buttonidИдентификатор создаваемой кнопки
nameТекстовая строка, которая появится на кнопке
macroИмя макрокоманды, которая будет выполнена, когда пользователь выберет созданную кнопку

DeleteItem("itemid")

Удаление строки меню с идентификатором itemid.

DeleteMark("marktext")

Удаление отметки в тексте, созданной макрокомандой SaveMark.

DestroyButton("buttonid")

Удаление кнопки с идентификатором buttonid.

DisableButton("buttonid")

Блокирование кнопки с идентификатором buttonid.

Алиас: DB.

DisableItem("itemid")

Блокирование строки меню с идентификатором itemid.

Алиас: DI.

EnableButton("buttonid")

Разблокирование кнопки с идентификатором buttonid.

Алиас: EB.

EnableItem("itemid")

Разблокирование строки меню с идентификатором itemid.

Алиас: EI.

ExecProgram("cmd", "show")

Запуск приложения Windows.

Алиас: EP.

Параметры:

ПараметрОписание
cmdКомандная строка для запуска (с параметрами запуска)
showСпособ отображения окна запускаемого приложения:0 нормальное;1 минимизированное;2 максимизированное

Exit()

Завершение работы приложения winhelp.exe.

FileOpen()

Отображение диалоговой панели "Open", которая обычно появляется при выборе из меню "File" приложения winhelp.exe строки "Open...".

FocusWindow("windowname")

Назначение фокуса ввода окну, указанному параметром windowname.

GoToMark("marktext")

Переход на отметку в тексте (закладку) с именем marktext, установленную макрокомандой SaveMark.

HelpOn()

Отображение содержимого справочной системы, содержащей информацию об использовании приложения winhelp.exe.

History()

Отображение диалоговой панели "History", позволяющей выбрать один из нескольких только что просмотренных разделов справочной системы.

IfThen(...)

Условный запуск макрокоманды. Обычно используется вместе с макрокомандой IsMark:

IfThen(IsMark("markertext", "macro")

Параметры:

ПараметрОписание
markertextМаркер, который проверяется макрокомандой IsMark
macroИмя макрокоманды, которая будет выполнена, если указанный маркер существует

IfThenElse(...)

Запуск одной из двух макрокоманд в зависимости от существования маркера. Обычно используется вместе с макрокомандой IsMark:

IfThenElse(IsMark("markertext", "macro1", "macro2")

Параметры:

ПараметрОписание
markertextМаркер, который проверяется макрокомандой IsMark
macro1Имя макрокоманды, которая будет выполнена, если указанный маркер существует
macro2Имя макрокоманды, которая будет выполнена, если указанный маркер не существует

InsertItem("menuid", "itemid", "itemname", "macro", "pos")

Вставка новой строки в существующее меню в заданной позиции.

Параметры:

ПараметрОписание
menuidИмя меню, использованное в макрокоманде InsertMenu, или одно из имен стандартных меню: mnu_file, mnu_edit, mnu_bookmark, mnu_helpon.
itemidИмя, идентифицирующее строку меню
itemnameТекстовая строка, отображаемая в новой строке меню
macroИмя макрокоманды, которая будет выполнена после того как пользователь выберет из меню вставленную строку
posПозиция, где будет вставлена строка. Значение 0 соответствует самой верхней позиции в меню

InsertMenu("menuid", "menuname", pos)

Добавление нового временного меню к главному меню приложения winhelp.exe.

Параметры:

ПараметрОписание
menuidИдентификатор добавляемого меню
menunameТекстовая строка названия меню
posПозиция, где будет вставлено меню. Значение 0 соответствует самой левой позиции в главном меню приложения winhelp.exe

IsMark("marktext")

Эта макрокоманда проверяет, существует ли маркер (закладка), указанная в параметре marktext и определенная макрокомандой SaveMark. Используется совместно с макрокомандами IfThen и IfThenElse.

JumpContents("hlp_filename")

Отображение раздела, выполняющего роль оглавления справочной системы, расположенной в hlp-файле с именем hlp_filename.

JumpContext("filename", contextnumber)

Переход к разделу, номер контекста которого равен contextnumber. Расположение раздела (имя hlp-файла) определяется параметром filename.

Алиас: JC.

Параметры:

ПараметрОписание
filenameИмя hlp-файла
contextnumberНомер контекста раздела в указанном hlp-файле. Этот номер должен быть определен в разделе MAP файла проекта *.hpj справочной системы

Немного о секции MAP и о номере контекста раздела.

Секция файла проекта справочной системы MAP предназначена для установки соответствия между строками контекста и номерами контекста. Номер контекста - это численное значение, которое используется приложением для ссылки на раздел справочной системы.

Приведем пример оформления секции MAP:

[MAP]
file_wnd      0x01
edit_wnd      0x02
view_wnd      0x03
content_topic 100

Для номеров контекста можно использовать шестнадцатиричные или десятичные числа.

Допускается также включать в секцию MAP incude-файлы в стандарте Си, содержащие определения констант. Для этого необходимо использовать обычный оператор #include:

#include <menuid.h>

JumpHelpOn()

Переход к разделу, выполняющему роль оглавления справочной системы, содержащей информацию об использовании приложения winhelp.exe.

JumpId("filename", "contextstring")

Переход к разделу с контекстом contextstring. Расположение раздела (имя hlp-файла) определяется параметром filename.

Алиас: JI.

Параметры:

ПараметрОписание
filenameИмя hlp-файла
contextstringСтрока контекста раздела, на который выполняется переход

JumpKeyword("filename", "keyword")

Поиск раздела по ключевому слову keyword. Расположение раздела (имя hlp-файла) определяется параметром filename.

Алиас: JK.

Параметры:

ПараметрОписание
filenameИмя hlp-файла
keywordКлючевое слово, по которому выполняется поиск раздела справочной системы

Next()

Переход к следующему разделу в разделах, расположенных последовательно.

Not(...)

Эта макрокоманда инвертирует результат проверки, выполняемой макрокомандой IsMark:

Not(IsMark("markertext"))

PopupContext("filename", contextnumber)

Отображение раздела, номер контекста которого равен contextnumber. Расположение раздела (имя hlp-файла) определяется параметром filename.

Алиас: PC.

Параметры:

ПараметрОписание
filenameИмя hlp-файла
contextnumberНомер раздела в указанном hlp-файле. Этот номер должен быть определен в разделе MAP файла проекта *.hpj справочной системы

PopupId("filename", "contextstring")

Отображение раздела с контекстом contextstring. Расположение раздела (имя hlp-файла) определяется параметром filename.

Алиас: PI.

Параметры:

ПараметрОписание
filenameИмя hlp-файла
contextstringСтрока контекста отображаемого раздела

PositionWindow(x, y, w, h, wndstate, "windowname")

Изменение размеров и расположения главного или вторичного окон приложения winhelp.exe.

Алиас: PW.

Параметры:

ПараметрОписание
xX-координата верхнего левого угла окна (значение параметров x, y, w, h может находиться в диапазоне от 0 до 1024)
yY-координата верхнего левого угла окна
wВысота окна
hШирина окна
wndstateСостояние окна:0 нормальное;1 максимизированное
windownameИмя окна (главному окну приложения winhelp.exe соответствует имя "main")

Prev()

Переход к предыдущему разделу в разделах, расположенных последовательно.

Print()

Печать содержимого текущего (отображаемого в главном окне) раздела на принтере.

PrinterSetup()

Установка параметров принтера с помощью диалоговой панели "Print Setup".

RegisterRoutine("DLLname", "functionname", "format")

Макрокоманда RegisterRoutine позволяет вам расширить набор макрокоманд, определив собственные макрокоманды. Вы можете создать макрокоманду в виде функции, находящейся в разработанной вами DLL-библиотеке. Перед использованием такую функцию необходимо зарегистрировать, вызвав макрокоманду RegisterRoutine. Лучшее место для вызова макрокоманды регистрации - раздел CONFIG файла проекта справочной системы, хотя вы можете зарегистрировать свою функцию в любое время до ее вызова.

Алиас: RR.

Параметры:

ПараметрОписание
DLLnameИмя DLL-библиотеки, из которой выполняется вызов функции
functionnameИмя функции
formatОписание формата параметров.

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

Буква в строке форматаТип параметра
uunsigned short
Uunsigned long
ishort int
Ilong int
snear char *
Sfar char *
vvoid

SaveMark("marktext")

Эта макрокоманда сохраняет расположение текущего отображаемого раздела и файла в виде закладки или маркера, имеющего имя marktext.

Search()

Отображает диалоговую панель "Search", которая обычно появляется на экране, если нажать кнопку "Search" в окне Toolbar приложения winhelp.exe.

SetContents("filename", "contextnumber")

С помощью этой макрокоманды вы можете указать, что раздел, имеющий номер контекста contextnumber, должен использоваться в качестве оглавления справочной системы, расположенной в hlp-файле с именем filename.

Параметры:

ПараметрОписание
filenameИмя hlp-файла
contextnumberНомер раздела в указанном hlp-файле. Этот номер должен быть определен в разделе MAP файла проекта *.hpj справочной системы

SetHelpOnFile("filename")

Вы можете заместить справочную систему, содержащую сведения об использовании приложения winhelp.exe (расположенную в файле winhelp.hlp) на свою собственную. Для этого в качестве параметра макрокоманде SetHelpOnFile следует указать имя hlp-файла, замещающего файл winhelp.hlp.

4.5. Функция WinHelp

Приложения Windows обращаются к справочной системе с помощью специально предназначенной для этого функции WinHelp. Когда приложение вызывает эту функцию, происходит запуск приложения winhelp.exe. Вызывая функцию WinHelp, приложение может отобразить на экране любую информацию, обычно доступную пользователю через меню или кнопки окна Toolbar приложения winhelp.exe.

Хорошо спроектированное приложение имеет меню "Help", с помощью которого пользователь может получить доступ к оглавлению и предметному указателю справочной системы. Кроме этого, обычно имеется возможность получения так называемой контекстно-зависимой справочной информации. Если вы работали со справочной системой, входящей в состав Borland C++ или Microsoft Visual C++, то вы уже знаете, что это такое.

Когда пользователь нажимает клавишу <F1> или <Shift+F1>, приложение выдает справочную информацию, которая зависит от того, в каком состоянии находятся органы управления приложения, какая строка какого меню выделена, около какого слова в редактируемом тексте находится курсор и т. п.

Например, если вы раскрыли меню "File" и выделили строку "Open...", а затем нажали клавишу <F1>, скорее всего, в любом стандартном приложении вы увидите на экране раздел справочной системы, рассказывающей о том, как пользоваться строкой "Open..." из меню "File".

И это именно такое поведение, которое пользователь ожидает от вашего приложения. Для пользователя важно получить подсказку в каждой конкретной ситуации, нажимая при этом на одну и ту же (для всех приложений Windows) функциональную клавишу <F1>. И если вместо этого пользователь каждый раз будет попадать в раздел оглавления и искать нужную информацию в дебрях гипертекстовой системы, он едва ли будет в восторге.

Функция WinHelp позволяет организовать поиск нужного раздела в справочной системе и отображение его на экране, но и только. Задача отслеживания текущего состояния органов управления и организации контекстно-зависимой подсказки целиком ложится на плечи разработчика приложения.

Прототип функции WinHelp

Прототип функции WinHelp определен в файле windows.h:

BOOL WINAPI WinHelp(
  HWND hwndMain,   // идентификатор окна
  LPCSTR lpszHelp, // путь к hlp-файлу
  UINT usCommand,  // код операции
  DWORD ulData);   // дополнительные данные

Параметр hwndMain перед вызовом функции должен содержать идентификатор окна, для которого вызывается справочная система.

Через параметр lpszHelp передается указатель на текстовую строку, закрытую двоичным нулем, в которой должен быть записан путь к hlp-файлу, содержащему нужную справочную систему.

Функция WinHelp может выполнять одну из нескольких операций в зависимости от значения параметра usCommand:

КомандаОписание
HELP_COMMAND0x0102Выполнение макрокоманды, заданной параметром ulData. Этот параметр должен содержать дальний указатель на текстовую строку, содержащую макрокоманду. Перед использованием команды HELP_COMMAND необходимо, чтобы было запущено приложение winhelp.exe и чтобы нужный hlp-файл был открыт
HELP_CONTENTS0x0003Отображение раздела, выполняющего роль оглавления справочной системы. Параметр ulData для этой команды должен быть равен нулю
HELP_CONTEXT0x0001Отображение содержимого раздела, заданного номером контекста, определенным в разделе MAP файла проекта справочной системы. Через параметр ulData передается номер контекста отображаемого раздела
HELP_CONTEXTPOPUP0x0008Отображение содержимого раздела, заданного номером контекста, во временном окне. Номер контекста должен быть определен в секции MAP файла проекта справочной системы и указан в параметре ulData
HELP_FORCEFILE0x0009Если в момент вызова функции WinHelp с этим кодом операции отображается правильный hlp-файл, функция отрабатывает вхолостую. В противном случае отображается раздел оглавления, заданный в секции CONTENTS файла проекта справочной системы. Параметр ulData для этой команды должен быть равен нулю
HELP_HELPONHELP0x0004Отображение раздела оглавления справочной системы, содержащей информацию об использовании приложения winhelp.exe. Параметр ulData должен быть равен нулю
HELP_INDEX0x0003Синоним HELP_CONTEXT, использовался раньше в функции WinHelp для Windows версии 3.0
HELP_KEY0x0101Отображение раздела справочной системы в соответствии с ключевым словом, передаваемым через параметр ulData. Этот параметр должен содержать дальний указатель на текстовую строку, содержащую ключевое слово
HELP_MULTIKEY0x0201Аналогично предыдущему, но с использованием альтернативной таблицы ключей. Параметр ulData должен содержать дальний указатель на структуру MULTIKEYHELP, определяющую символ сноски для альтернативного ключа и ключевое слово
HELP_POPUPID0x0104Отображение содержимого раздела, заданного номером контекста, во временном окне. Через параметр ulData передается номер контекста отображаемого раздела, определенный в разделе MAP файла проекта справочной системы.
HELP_PARTIALKEY0x0105Аналогично HELP_KEY, однако отображаются разделы, для которых имеется неполное соответствие (несколько начальных символов ключевого слова)
HELP_QUIT0x0002Завершение работы с hlp-файлом. Если ни одно другое приложение не выполняет никаких операций со справочной системой, приложение winhelp.exe завершает свою работу. Параметр ulData должен быть равен нулю
HELP_SETCONTENTS0x0005Раздел, номер контекста которого указан в параметре ulData, будет выполнять функции оглавления справочной системы. Номер контекста раздела должен быть определен в секции MAP файла проекта справочной системы
HELP_SETINDEX0x0005Синоним HELP_SETCONTEXT, использовался раньше в функции WinHelp для Windows версии 3.0
HELP_SETWINPOS0x0203Изменение размеров и расположения окна приложения winhelp.exe в соответствии со значениями, определенными в структуре HELPWININFO, указатель на которую передается через параметр ulData

Структура MULTIKEYHELP определена в файле windows.h следующим образом:

typedef struct tagMULTIKEYHELP
{
    UINT    mkSize;         // размер структуры в байтах
    BYTE    mkKeylist;      // символ сноски
    BYTE    szKeyphrase[1]; // текстовая строка, содержащая
                            // ключевое слово
} MULTIKEYHELP;

Текстовая строка szKeyphrase должна быть закрыта двоичным нулем.

Структура HELPWININFO (и указатели на нее) определена также в файле windows.h:

typedef struct
{
    int  wStructSize; // размер структуры в байтах
    int  x;           // X-координата верхнего левого угла окна
    int  y;           // Y-координата верхнего левого угла окна
    int  dx;          // ширина окна
    int  dy;          // высота окна
    int  wMax;        // стиль отображения окна
    char rgchMember[2]; // имя окна
} HELPWININFO;
typedef HELPWININFO NEAR* PHELPWININFO;
typedef HELPWININFO FAR* LPHELPWININFO;

Для стиля отображения окна вы можете использовать константы с префиксом имени SW:

КонстантаОписание
SW_HIDEСкрыть окно
SW_SHOWNORMALАктивизировать окно и отобразить его в нормальном состоянии (не минимизированном или максимизированном)
SW_SHOWMINIMIZEDМинимизировать окно
SW_SHOWMAXIMIZEDМаксимизировать окно
SW_SHOWNOACTIVEИспользовать для окна старые размеры и расположение. Те окна, которые были активными на момент вызова функции, по-прежнему остаются активными
SW_SHOWАктивизировать и отобразить окно, используя текущие размеры и расположение
SW_MINIMIZEМинимизировать окно, активизировав другое, расположенное в самом низу (т. е. окно нижнего уровня вдоль оси Z)
SW_SHOWMINNOACTIVEОтобразить окно как пиктограмму. Те окна, которые были активными на момент вызова функции, по-прежнему остаются активными
SW_SHOWNAОтобразить окно в текущем состоянии. Те окна, которые были активными на момент вызова функции, по-прежнему остаются активными
SW_RESTOREСиноним SW_SHOWNORMAL

Справочная система HELPMORE.HLP

Для иллюстрации применения стандартных и дополнительных макрокоманд, функции WinHelp, а также малоизвестных и редко используемых, но полезных встроенных окон (Embedded Windows), мы создали справочную систему helpmore.hlp (рис. 4.21). При этом мы взяли за основу подробно описанную нами ранее справочную систему hlpfile.hlp.

4.21. Справочная система helpmore.hlp

Обратите внимание на окно Toolbar. В нем появилась новая кнопка "Calc". Если нажать на нее, будет запущено приложение calc.exe. Эта возможность реализована с помощью стандартных макрокоманд.

Выберите мышью строку "Вызов функции MsgBox из DLL". На экране появится сообщение (рис. 4.22).

4.22. Сообщение, которое выводится при помощи специально созданной макрокоманды

Для вывода такого сообщения мы расширили стандартный набор макрокоманд приложения winhelp.exe, добавив собственную макрокоманду MsgBox, реализованную как функцию библиотеки helpmore.dll.

Если выбрать строку "Вторичное окно", на экране появится еще одно окно, которое живет самостоятельно, вне зависимости от состояния главного окна приложения winhelp.exe (рис. 4.23).

4.23. Вторичное окно

Однако наибольший интерес представляет собой небольшое прямоугольное окно, внутри которого в цифровом виде отображается текущее время! Это так называемое встроенное окно. Мы использовали его для часов, однако в таком окне можно отображать все что угодно, например, анимацию или даже видеофильмы.

Вы можете сделать щелчок левой клавишей мыши внутри встроенного окна, при этом на экране появится диалоговая панель с предложением запустить "настоящие" часы clock.exe (рис. 4.24).

4.24. Пользователю предлагается запустить приложение clock.exe

В случае утвердительного ответа приложение clock.exe будет запущено, вслед за чем на экране появится раздел справочной системы с информацией о часах. Этот раздел будет показан во временном окне, и в нем также отображается текущее время (рис. 4.25). Таким образом, мы использовали временное окно еще и как нестандартное средство для организации гипертекстовой ссылки.

4.25. Гипертекстовая ссылка из встроенного окна

Для экспериментов со справочной системой hlpmore.hlp лучше всего использовать ее исходные тексты и другие файлы, расположенные на дискете, продаваемой вместе с книгой в каталоге hlpmore. Для тех, кто не смог приобрести дискету, мы приведем содержимое первого раздела справочной системы (раздела оглавления) и еще одного дополнительного раздела, которого нет в предыдущей описанной нами справочной системе helpfile.hlp.

На рис. 4.26 изображено оформление раздела оглавления.

4.26. Раздел содержания справочной системы hlpmore.hlp

Вызов созданной нами макрокоманды MsgBox выполняется следующим образом (в исходном *.rtf файле правая часть строки оформлена скрытым текстом):

Вызов функции MsgBox из DLL!MsgBox(hwndApp,"Сообщение из DLL")

Макрокоманда получает два параметра, первый из которых является внутренней глобальной переменной hwndApp (идентификатор главного окна приложения winhelp.exe), а второй представляет собой произвольную текстовую строку.

Для отображения содержимого во вторичном окне использована следующая строка:

Вторичное окноgraphics>grwnd

Здесь graphics - контекст раздела, а grwnd - название вторичного окна, определенного в файле проекта справочной системы hlpmore.hpj (будет описан позже).

Для создания встроенного окна использована следующая строка:

{ewl HLPMORE, EWHlpMoreClass, TestString}

В этой строке оператор ewl указывает, что необходимо встроить окно и расположить его в левой части основного окна (аналогично bml). Существуют также операторы ewc и ewr, с помощью которых можно задать центрирование встроенного окна и выравнивание вправо, соответственно.

Параметр HLPMORE - имя DLL-библиотеки, содержащей функцию окна для обработки сообщений встроенного окна. В данном случае используется библиотека hlpmore.dll, исходным текстом которой мы займемся чуть позже.

Параметр EWHlpMoreClass - это имя класса окна, зарегистрированное DLL-библиотекой для обработки сообщений от встроенного окна.

Строка TestString - произвольная строка, которая передается в функцию встроенного окна на этапе его создания.

Встроенными окнами мы займемся ниже в отдельном разделе.

Если вы создаете исходный текст справочной системы hlpmore.hlp на базе файла hlpfile.rtf, описанного нами ранее, добавьте в него раздел с контекстом clock (рис. 4.27). Этот раздел будет появляться во временном окне в том случае, если вы щелкните левой клавишей мыши внутри встроенного окна.

4.27. Раздел с контекстом clock

Приведем полный список подстрочных ссылок, определенных в файле hlpmore.rtf:

$ Пример справочной системы
# cont
+ cont:010
K оглавление
$ Описание команд
# cmd
+ cont:020
K команды
$ Использование клавиатуры
# key
+ cont:030
K клавиатура
$ Графические изображения
# graphics
K графика;битовые изображения
$ Меню File
# file
+ cmd:010
K File; загрузка документа
$ Меню Edit
# edit
+ cmd:020
K edit; редактирование
$ Меню View
# view
+ cmd:030
K view
$ часы
# clock
$ Отсутствующий раздел
# missing

В файле hlpmore.hpj находится файл проекта справочной системы (листинг 4.2).


Листинг 4.2. Файл hlpmore/hlpmore.hpj


[OPTIONS]
errorlog = hlpmore.err
title = Help Sample
contents = cont
compress = 1
warning = 3
report = 1
copyright = (C) Frolov A.V., 1995
icon=hlpmore.ico

[FILES]
hlpmore.rtf

[WINDOWS]
main = "Help Sample",,,, (255,255,192 )
grwnd = "Graphics",(220,200,700,300),,,(255,255,192)

[MAP]
#define clock 200
#define cmd   201
#define key   202
#define file  203
#define edit  204
#define view  205

[CONFIG]
BrowseButtons()
CB("calc_btn","Calc","EP(`calc.exe', 0)")
RR("hlpmore.dll", "MsgBox", "US")

В секции [OPTION] добавились строки copyright и icon. Первая из них предназначена для добавления сведений о разработчиках справочной системы в диалоговую панель, отображаемую при выборе строки "About Help..." из меню "Help" приложения winhelp.exe. Вторая указывает пиктограмму, в которую превращается главное окно winhelp.exe при его минимизации. С остальными строками этой секции вы уже знакомы.

В секции [WINDOWS] помимо основного окна main описано вторичное окно grwnd, на которое есть ссылка из раздела оглавления. Помимо цвета не сворачиваемой области для вторичного окна следует указать координаты верхнего левого угла, ширину и высоту.

Секция MAP определяет номера контекста, которые будут использованы для ссылки при вызове функции WinHelp.

В секции CONFIG вызываются три макрокоманды: BrowseButtons, CB и RR.

Макрокоманда BrowseButtons добавляет кнопки просмотра последовательностей логически связанных разделов.

Макрокоманда CB (полное имя CreateButton) добавляет в окно Toolbar новую кнопку с надписью "Calc", предназначенную для запуска калькулятора calc.exe.

Макрокоманда RR (полное имя RegisterRoutine) предназначена для регистрации макрокоманды MsgBox, определенной в DLL-библиотеке hlpmore.dll.

Приложение HELPMWH

Приложение HELPMWH демонстрирует приемы работы с функцией WinHelp и один из возможных способов организации получения контекстно-зависимой справки. Меню "Help" этого приложения (рис. 4.28) открывает доступ к содержимому справочной базы данных hlpmore.hlp, описанной в предыдущем разделе.

4.28. Меню 'Help" приложения HELPMWH

Если, запустив приложение HELPMWH, нажать комбинацию клавиш <Shift+F1>, запустится приложение winhelp.exe и в его главном окне отобразится раздел оглавления справочной системы hlpmore.hlp.

До тех пор, пока не выделена какая-нибудь строка меню, клавиша <F1> не действует. Если же выделить любую строку любого меню, кроме "Help", с помощью клавиши <F1> можно будет получить контекстно-зависимую подсказку. Например, при выделении любой строки в меню "File" с последующим нажатием на клавишу <F1> на экране появится справка об использовании меню "File". Аналогичная операция в меню "Edit" или 'View" приведет к отображению справочной информации об использовании этих меню.

Нажав на клавишу <F1> при выделенном меню "Help", вы увидите оглавление справочной системы.

Таким образом, доступ к справочной системе организован таким образом, что в зависимости от того, какое меню выделено, с помощью клавиши <F1> можно вызвать тот или иной раздел справочной системы.

Клавиша <F1> действует и во время отображения диалоговой панели, которая появляется на экране при выборе из меню "Help" нашего приложения строки "About..." (рис. 4.29).

4.29. Диалоговая панель, которая появляется при выборе из меню "Help" строки "About..."

Мы организовали контекстно-чувствительную подсказку таким образом, что нажав клавишу <F1> во время отображения диалоговой панели, мы попадаем в раздел оглавления, однако вы можете выбрать любой другой раздел по вашему усмотрению, немного изменив исходные тексты приложения.

Основной файл исходных текстов приведен в листинге 4.3.


Листинг 4.3. Файл hlpmore/helpmwh.cpp


// ----------------------------------------
// Демонстрация использования функции WinHelp
// ----------------------------------------
#define STRICT
#include <windows.h>
#include <mem.h>
#include "helpmwh.hpp"

BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK    _export DlgProc(HWND, UINT, WPARAM, LPARAM);

char const szClassName[]   = "HelpmWhClass";
char const szWindowTitle[] = "WinHelp Demo";
HACCEL     hAccel;
BOOL       bF1 = FALSE;
HWND       hwndDlg = NULL;
DLGPROC    lpfnDlgProc;
HINSTANCE  hInst;

// =====================================
// Функция WinMain
// =====================================
#pragma argsused
int PASCAL
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  LPSTR lpszCmdLine, int nCmdShow)
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  if(!InitApp(hInstance))
      return FALSE;

  hInst = hInstance;

  hwnd = CreateWindow(
    szClassName, szWindowTitle, WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT,  CW_USEDEFAULT,
    0, 0, hInstance, NULL);

  if(!hwnd)
    return FALSE;

  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  // Загружаем таблицу акселераторов
  hAccel = LoadAccelerators(hInstance, "APP_ACCEL");

  while(GetMessage(&msg, 0, 0, 0))
  {
    if(!TranslateAccelerator(hwnd, hAccel, &msg))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================
BOOL InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass;
  WNDCLASS wc;

  memset(&wc, 0, sizeof(wc));
  wc.lpszMenuName  = "APP_MENU";
  wc.style         = 0;
  wc.lpfnWndProc   = (WNDPROC) WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszClassName = (LPSTR)szClassName;

  aWndClass = RegisterClass(&wc);
  return (aWndClass != 0);
}

// =====================================
// Функция WndProc
// =====================================
LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
    // Это сообщение поступает, если меню или модальная
    // диалоговая панель находится в состоянии ожидания
    case WM_ENTERIDLE:
    {
      // Пользователь выделил строку меню
      // Проверяем, была ли нажата клавиша <F1> 
      if((wParam == MSGF_MENU) &&
         ((GetKeyState(VK_F1) & 0x8000) != 0))
      {
        // Если была нажата клавиша <F1>, устанавливаем
        // флаг bF1, а затем имитируем нажатие
        // клавиши <Enter>
        bF1 = TRUE;
        PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0l);
      }

      // Если клавиша <F1> была нажата во время отображения
      // диалоговой панели, вызываем раздел оглавления
      // справочной системы
      else if((wParam == MSGF_DIALOGBOX) &&
         ((GetKeyState(VK_F1) & 0x8000) != 0))
      {
        hwndDlg = (HWND)LOWORD(lParam);
        WinHelp(hwnd, "hlpmore.hlp", HELP_CONTENTS, 0L);
      }
      break;
    }

    case WM_COMMAND:
    {
      switch (wParam)
      {
        // Отображаем раздел оглавления справочной системы
        case CM_HELPINDEX:
        {
          WinHelp(hwnd, "hlpmore.hlp", HELP_CONTENTS, 0L);
          return 0L;
        }
        case CM_HELPCOMMANDS:
        {
          // Если строка меню была выбрана клавишей <F1>,
          // выводим справочную информацию, в противном
          // случае выполняем команду
          if(bF1)
          {
            WinHelp(hwnd, "hlpmore.hlp", HELP_CONTENTS, 0L);
            bF1 = FALSE;
          }
          else
            WinHelp(hwnd, "hlpmore.hlp", HELP_CONTEXT,
              (DWORD)IDN_cmd);
          return 0L;
        }

        case CM_HELPKEYBOARD:
        {
          if(bF1)
          {
            WinHelp(hwnd, "hlpmore.hlp", HELP_CONTENTS, 0L);
            bF1 = FALSE;
          }
          else
            WinHelp(hwnd, "hlpmore.hlp", HELP_CONTEXT,
              (DWORD)IDN_key);
          return 0L;
        }

        case CM_HELPUSING_HELP:
        {
          if(bF1)
          {
            WinHelp(hwnd, "hlpmore.hlp", HELP_CONTENTS, 0L);
            bF1 = FALSE;
          }
          else
            WinHelp(hwnd, "hlpmore.hlp", HELP_HELPONHELP, 0L);
          return 0L;
        }

        case CM_HELPABOUT:
        {
          if(bF1)
          {
            WinHelp(hwnd, "hlpmore.hlp", HELP_CONTENTS, 0L);
            bF1 = FALSE;
          }
          else
          {
            lpfnDlgProc = (DLGPROC)MakeProcInstance(
               (FARPROC)DlgProc, hInst);
            DialogBox(hInst, "ABOUT_DIALOG",
               hwnd, lpfnDlgProc);
          }
          return 0;
        }

        case CM_FILEPRINTER_SETUP:
        case CM_FILEPAGE_SETUP:
        case CM_FILEPRINT:
        case CM_FILESAVEAS:
        case CM_FILESAVE:
        case CM_FILEOPEN:
        case CM_FILENEW:
        {
          if(bF1)
          {
            WinHelp(hwnd,"hlpmore.hlp", HELP_CONTEXT,
              (DWORD)IDN_file);
            bF1 = FALSE;
          }
          else
            MessageBox(hwnd, "Меню File",
              "WinHelp Demo", MB_OK);
          return 0;
        }

        case CM_EDITPASTE:
        case CM_EDITCOPY:
        case CM_EDITCUT:
        case CM_EDITUNDO:
        {
          if(bF1)
          {
            WinHelp(hwnd,"hlpmore.hlp", HELP_CONTEXT,
              (DWORD)IDN_edit);
            bF1 = FALSE;
          }
          else
             MessageBox(hwnd, "Меню Edit",
               "WinHelp Demo", MB_OK);
          return 0;
        }

        case CM_VIEWNORMAL:
        case CM_VIEWZOOM:
        {
          if(bF1)
          {
            WinHelp(hwnd,"hlpmore.hlp", HELP_CONTEXT,
              (DWORD)IDN_view);
            bF1 = FALSE;
          }
          else
            MessageBox(hwnd, "Меню View",
              "WinHelp Demo", MB_OK);
          return 0;
        }

        case CM_FILEEXIT:
        {
          DestroyWindow(hwnd);
          return 0;
        }

        default:
          return 0;
      }
    }

    case WM_DESTROY:
    {
      PostQuitMessage(0);
      return 0;
    }

    default:
      break;
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

// =====================================
// Функция DldProc
// =====================================
#pragma argsused
BOOL CALLBACK _export
DlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    case WM_INITDIALOG:
    {
      return TRUE;
    }

    case WM_COMMAND:
    {
      switch(wParam)
      {
        case IDOK:
        case IDCANCEL:
        {
          EndDialog(hdlg, 0);
          return TRUE;
        }
      }
    }
  }
  return FALSE;
}

В функции WinMain после обычной инициализации загружается таблица акселераторов, состоящая из одного определения. Комбинации клавиш <Shift+F1> ставится в соответствие сообщение CM_HELPINDEX, попадающее в функцию окна приложения при выборе строки "Index" из меню "Help". Используя эту комбинацию клавиш, пользователь сможет отобразить раздел оглавления справочной системы.

Функция окна обрабатывает сообщение WM_ENTERIDLE, которое и помогает нам организовать контекстно-зависимую подсказку.

Это сообщение попадает в функцию окна приложения в том случае, если активизировано меню или диалоговая панель, и эти органы управления находятся в состоянии ожидания.

Если сообщение WM_ENTERIDLE попало в функцию окна в результате отображения меню, параметр wParam этого сообщения содержит значение MSGF_MENU.

Если же указанное выше сообщение явилось результатом отображения диалоговой панели, параметр wParam содержит значение MSGF_DIALOGBOX.

В обоих случаях младшее слово параметра lParam содержит идентификатор окна (при отображении меню) или диалоговой панели (при отображении диалоговой панели).

Чем же нам может помочь сообщение WM_ENTERIDLE для организации контекстно-зависимой подсказки?

При обработке этого сообщения приложение может проверить состояние клавиши <F1>. Если эта клавиша была нажата, можно установить глобальный флаг запроса подсказки и поместить в очередь приложения сообщение WM_KEYDOWN с кодом клавиши <Enter>.

Результат будет такой же, как если бы пользователь выбрал строку меню при помощи клавиатуры, вначале выделив ее, а затем нажав клавишу <Enter>. Отличие заключается в том, что теперь установлен глобальный флаг запроса подсказки. Обработчик, запускаемый при выборе строки меню, может проверить этот флаг, и если он установлен, сбросить его и запросить контекстно-зависимую подсказку. Так как каждой строке меню соответствует свой индивидуальный обработчик, с организацией контекстно-зависимой подсказки не возникнет никаких проблем.

Именно по такому алгоритму и происходит обработка сообщения WM_COMMAND в нашем приложении.

Все необходимые константы определены в файле helpmwh.hpp (листинг 4.4).


Листинг 4.4. Файл hlpmore/helpmwh.hpp


#define CM_HELPABOUT         401
#define CM_HELPUSING_HELP    402
#define CM_HELPCOMMANDS      403
#define CM_HELPKEYBOARD      404
#define CM_HELPINDEX         405

#define CM_EDITPASTE         501
#define CM_EDITCOPY          502
#define CM_EDITCUT           503
#define CM_EDITUNDO          504

#define CM_VIEWNORMAL        601
#define CM_VIEWZOOM          602

#define CM_FILEEXIT          701
#define CM_FILEPRINTER_SETUP 702
#define CM_FILEPAGE_SETUP    703
#define CM_FILEPRINT         704
#define CM_FILESAVEAS        705
#define CM_FILESAVE          706
#define CM_FILEOPEN          707
#define CM_FILENEW           708

#define IDN_cmd  201
#define IDN_key  202
#define IDN_file 203
#define IDN_edit 204
#define IDN_view 205

Обратите внимание на константы, имя которых начинается с префикса IDN. Это номера контекста разделов справочной системы hlpmore.hlp, определенные в файле проекта hlpmore.hpj (листинг 4.2).

Ресурсы приложения (меню, пиктограмма, акселераторы и диалоговая панель) определены в файле helpmwh.rc (листинг 4.5).


Листинг 4.5. Файл hlpmore/helpmwh.rc


#include "helpmwh.hpp"

APP_MENU MENU 
BEGIN
        POPUP "&File"
        BEGIN
          MENUITEM "&New",              CM_FILENEW
          MENUITEM "&Open...",          CM_FILEOPEN
          MENUITEM "&Save",             CM_FILESAVE
          MENUITEM "Save &as...",       CM_FILESAVEAS
          MENUITEM SEPARATOR
          MENUITEM "&Print...",         CM_FILEPRINT
          MENUITEM "Page se&tup...",    CM_FILEPAGE_SETUP
          MENUITEM "P&rinter setup...", CM_FILEPRINTER_SETUP
          MENUITEM SEPARATOR
          MENUITEM "E&xit",             CM_FILEEXIT
        END

        POPUP "&Edit"
        BEGIN
          MENUITEM "&Undo\tCtrl+Z",     CM_EDITUNDO
          MENUITEM "Cu&t\tCtrl+X",      CM_EDITCUT
          MENUITEM "&Copy\tCtrl+C",     CM_EDITCOPY
          MENUITEM "&Paste\tCtrl+V",    CM_EDITPASTE
        END

        POPUP "&View"
        BEGIN
          MENUITEM "&Normal",     CM_VIEWNORMAL
          MENUITEM "&Zoom...",    CM_VIEWZOOM
        END

        POPUP "&Help"
        BEGIN
          MENUITEM "&Index\tF1",  CM_HELPINDEX
          MENUITEM "&Keyboard",   CM_HELPKEYBOARD
          MENUITEM "&Commands",   CM_HELPCOMMANDS
          MENUITEM "&Using help", CM_HELPUSING_HELP
          MENUITEM SEPARATOR
          MENUITEM "&About...",   CM_HELPABOUT
        END
END

AppIcon ICON helpmwh.ico

APP_ACCEL ACCELERATORS
BEGIN
  VK_F1, CM_HELPINDEX, VIRTKEY, SHIFT
END

ABOUT_DIALOG DIALOG 25, 34, 152, 67
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "WinHelp Demo"
BEGIN
  CTEXT "WinHelp Demo\n"
        "Приложение HELPMWH\n"
         "(C) Frolov A.V., 1995", -1, 28, 9, 117, 26,
     WS_CHILD | WS_VISIBLE | WS_GROUP
   ICON "AppIcon", -1, 6, 14, 16, 16, WS_CHILD | WS_VISIBLE
   DEFPUSHBUTTON "OK", IDOK, 56, 43, 36, 14,
     WS_CHILD | WS_VISIBLE | WS_TABSTOP
END

Файл определения модуля приложения HELPMWH представлен в листинге 4.6.


Листинг 4.6. Файл hlpmore/helpmwh.def


NAME        HELPMWH
DESCRIPTION 'Приложение HELPMWH, (C) 1995, Frolov A.V.'
EXETYPE     windows
STUB        'winstub.exe'
STACKSIZE   8120
HEAPSIZE    1024
CODE        preload moveable discardable
DATA        preload moveable multiple

4.6. Встроенное окно

При создании справочной базы данных с использованием приложения winhelp.exe существует малоизвестная возможность создания встроенных окон, внутри которых разработчик справочной системы может делать практически все что угодно, за исключением ввода с клавиатуры (так как встроенное окно не может получить фокус ввода).

Процедура создания встроенных окон не описана в документации, поставляющейся вместе с SDK, однако необходимая информация есть в руководстве к утилите "Windows Help Authoring Guide for Word for Windows 2.0", которое поставляется на компакт-диске MSDN CD ("Microsoft Developer Network. Development Library").

Для чего можно использовать встроенное окно?

Можно придумать различные применения, например, следующие.

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

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

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

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

{ewl dllname, wndclass, param}

Как и при вставке bmp-файлов, в зависимости от выбранной команды будет использован один из трех способов взаимного расположения текста и встроенного окна в окне раздела:

КомандаСпособ расположения
ewcВстроенное окно будет вставлено в строку как символ
ewlВстроенное окно выравнивается по левой границе, текст располагается справа
ewrВстроенное окно выравнивается по правой границе, текст располагается слева

Параметр dllname - это имя DLL-библиотеки, которую требуется разработать специально для обслуживания встроенного окна. При инициализации функция LibMain этой библиотеки должна зарегистрировать класс окна wndclass, указанный во втором операторе команды вставки встроенного окна.

Функция окна, соответствующая классу wndclass и определенная в библиотеке dllname будет получать и обрабатывать сообщения, предназначенные для встроенного окна.

Через параметр param можно передать любую текстовую строку, которая будет доступна на этапе создания встроенного окна при обработке сообщения WM_CREATE.

Сообщения для встроенного окна

Функция встроенного окна ведет себя как дочернее окно главного окна приложения winhelp.exe (или вторичного окна). В частности, при создании функция окна получает сообщение WM_CREATE, а при уничтожении - WM_DESTROY. Есть также ряд сообщений, специфических для встроенного окна.

Сообщение WM_CREATE

Сообщение WM_CREATE может попадать в функцию встроенного окна несколько раз за время одного сеанса работы со справочной системой. Если пользователь отображает раздел, содержащий встроенное окно, оно создается. Затем это окно может быть уничтожено при переходе к другому разделу и создано заново при повторном отображении того же раздела.

Когда функция встроенного окна получает сообщение WM_CREATE, параметр lParam содержит указатель на структуру CREATESTRUCT. Поле lpCreateParams этой структуры, в свою очередь, содержит указатель на структуру EWDATA следующего вида (не описана в файле windows.h):

typedef struct tagCreateInfo 
{
  short   idMajVersion; // ст. версия winhelp.exe
  short   idMinVersion; // мл. версия winhelp.exe
  LPSTR   szFileName;   // путь к hlp-файлу
  LPSTR   szAuthorData; // строка параметров команды ewl
  HANDLE  hfs;          // идентификатор файловой системы
  DWORD   coFore;  // основной цвет главного окна winhelp.exe
  DWORD   coBack;  // фоновый  цвет главного окна winhelp.exe
} EWDATA;

Microsoft рекомендует проверить поля idMajVersion и idMinVersion (старший и младший номер версии справочной системы winhelp.exe) на равенство нулю. Если содержимое этих полей не равно нулю, работоспособность вашей DLL-библиотеки с этой версией winhelp.exe не гарантируется.

Поле szFileName содержит указатель на текстовую строку, содержащую путь к hlp-файлу. Если эта строка вам нужна, ее надо скопировать в отдельный буфер на этапе обработки сообщения WM_CREATE.

Через поле szAuthorData передается указатель на текстовую строку, указанную при вставке встроенного окна в раздел, т. е. строка param в команде ewl, ewc или ewr. Если эта строка нужна, ее также следует сохранить на этапе обработки сообщения WM_CREATE.

Через параметр hfs передается идентификатор файловой системы hlp-файла, который может пригодиться при выполнении операций с данными, описанными в секции BAGGAGE файла проекта справочной системы. Подробное рассмотрение этих операций выходит за рамки нашей книге, однако несколько слов по этому поводу мы скажем в конце текущей главы.

И, наконец, через параметры coFore и coBack передается основной и фоновый цвет главного окна winhelp.exe, соответственно. Вы можете использовать эти значения для раскраски создаваемого встроенного окна.

Так как отображение встроенного окна выполняется приложением winhelp.exe, ваше приложение не должно вызывать для этого окна функцию ShowWindow или назначать для него стиль WS_VISIBLE.

Сообщение EWM_QUERYSIZE

Функция встроенного окна получает сообщение EWM_QUERYSIZE (с кодом 0x706b) от приложения winhelp.exe.

Параметр wParam содержит идентификатор контекста отображения для окна. Через параметр lParam передается указатель на структуру POINT.

Основная задача обработчика сообщения EWM_QUERYSIZE заключается в том, чтобы записать в поля x и y структуры POINT, соответственно, ширину и высоту встроенного окна. Таким образом, встроенное окно должно сообщить приложению winhelp.exe свои размеры.

Сообщение EWM_RENDER

Содержимое раздела справочной системы может быть скопировано в Clipboard или распечатано на принтере. В первом случае приложению winhelp.exe требуется получить текстовое представление содержимого встроенного окна, во втором - графическое в виде битового изображения.

Для получения текстового и графического представления приложение winhelp.exe посылает в функцию встроенного окна сообщение EWM_RENDER (с кодом 0x706a). Если параметр wParam этого сообщения равен константе CF_TEXT, обработчик должен вернуть текстовое представление, а если CF_BITMAP - графическое в виде битового изображения.

Процедура возврата текстового представления достаточно проста. Она заключается в том, что обработчик сообщения EWM_RENDER создает и фиксирует глобальный блок памяти. Затем он записывает в этот блок памяти текстовую строку представления содержимого встроенного окна, расфиксирует блок памяти и возвращает идентификатор блока памяти. Освобождение блока памяти выполняет приложение winhelp.exe, вам не нужно беспокоиться по этому поводу.

Если требуется вернуть графическое представление, параметр lParam сообщения EWM_RENDER содержит указатель на структуру следующего вида (не описана в файле windows.h):

typedef struct tagRenderInfo
{
  RECT rc;
  HDC  hdc;
} RENDERINFO;

Поле hdc этой структуры нужно использовать для создания битового изображения функцией CreateCompatibleBitmap.

Что же касается размеров битового изображения, их следует получить при помощи сообщения EWM_QUERYSIZE.

Сообщение EWM_ASKPALETTE

Приложение winhelp.exe посылает сообщение EWM_ASKPALETTE (с кодом 0x706c) функции встроенного окна для того чтобы получить информацию об используемой цветовой палитре.

Обработчик сообщения EWM_ASKPALETTE должен вернуть идентификатор палитры, используемой встроенным окном.

Сообщение EWM_FINDNEWPALETTE

Сообщение EWM_FINDNEWPALETTE (с кодом 0x706d) нигде не документировано, однако оно встречается в *.h файлах примеров, поставляемых в составе средств разработки справочных систем на базе Microsoft Windows Help.

Библиотека HELPMORE.DLL

В этом разделе мы приведем исходные тексты DLL-библиотеки, предназначенной для работы совместно со справочной системой helpmore.hlp, описанной нами ранее.

Основной файл исходного текста приведен в листинге 4.7.


Листинг 4.7. Файл hlpmore/hlpmore.cpp


#define  STRICT
#include <windows.h>
#include <mem.h>
#include <time.h>

#include "hlpmore.h"

BOOL RegisterEWclass(HMODULE hModule);
extern "C" LRESULT CALLBACK _export
EWWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
char const szClassName[]   = "EWHlpMoreClass";

// ========================================================
// Функция LibMain
// Получает управление только один раз при
// загрузке DLL-библиотеки в память
// ========================================================
#pragma argsused
int FAR PASCAL
LibMain(HINSTANCE hModule, WORD wDataSegment,
  WORD wHeapSize, LPSTR lpszCmdLine)
{
  // После инициализации локальной области данных
  // функция LibEntry фиксирует сегмент данных.
  // Его необходимо расфиксировать.
  if(wHeapSize != 0)
    // Расфиксируем сегмент данных
    UnlockData(0);

  // Регистрируем класс для встроенного окна
  if(!RegisterEWclass(hModule))
    return FALSE;
  else
    // Возвращаем TRUE. Это означает, что инициализация
    // DLL-библиотеки выполнена успешно
    return TRUE;
}

// ========================================================
// Функция WEP
// Получает управление только один раз при
// удалении DLL-библиотеки из памяти
// ========================================================
#pragma argsused
int FAR PASCAL WEP(int bSystemExit)
{
  return 1;
}

// ========================================================
// Функция MsgBox
// Выводит на экран диалоговую панель с сообщением
// ========================================================
extern "C" void FAR PASCAL _export
MsgBox(HWND hwnd, LPSTR szMsg)
{
  MessageBox(hwnd, szMsg, "Message from DLL", MB_OK);
}

// ========================================================
// Функция RegisterEWclass
// Регистрация класса для встроенного окна
// ========================================================
BOOL RegisterEWclass(HMODULE hModule)
{
  ATOM aWndClass;
  WNDCLASS wc;

  memset(&wc, 0, sizeof(wc));

  // Класс окна доступен для всех приложений
  wc.style         = CS_GLOBALCLASS;

  wc.lpszMenuName  = NULL;
  wc.lpfnWndProc   = (WNDPROC) EWWndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hModule;
  wc.hIcon         = NULL;
  wc.hCursor       = LoadCursor(hModule, "AppCursor");
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszClassName = (LPSTR)szClassName;

  aWndClass = RegisterClass(&wc);
  return (aWndClass != 0);
}

// ========================================================
// Функция EWWndProc
// Функция встроенного окна
// ========================================================
extern "C" LRESULT CALLBACK _export
EWWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  HDC hdc;
  PAINTSTRUCT ps;
  RECT rc;
  TEXTMETRIC tm;
  int cxChar, cyChar;
  QCI  qci;
  QRI  qri;
  static BYTE szCustomData[80];
  static BYTE szBuf[80];

  #define CLOCK_TIMER 1

  switch (msg)
  {
    // Создание встроенного окна
    case WM_CREATE:
    {
      // Копируем строку параметров
      qci = (QCI)((CREATESTRUCT FAR *)lParam)->lpCreateParams;
      if(lstrlen(qci->szAuthorData) < 80)
        lstrcpy(szCustomData, qci->szAuthorData);

      // Добавляем к встроенному окну рамку 
      SetWindowLong(hwnd, GWL_STYLE,
        GetWindowLong(hwnd,GWL_STYLE) | WS_BORDER);

      // Создаем таймер для часов
      SetTimer(hwnd, CLOCK_TIMER, 1000, NULL);
      return 0;
    }

    // Сообщение от таймера
    case WM_TIMER:
    {
      // Перерисовываем встроенное окно
      InvalidateRect(hwnd, NULL, FALSE);
      return 0;
    }

    // Обработчик сообщения WM_PAINT
    case WM_PAINT:
    {
      int    nBufSize;
      time_t t;
      struct tm *ltime;
      RECT    rc;

      hdc = BeginPaint(hwnd, &ps);

      // Определяем время и его отдельные компоненты
      time(&t);
      ltime = localtime(&t);

      // Подготавливаем буфер, заполняя его
      // строкой с текущим временем
      nBufSize = wsprintf(szBuf, "%02d:%02d:%02d",
        ltime->tm_hour, ltime->tm_min, ltime->tm_sec);

      // Выбираем шрифт с фиксированной шириной букв
      SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));

      // Получаем координаты и размер окна
      GetClientRect(hwnd, &rc);

      // Выбираем цвет текста для часов
      SetTextColor(ps.hdc, RGB(0,100,0));

      // Выводим время в центре окна
      DrawText(hdc, (LPSTR)szBuf, nBufSize, &rc,
        DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_SINGLELINE);

      EndPaint(hwnd, &ps);
      return 0;
    }

    // Обработчик этого сообщения должен определить
    // размеры встроенного окна
    case EWM_QUERYSIZE:
    {
      // Определяем метрики фиксированного шрифта
      hdc = GetDC(hwnd);
      SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
      GetTextMetrics(hdc, &tm);
      cxChar = tm.tmMaxCharWidth;
      cyChar = tm.tmHeight + tm.tmExternalLeading;
      ReleaseDC(hwnd, hdc);

      // Сохраняем размеры встроенного окна
      ((LPPOINT)lParam)->x = 10 * cxChar;
      ((LPPOINT)lParam)->y = 2  * cyChar;

      return 1;
    }

    // В ответ на это сообщение функция встроенного окна
    // должна вернуть представление содержимого окна
    // в виде текста или битового изображения
    case EWM_RENDER:
    {
      long lPtr = 0l;

      switch(wParam)
      {
        // Представление содержимого в виде текста
        case CF_TEXT:
        {
          // Заказываем глобальный блок памяти
          HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE, 50);
          if(hglb)
          {
            // Фиксируем блок памяти
            LPSTR lpszTempBuf = (LPSTR)GlobalLock(hglb);

            // Копируем строку, содержащую текущее время
            lstrcpy(lpszTempBuf,"\r\n");
            lstrcat(lpszTempBuf,szBuf);
            lstrcat(lpszTempBuf,"\r\n");

            // Расфиксируем блок памяти
            GlobalUnlock(hglb);

            // Возвращаем идентификатор блока памяти,
            // содержащего текстовое представление
            lPtr = (long)hglb;
          }
          break;
        }

        // Представление содержимого
        // в виде битового изображения 
        case CF_BITMAP:
        {
          POINT pt;
          RECT rc;
          HBITMAP hbmp, hbmpOld;
          HBRUSH hbrush;

          // Сохраняем указатель на структуру RENDERINFO
          qri = (QRI)lParam;

          // Создаем контекст отображения, совместимый
          // с экраном монитора
          hdc = CreateCompatibleDC(NULL);

          // Определяем размеры встроенного окна
          SendMessage(hwnd, EWM_QUERYSIZE,
            (WPARAM)hdc, (long)(LPPOINT)&pt);

          // Создаем битовое изображение, имеющее размеры,
          // равные размерам встроенного окна 
          rc.left = rc.top = 0;
          rc.right = pt.x;
          rc.bottom = pt.y;
          hbmp = CreateCompatibleBitmap(qri->hdc, pt.x, pt.y);

          // Выбираем битовое изображение
          // в контекст отображения
          hbmpOld = (HBITMAP)SelectObject(hdc,hbmp);

          // Закрашиваем битовое изображение цветом фона
          hbrush = CreateSolidBrush(GetBkColor(hdc));
          FillRect(hdc, &rc, hbrush);
          DeleteObject(hbrush);

          // Рисуем рамку по периметру битового изображения
          Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);

          // Рисуем время в центре битового изображения
          DrawText(hdc, (LPSTR)szBuf, lstrlen(szBuf), &rc,
            DT_CENTER | DT_VCENTER | DT_NOCLIP | DT_SINGLELINE);

          // Выбираем старое битовое изображение
          hbmp = (HBITMAP)SelectObject(hdc, hbmpOld);
          DeleteDC(hdc);

          // Возвращаем идентификатор созданного
          // битового изображения
          lPtr = (long)hbmp;

          break;
        }
      }

      return lPtr;
    }

    // Обрабатываем сообщение от левой клавиши мыши
    case WM_LBUTTONDOWN:
    {
      if(IDYES == MessageBox(hwnd, "Запустить clock.exe?",
       "Help Sample", MB_YESNO | MB_ICONQUESTION))
        WinExec("clock.exe", SW_SHOW);

      #define IDN_CLOCK 200

      // Во временном окне отображаем раздел справочной
      // системы с номером контекста, равным IDN_CLOCK
      WinHelp(hwnd, "hlpmore.hlp", HELP_CONTEXTPOPUP,
          (DWORD)IDN_CLOCK);

      return 0;
    }

    // При удалении встроенного окна уничтожаем таймер
    case WM_DESTROY:
    {
      KillTimer(hwnd, CLOCK_TIMER);
      return 0;
    }

    default:
      break;
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

Функция WinMain получает управление при загрузке DLL-библиотеки в память. Ее основная задача - регистрация класса встроенного окна, для чего вызывается функция RegisterEWclass, определенная в этой же библиотеке.

Функция RegisterEWclass выполняет обычную процедуру регистрации класса, однако при регистрации используется стиль CS_GLOBALCLASS. Класс, зарегистрированный с этим стилем, доступен для использования всеми запущенными приложениями - это глобальный класс.

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

Функция EWWndProc выполняет роль функции встроенного окна. Она обрабатывает все сообщения, поступающие от приложения winhelp.exe при создании, в процессе работы и при удалении встроенного окна.

Обработчик сообщения WM_CREATE копирует строку параметров, добавляет к окну рамку и создает таймер с периодом работы 1 сек.

Каждую секунду от таймера в функцию встроенного окна приходит сообщение WM_TIMER. Обработка этого сообщения заключается в полной перерисовке содержимого встроенного окна.

Обработчик сообщения WM_PAINT вызывается при создании окна и затем периодически, раз в секунду. Он рисует в центре окна текстовую строку текущего времени.

Обработчик сообщения EWM_QUERYSIZE возвращает размер окна, определяя его на основании метрик фиксированного системного шрифта.

Как мы уже говорили, когда приложению winhelp.exe требуется получить текстовое или графическое представление содержимого встроенного окна, оно посылает функции окна сообщение EWM_RENDER.

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

Все выполняемые при этом действия были описаны нами ранее в предыдущих томах "Библиотеки системного программиста", поэтому они должны быть понятны без дополнительных объяснений.

Обратим ваше внимание на обработчик сообщения WM_LBUTTONDOWN.

Этот обработчик был определен для обеспечения возможности использования встроенного окна для организации чувствительной точки (в исходном тексте раздела встроенное окно нельзя использовать для организации ссылки или запуска макрокоманд).

Когда пользователь расположит курсор мыши над поверхностью встроенного окна и нажмет левую клавишу мыши, функция встроенного окна получит обычное сообщение WM_LBUTTONDOWN. Обработчик этого сообщения выводит диалоговую панель с предложением запустить приложение clock.exe, при необходимости запускает это приложение, а затем вызывает функцию WinHelp.

Функция WinHelp используется для организации гипертекстовой ссылки на раздел с номером контекста IDN_CLOCK. Раздел будет отображен во временном окне.

Идентификаторы констант, а также все необходимые структуры данных определены в файле hlpmore.h (листинг 4.8).


Листинг 4.8. Файл hlpmore/hlpmore.h


#define EWM_RENDER         0x706A
#define EWM_QUERYSIZE      0x706B
#define EWM_ASKPALETTE     0x706C
#define EWM_FINDNEWPALETTE 0x706D

typedef struct tagCreateInfo 
{
  short   idMajVersion;
  short   idMinVersion;
  LPSTR   szFileName;
  LPSTR   szAuthorData;
  HANDLE  hfs;
  DWORD   coFore;
  DWORD   coBack;
} EWDATA, FAR* QCI;

typedef struct tagRenderInfo
{
  RECT rc;
  HDC  hdc;
} RENDERINFO, FAR* QRI;

Файл описания ресурсов содержит ссылку на файл hlpmore.cur (листинг 4.9). Файл hlpmore.cur содержит курсор, который используется для встроенного окна.


Листинг 4.9. Файл hlpmore/hlpmore.rc


AppCursor CURSOR hlpmore.cur

Файл определения модуля DLL-библиотеки hlpmore.dll приведен в листинге 4.10.


Листинг 4.10. Файл hlpmore/hlpmore.def


LIBRARY        HLPMORE
DESCRIPTION    'DLL-библиотека HLPMORE, (C) 1995, Frolov A.V.'
EXETYPE        windows
CODE           preload moveable discardable
DATA           preload moveable single
HEAPSIZE       1024

4.7. Другие возможности

Возможности приложения winhelp.exe слишком велики, чтобы их можно было описать полностью, к тому же они не все документированы. Авторы этой книги знают о существовании полного описания системы Windows Help, предназначенной только для внутреннего пользования в Microsoft, состоящего из сотен страниц. В этом разделе мы очень кратко расскажем еще о нескольких возможностях.

Глобальные переменные

Если вы создаете собственные макрокоманды (как функции DLL-библиотеки), вам может пригодиться информация о внутренних переменных winhelp.exe. Эти переменные можно передавать как параметры стандартным и созданным вами макрокомандам.

Приведем список внутренних переменных.

Имя переменнойТипОписание
hwndAppUИдентификатор главного окна приложения winhelp.exe. Можно пользоваться только во время выполнения функции, вызываемой из DLL-библиотеки
hwndContextUИдентификатор текущего активного окна приложения winhelp.exe
qchPathSПуть к hlp-файлу
qErrorSДальний указатель на структуру, содержащую информацию об ошибке, возникшей при последнем обращении к winhelp.exe
lTopicNoUНомер раздела
hfsUИдентификатор файловой системы для текущего hlp-файла
coForegroundUОсновной цвет окна
coBackgroundUФоновый цвет окна

Секция BAGGAGE

Разработчик справочной системы может добавить в hlp-файл (в его внутреннюю файловую систему) произвольные файлы данных, описав их в секции BAGGAGE файла проекта справочной системы. Это могут быть, например, видео- или звуковые данные, графические изображения и т. п.

Вызов внутренних функций

Разработчик справочной системы может использовать 16 внутренних функций, экспортируемых приложением winhelp.exe. Эти функции позволяют работать с внутренней файловой системой hlp-файла. Их можно использовать для доступа к данным, описанным в секции BAGGAGE.

Определив функцию LDLLHandler, разработчик DLL-библиотеки может получать извещения от приложения winhelp.exe о таких действиях пользователя, как выбор чувствительной точки или передача фокуса ввода другим приложениям.

Назад       Содержание       Вперёд