    Система помощи 

    Интерактивная помощь с самого начала была частью Windows и ее приложений. 
Но в последнее время система помощи приобрела новые возможности и стала играть 
более важную роль. Например, в интерфейсе пользователя в Windows 95 
существенное внимание уделяется именно помощи. Если раньше можно было написать 
вполне профессиональное приложение, которое включало бы только наиболее 
устаревшие виды интерактивной помощи, то сейчас это невозможно. Сегодня любая 
солидная программа должна включать все современные возможности системы помощи. 
А интерактивная помощь стала неотъемлемой частью всех коммерческих приложений. 
    Поскольку интерактивная помощь очень важна, то в большинстве программ 
предыдущих 15 глав для нее отводился специальный пункт меню. Он предназначался 
только для того, чтобы подчеркнуть, что система помощи должна быть включена во 
все приложения Windows. В этой главе будет рассмотрено, как заменить данный 
пункт на реальный вызов системы помощи. 

    431 


    Два типа помощи 

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

    Рис. 16.1. Стандартное окно помощи 

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

    432 MFC: основы программирования 


    Рис. 16.2. Пример контекстной помощи 


    Вызов помощи 

    Чтобы реализовать все возможности системы помощи Windows, любая программа 
должна поддерживать стандартные методы вызова помощи пользователем. В 
частности, пользователь может получить помощь одним из четырех способов: 
    1. По щелчку правой кнопки мыши на объекте. 
    2. По щелчку на кнопке "?", а затем на требуемом объекте. 
    3. По нажатию клавиши [F1]. 
    4. Через меню Help. 
    Первые два способа практически всегда используются для вызова контекстной 
помощи или всплывающих подсказок. Иногда и клавиша [F1] используется для 
вызова контекстной помощи. Но в основном она предназначена для вызова 
справочной помощи. Меню Help предназначено только для работы со справочной помощью. 
    Допускается также, чтобы сама программа вызывала, при необходимости, 
систему помощи. Это возможно, к примеру, в тех ситуациях, когда пользователь 
пытается выполнить некорректные действия. 
    В MFC работа с системой помощи ведется через класс CWinApp. Когда 
пользователь запрашивает помощь, приложение автоматически обрабатывает этот запрос 

    16. Система помощи 433 

    путем вызова либо функции WinHelpQ класса CWinApp, либо (в некоторых 
ситуациях) непосредственно API-функции WinHelpQ. Эти функции довольно мощные, 
они автоматически обрабатывают все запросы помощи. Прежде чем приступить к их 
изучению, необходимо научиться создавать файл помощи. 
    Примечание: Во избежание путаницы, при ссылке на API-версию функции 
WinHelp() в тексте главы ей будет предшествовать оператор расширения области видимости: 

    ::WinHelp(). 


    Файл помощи 

    Ядром системы помощи в Windows является файл помощи. Он используется как 
для контекстных подсказок, так и в справочной помощи. Такие файлы не являются 
текстовыми файлами. Они компилируются особым образом и имеют расширение HLP. 
Для создания файла помощи необходимо сначала создать файл формата RTF (Rich 
Text Format), содержащий все необходимые разделы в форматированном виде, с 
индексами и перекрестными ссылками. Такой файл имеет расширение RTF и 
компилируется с помощью компилятора файлов помощи. Например, с Microsoft 
Visual C++ поставляется компилятор HCW. Результатом работы компилятора 
является HLP-файл. Таким образом, по отношению к этому компилятору RTF-файл 
является исходным, а HLP-файл — объектным. 
    В формате RTF содержится большое число команд. Компилятор 4)айлов помощи 
воспринимает лишь часть из них. В то же время система помощи распознает 
некоторые специальные команды помощи, не связанные с форматом RTF. Все 
RTF-команды начинаются с символа "\". Например, команда \Ь означает выделение 
жирным шрифтом (bold). Мы не станем описывать здесь все RTF-команды (для этого 
потребовалась бы целая книга). Будут рассмотрены лишь самые важные и наиболее 
часто используемые команды, относящиеся к файлам помощи. Но для серьезной 
работы с файлами помощи необходимо, конечно же, полное описание формата RTF. 
    Помимо RTF-файлов компилятор файлов помощи использует также файл проекта. 
В нем задаются различные установки и константы, относящиеся к файлу помощи. 
Файл проекта имеет расширение HPJ. 

    Создание файла помощи 

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

    434 MFC: основы программирования 


    Общий вид файла помощи 

    В исходном варианте все файлы помощи имеют некоторые общие компоненты. 
Во-первых, весь текст файла должен быть заключен в фигурные скобки. Т.е. файл 
должен начинаться с символа "{" и заканчиваться символом "}". Сразу вслед за 
открывающей фигурной скобкой должна находиться команда \rtf. Она указывает, 
что данный файл создан в формате RTF, и определяет версию формата. Затем 
необходимо указать используемый набор символов. Обычно для этого используется 
команда \ansi, которая задает набор символов, соответствующий стандарту ANSI. 
Необходимо также определить используемые шрифты. Для этого предназначена 
команда \fonttbl. Таким образом, общий вид RTF-файла помощи будет примерно таким: 

    {\rtf4\ansi\fonttbl ... 
    Содержимое файла помощи 
    } 

    В RTF-файле могут использоваться дополнительные фигурные скобки, которые 
предназначены для определения действий, относящихся к одной команде. Это 
напоминает файлы на С или C++, где фигурные скобки определяют блок команд. 

    Некоторые RTF-команды 

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

    Таблица 16.1. Некоторые RTF-команды, связанные с файлами помощи 

    RTF-команда Назначение 

    \ansi              Определяет набор символов, соответствующий стандарту ANSI 
    \b               Включает режим символов, выделенных жирным шрифтом 
    \ЬО              Выключает режим символов, выделенных жирным шрифтом 
    \fn               Устанавливает шрифт, определяемый параметром п 
    \fsn               Устанавливает размер шрифта, определяемый параметром и 
    \fonttbl            Определяет таблицу шрифтов 
    \footnote          Задает ключевые слова и заголовки, помещаемые в индекс 
    \i               Включает режим наклонных символов 
    \Ю              Выключает режим наклонных символов 
    \page              Обозначает конец раздела 
    \раг               Обозначает конец параграфа 
    \rtf>i              Определяет версию RTF-формата. Для Windows 95 параметр 
п должен равняться 4. Для более старых версий Windows необходимо указывать 1 
    \tab               Передвигает курсор на одну позицию табуляции вперед 
    \uldb              Выделяет цветом гипертекстовую связь ("горячее слово") 
с другим разделом 
    \v                 Создает гипертекстовую связь (используется вместе с 
командой \uldb) 


    16. Система помощи 435 


    \ansi 
    Эта команда определяет набор символов, соответствующий стандарту ANSI. В 
формате RTF предусмотрена поддержка и других наборов символов, таких как \тас 
(для Macintosh) и \рс (набор символов, определяемый OEM-производителем). Чаше 
всего для приложений Windows используется ANSI-набор. 
    \Ь 
    Эта команда включает режим символов, выделенных жирным шрифтом. Команда 
\ЬО выключает данный режим. Если команда \Ь используется в пределах блока, то 
жирным шрифтом будет выделен только текст этого блока, и использовать затем 
команду \ЬО нет необходимости. Например, в выражении 
    {\Ь это жирный шрифт,} а это нет 
    только текст, заключенный в фигурные скобки, будет выделен жирным шрифтом. 
    V" 
    С помощью данной команды можно установить определенный шрифт, который 
    задается номером, указываемым в параметре п. Шрифт должен быть 
предварительно описан с помощью команды \fonttbl. 
    \fsn 
    Эта команда устанавливает размер шрифта равным параметру п. При этом одной 
единице размера соответствует половина пункта (point). Например, команда \fs24 
задает размер шрифта 12. 
    \fonttbl 
    Прежде чем шрифт будет использован, он должен быть включен в выражение 
\fonttbl. Формат данного выражения таков: 

    {\fonttbl 
    (\И\Имя семейства Имя шрифта;} 
    {\^2\Имя семейства Имя шрифта;] 
    {\{3\Имя семейства Имя шрифта;} 
    {\{п\Имя семейства Имя шрифта;} 
    } 

    Здесь параметр Имя_семейства задает семейство шрифта (например froman или 
fswiss), а параметр Имя_шрчфта определяет имя конкретного шрифта (например 
Times New Roman, Arial или Old English) в пределах данного семейства. Номер 
шрифта, указываемый с помощью команды \fn, будет впоследствии использован при 
выборе этого шрифта. Ниже приведен частичный список семейств и соответствующих 
им названий шрифтов (табл. 16.2). 

    436 MFC: основы программирования 


    Таблица 16.2. Семейства и названия шрифтов 

    Семейство          Шрифты 

    \froman            Times New Roman, Palatino 
    \fswiss                 Arial 
    \fmodern           Courier New, Pica 
    \fscript                Cursive 
    \fdecor               Old English 


    Например, в следующем блоке шрифту \fswiss Arial присваивается номер 0: 

    (\fonttbl {\f0\fswiss Arial;)} 
    \footnote 

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

    $(\footnote string) 
    K(\footnote string) 
    #(\footnote string) 
    +(\footnote Имя последовательности:Порядок следования} 
    @{\footnote string) 

    Форма $ определяет название раздела, которое будет отображено в окне 
помощи. Название может включать в себя пробелы. 
    Форма К указывает, что параметр string является ключевым словом или 
фразой. Этот параметр также может включать пробелы. Ключевые слова 
отображаются в списке индексов. Если первым символом строки является "К", то 
перед ним должен находиться дополнительный пробел. Форма К может 
использоваться только в том случае, когда определено имя раздела. 
    Форма # определяет контекстный идентификатор, который используется для 
организации гипертекстовых связей и перекрестных ссылок между разделами. Этот 
идентификатор также используется приложением для доступа к отдельным 
фрагментам файла помощи. В этом случае параметр string не должен содержать 
пробелов. Строка идентификатора обычно является константой, заменяющей 
конкретное числовое значение. 
    Форма + задает последовательность просмотра. Данная последовательность 
определяет порядок переходов между разделами при нажатии кнопок просмотра. 
(Это кнопки « и », расположенные в панели кнопок окна помощи.) Здесь параметр 
Имя_последовательности определяет саму последовательность, а параметр Порядок. 
_следования задает позицию текущего раздела в последовательности. Такие 
последовательности выполняются в алфавитном порядке или в порядке возрастания 
номеров позиций, в зависимости от значений, указываемых в параметре 
Порядок_следования. В файле помощи может быть несколько последовательностей 
просмотра. Для их задания в команде \footnote необходимо указывать как 
параметр Ямя_яоследовательности, так и 

    16. Система помощи                                               437 

    параметр Порядок _следования. Если в файле помощи имеется только одна 
последовательность просмотра, то параметр Имя последовательности можно 
опускать. Пример последовательности просмотра содержится в тексте файла 
помощи, приводимом ниже. 
    Для того чтобы кнопки просмотра появились в стандартном окне помощи, 
необходимо в конфигурационный раздел файла проекта, связанного с файлом 
помощи, включить макрокоманду BrowseButtonsQ. 
    Форма @ команды \footnote используется для включения в файл комментариев. 
    \« 
    Эта команда включает режим наклонных символов. Команда \i0 выключает 
данный режим. Если команда \i используется в пределах блока, то курсивом будет 
выделен только текст этого блока, и использовать затем команду \i0 нет необходимости. 
    \раде 
    Эта команда обозначает конец раздела. 
    \раг 
    Эта команда обозначает конец параграфа. Она также указывает на то, что 
данная строка должна быть пропущена. Таким образом, две команды \раг, 
записанные подряд, обозначают пропуск двух строк. 
    \rtfn 
    Эта команда определяет используемую версию формата RTF. Для Windows 95 
параметр п должен равняться 4. Для Windows 3.1 значением п должно быть 1. 
    \tab 
    Эта команда передвигает курсор на следующую позицию табуляции. 
    \uldb 
    Для выделения так называемого "горячего слова" (т.е. гипертекстовой связи) 
необходимо использовать команду \uldb. Она имеет следующий формат: 
    \uldb text 
    Строка, задаваемая параметром text, будет отображена стандартным цветом и 
шрифтом, установленным для горячих слов. Данную команду всегда необходимо 
использовать совместно с командой \v. 
    \v 
    Эта команда создает гипертекстовую связь к другому разделу. Ее формат таков: 
    \v context-ID 
    Здесь параметр context-ID должен соответствовать одному из значений, 
определенных командой #\footnote. Гипертекстовая связь активизируется, когда 
пользователь выполняет щелчок на горячем слове, связанном с командой \v. 

    438 MFC: основы программирования 


    Пример файла помощи 

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

    (\rtf4\ansi 
    (\fonttbl(\f0\fswiss Arial;) (\fl\fdecor Old English;)) 
    \fs40 
    \fl 
    @{\footnote This is a comment. So is the following.) 
    @{\footnote This is a Sample Help File.) 
    $(\footnote Contents) 
    Contents of Sample Help File 
    \f0 
    \fs20 
    \par 
    \par 
    
    \tab(\uldb Main Window \v MainWindow) 
    \par 
    
    \tab(\uldb Push Button 1 \v PushButtonI) 
    \par 
    
    \tab{\uldb Push Button 2 \v PushButton2) 
    \par 
    
    \tab(\uldb Push Button 3 \v PushButton3) 
    \par 
    
    \tab{\uldb List Box \v ListBox) 
    \par 
    
    \tab{\uldb Check Box \v CheckBox) 
    \par 
    \par 
    \fl 
    \fs30 
    
    Select a Topic. 
    \fs20 
    \f0 
    \page 
    
    #{\footnote PushButtonI} 
    $(\footnote Push Button 1) 
    K(\footnote Push Button 1) 
    +(\footnote Push:A) 
    {\fs24\b Push Button One) 
    \par 
    \par 
    This is help for the first push button. 
    \par 
    \par 
    See also (\uldb Push Button 2 \v PushButton2) 
    \page 
    #(\footnote IDH_PB1) 
    This is the popup for the first push button. 


    16. Система помощи                                             439 


    \paqe 
    #(\footnote PushButton2) 
    $(\footnote Push Button 2) 
    K{\footnote Push Button 2} 
    +(\footnote Push:B) 
    (\fs24\b Push Button Two) 
    \par 
    \par 
    This is help for the second push button. 
    \par 
    \par 
    See also {\uldb Push Button 3 \v PushButton3) 
    \page 
    #(\footnote IDH_PB2) 
    This is the popup for the second push button. 
    \page 
    #(\footnote PushButton3} 
    ${\footnote Push Button 3} 
    K(\footnote Push Button 31 
    +{\footnote Push:C} 
    (\fs24\b Push Button Three) 
    \par 
    \par 
    This is help for the third push button. 
    \par 
    \par 
    See also (\uldb Push Button 1 \v PushButtonI) 
    \page 
    #(\footnote IDH_PB3) 
    This is the popup for the third push button. 
    \page 
    #(\footnote MainWindow) 
    $(\footnote Main Window) 
    Kf\footnote Main Window) 
    (\fs24\b Main Window) 
    \par 
    \par 
    This is the main program window. 
    \page 
    #(\footnote IDHJY1AIN) 
    This is the Main Window popup help message. 
    \page 
    
    #(\footnote IDH_DLG) 
    This is a dialog box. 
    \page 
    
    #l\footnote ListBox) 
    $(\footnote List Box) 
    K(\footnote List Box) 
    +(\footnote Box:A) 
    (\fs24\b List Box) 
    \par 
    \par 


    440                                    MFC: основы программирования 


    This is help for the list box. 
    \page 
    #<\footnote IDH_LB1) 
    This is the popup for the list box. 
    \page 
    #{\footnote CheckBox) 
    ${\footnote Check Box) 
    K(\footnote Check Box) 
    +{\footnote Box:B) 
    (\fs24\b Check Box) 
    \par 
    \par 
    This is help for the check boxes. 
    \page 
    #(\footnote IDH_CB1) 
    This is the popup for the check boxes. 
    \page 
    } 

    В этом файле команды #\footnote, чьи идентификаторы имеют префикс IDH, 
являются точками входа в разделы, связанные с контекстной помощью. Остальные 
команды #\footnote определяют гипертекстовые связи, используемые для поддержки 
системы справочной помощи в стандартном окне помощи. 
    Данный файл должен быть откомпилирован с помощью компилятора файлов 
помощи. Но перед этим необходимо в конфигурационном разделе файла проекта 
объявить следующую таблицу (табл. 16.3): 

    Таблица 16.3. Контекстные идентификаторы 

    ЮН_РВ1           700 
    IDH_PB2           701______ 
    1DH_PB3__________702______ 
    JDH_LB1           "703 
    TDHLCBI________~704______ 
    IDH_MAIN         705 
    ~Ю H_DLGУбб 

    Данные константы будут использованы в программе для вызова контекстной помощи. 
    Легче всего определить эти константы путем включения в файл помощи 
табличного файла (map file). Для привязки числовых значений к константам в 
таких файлах используется следующий формат записи: 

    Идентификатор!    Значение! 
    Идентификатор2    Значение2 
    ИдентификаторЗ    ЗначениеЗ 
    Идентификатор^   Значением 


    16. Система помощи                                              441 

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

    IDH_PB1   700 
    IDH_PB2   701 
    IDH_PB3   702 
    IDH_LB1   703 
    IDH_CB1   704 
    IDHJ4AIN 705 
    IDH_DLG   706 

    Необходимо также активизировать кнопки просмотра в стандартном окне помощи 
путем включения команды BrowseButtonsQ в конфигурационный раздел файла 
проекта. И наконец, чтобы определить заголовок окна помощи, нужно задать его в 
диалоговом окне Options компилятора файлов помощи. Если этого не сделать, 
будет использован стандартный заголовок. В следующем примере в качестве 
заголовка используется строка "Sample Help File". 
    При компиляции данного файла назовите выходной файл HELPTEST.HLP. Он 
должен находиться в той же директории, что и исполняемый файл программы, текст 
которой приведен в конце главы. 

    Несколько слов о контекстных идентификаторах 

    Необходимо также вкратце упомянуть о так называемых контекстных 
идентификаторах, связанных с системой контекстной помощи. Как упоминалось в 
предыдущем параграфе, контекстный идентификатор связан с определенной частью 
файла помощи. Такие идентификаторы могут быть определены для различных 
элементов интерфейса Windows, включая меню, диалоговые окна и обычные окна. 
Они похожи на идентификаторы элементов управления или элементов меню и 
используются для определения элементов, связанных с системой помощи. 
    В MFC определено несколько стандартных диапазонов для контекстных 
идентификаторов. Например, значения идентификаторов в диапазоне от 0х10000 
(65536) до OxIFFFF (131071) зарезервированы для меню и кнопок. Значения в 
диапазоне от 0х20000 (131072) до Ox2FFFF (196607) зарезервированы для 
стандартных и диалоговых окон. Значения в диапазоне от 0 до OxFFFF (65535) 
зарезервированы для идентификаторов, определяемых пользователем. Стандартные 
диапазоны идентификаторов используются в тех случаях, когда программа не берет 
на себя полный контроль над системой помощи, а полагается на действия, 
предусмотренные по умолчанию. Однако, с практической точки зрения, это 
делается очень редко, ведь пользователь привык ожидать чего-то большего, чем 
просто стандартные операции. Поэтому в примере данной главы определяются 
собственные контекстные идентификаторы. 

    442                                    MFC: основы программирования 


    Включение системы помощи в MFC-программу 

    Систему помощи довольно легко включить в MFC-программу. Общая процедура такова: 
    1. Добавить обработчики сообщений помощи в очередь сообщений приложения. 
    2. Определить обработчики сообщений WM_CONTEXTMENU и WM_HELPINFO. 
    3. При необходимости, определить обработчики сообщения WM_HELPCOMMAND. 
    4. Включить пункт меню Help в главное меню приложения. 
    5. При необходимости, вызвать функцию WinHelpO. 
    В последующих параграфах рассматривается каждый из перечисленных пунктов. 
Начнем с функции WinHelpO, поскольку она является ядром системы помощи. 

    Использование API-функции WinHelpO 

    К моменту написания данной книги еще остались некоторые ситуации (особенно 
в случае со всплывающими контекстными подсказками), когда проще использовать 
API-функцию WinHelpO, а не ее MFC-эквивалент. Дело в том, что соответствующая 
API-функция позволяет немного точнее управлять способом вызова системы помощи. 
Прототип этой функции таков: 

    BOOL WinHelp(HWND hwnd, LPCSTR IpszFilename, UINT Command, DWORD dwinfo); 

    Здесь параметр hwnd является дескриптором окна, из которого была вызвана 
помощь. Получить такой дескриптор легко: он содержится в переменной m_hWnd 
класса CWnd. 
    Имя вызываемого файла помощи указывается в параметре Ips^Filename и может 
включать также имя логического диска и путь к файлу. Эти значения также 
довольно легко получить. После запуска MFC-программы путь и имя файла помощи, 
связанного с приложением, будут находиться в переменной m_pszHelpFilePath 
класса CWinApp. По умолчанию это будет имя приложения, за которым следует 
расширение HLP. Однако эти значения, при желании, можно изменять и явно 
указывать имя файла помощи. 
    Точное действие, выполняемое функцией WinHelpO, определяется параметром 
Command. Значения этого параметра приведены в табл. 16.4: 

    Таблица 16.4. Значения параметра Command 

    Константа               Действие функции 

    HELP_COMMAND       Выполняет макрокоманду 
    HELP_CONTENTS       Больше не используется (заменена на HELP_FINDER) 
    HELP_CONTEXT        Отображает указанный раздел 
    HELP_CONTEXTMENU   Отображает окно контекстной помощи 


    16. Система помощи 443 


    Константа               Действие функции 

    HELP_CONTEXTPOPUP   Отображает окно контекстной помощи 
    HELP_FINDER          Отображает стандартное окно Help Topics 
    HELP_FORCEF1LE       Отображает файл помощи 
    HELP_HELPONHELP     Отображает справочную информацию о системе помощи 
    HELP_INDEX           Больше не используется (заменена на HELP_FINDER) 
    HELP_KEY              Отображает раздел, определяемый его ключевым словом 
    HELP_ML)LTIKEY        Отображает раздел, определяемый его альтернативным 
ключевым словом 
    HELP_PARTIALKEY      Отображает раздел, определяемый его вторичным 
ключевым словом 
    HELP_QUIT            Закрывает окно помощи 
    HELP_SETCONTENTS    Задает содержимое раздела 
    HELP_SETINDEX        Устанавливает вторичный индекс ключевого слова 
    HELP_SETPOPUP_POS    Определяет позицию окна следующей всплывающей 
подсказки, которая будет отображена системой помощи 
    HELP_SETWINPOS       Определяет размеры и позицию окна помощи и при 
необходимости отображает его 
    HELP_TCARD            Эта команда объединяется операцией побитового ИЛИ с 
другими командами и предназначена для отображения обучающей карточки 
    HELP_WM_HBLP        Отображает контекстную всплывающую подсказку 
    Для некоторых из перечисленных команд требуется вспомогательная 
информация. В этом случае она передается в параметре dwinfo. Значения этого 
параметра для каждой из команд приведены в табл. 16.5: 

    Таблица 16.5. Значения параметра dwfnfo 

    Параметр Command      Значение параметра dwinfo 

    HELP_COMMAND        Указатель на строку, содержащую макрокоманду 
    HELP_CONTE1MTS        He используется (устанавливается в 0) 
    HELP_CONTEXT         Контекстный идентификатор раздела 
    HELP_CONTEXTMENU   Смотри текст после таблицы 
    HELP_CONTEXTPOPUP   Контекстный идентификатор раздела 
    HELP_FINDER           Не используется (устанавливается в 0) 
    HELP_FORCEFILE        Не используется (устанавливается в 0) 
    HELP_HELPONHELP     Не используется (устанавливается в 0) 
    HELP_INDEX            Не используется (устанавливается в 0) 


    444                                    MFC: основы программирования 


    Параметр Command      Значение параметра dwinfo 

    HELP_KEY              Указатель на строку, содержащую ключевое слово 
    HELP_MULTIKEY        Указатель на структуру типа MULTIKEYHELP 
    HELP_PARTIALKEY      Указатель на строку, содержащую вторичное ключевое слово 
    HELP_QU1T             He используется (устанавливается в 0) 
    HELP_SETCONTENTS     Контекстный идентификатор раздела 
    HELP_SETINDEX        Контекстный идентификатор для индекса 
    HELP_SETPOPUP_POS    Указатель на структуру типа POINTS 
    HELP_SETWINPOS       Указатель на структуру типа HELPWININFO 
    HELP_WM_HELP         Смотри текст после таблицы 

    Для команд HELP_WM_HELP и HELP_CONTEXTMENU смысл параметра dwinfo чуть 
более сложен, чем у других команд. Здесь параметр dwinfo является указателем 
на массив значений типа DWORD. Все элементы массива разбиты на пары. Первое 
значение пары является идентификатором элемента управления (например кнопки, 
поля ввода и т.п.), а второе значение является контекстным идентификатором 
раздела файла помощи, связанного с этим элементом. Массив должен заканчиваться 
двумя нулями. Обе эти команды предназначены для поддержки контекстной помощи и 
обработки сообщений WM_COMMANDHELP, WM_HELPINFO и WM_CONTEXTMENU, которые 
будут описаны позднее. 

    Использование функции CWinApp::WinHelp() 

    В большинстве случаев вместо API-фукции WinHelpO используется 
эквивалентная ей функция, содержащаяся в классе CWinApp. Ее прототип таков: 

    virtual void CWinApp::WinHelp(DWORD dwinfo, 
    UINT Cominand=HELP__CONTEXT) ; 

    Здесь параметры dwinfo и Command имеют те же значения, что и в 
API-варианте функции WinHelpO, описанном ранее. 
    Данная функция автоматически находит файл помощи, определяемый переменной m_pszHelpFilePath. 

    Обработчики сообщений помощи 

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

    ON_COMMAND(ID_HELP, OnHelp) 
    ON_COMMAND(ID_HELP_FINDER, OnHelpFinder) 
    ON_COMMAND(ID_HELP_INDEX, OnHelpIndex) 
    ON_COMMAND(ID_HELP_USING, OnHelpUsing) 
    В некоторых ситуациях может также понадобиться команда 
    ON_COMMAND(ID_CONTEXT_HELP, OnContextHelp) 


    16. Система помощи                                               445 

    Функции OnHelpQ, OnHelpFinder(), OnHelpIndex(), OnHelpUsingO и 
OnContextHelpO являются членами класса CWinApp. При вызове они, в свою 
очередь, вызывают функцию WinHelpO. Это осуществляется следующим образом 
(табл. 16.6): 

    Таблица 16.6. Вызов функции WinHelpO обработчиками сообщении помощи 

    Функция                   Действие 

    CWinApp::OnHelp()            Вызывает срункцию WinHelpO, основываясь на 
текущем контексте помощи. 
    CWinApp::OnHelpFinder()       Вызывает функцию WinHelpO с параметром HELP_FINDER. 
    CWinApp::OnHelpIndex()        Вызывает функцию WinHelpO с параметром HELPJNDEX. 
    CWinApp::OnHelpUsingO       Вызывает функцию WinHelpO с параметром HELP_HELPONHELP. 
    CWinApp::OnContextHelp()      Вызывает функцию WinHelpO, основываясь на 
текущем контексте помощи. Курсор мыши принимает форму вопросительного знака. 
Контекст помощи определяется элементом, на который указывает курсор. 

    Идентификаторы для данных обработчиков определены в MFC. Это стандартные 
значения, которыми пользуется большинство программистов, хотя здесь можно 
указывать произвольные идентификаторы. 
    В программе не требуется выполнять вызовы этих функций. Размещение их 
макрокоманд в очереди сообщений позволяет MFC самостоятельно вызывать эти 
функции в случае необходимости. Более того, для большинства приложений вполне 
достаточно тех версий обработчиков OnHelpFinderQ, OnHelpIndexQ и OnHelpUsingO, 
которые определены в MFC. Однако для более точного управления системой помощи 
часто требуется переопределять функции OnHelpO и OnContextHelpO. 
    Поскольку все эти функции являются членами класса CWinApp, лучше всего 
размещать их макрокоманды в очереди сообщений, которая относится к классу, 
определяющему приложение, так как он порождается непосредственно от CWinApp. 
Нив одном из примеров книги не создавалась очередь сообщений для данного 
класса, поскольку в этом не было необходимости. Но при работе с системой 
помощи такая очередь будет создана. 

    Обработка вызовов помощи 

    Как уже упоминалось в начале главы, есть два основных типа помощи: 
справочная и контекстная. В корректно написанном Windows-приложении 
пользователь может вызвать справочную помощь (т.е. стандартное окно помощи) 
через меню Help или (в некоторых случаях) с помощью клавиши [F1]. Контекстная 
помощь вызывается либо при щелчке правой кнопки мыши на элементе управления 
или окне, либо с помощью кнопки "?", либо также с помощью клавиши [F1 ]. 
(Различие между двумя способами использования клавиши [F1] будет объяснено ниже.) 

    446                                    MFC: основы программирования 

    Поскольку на различные типы вызовов помощи программа должна реагировать 
по-разному, должен существовать какой-то способ различать их. И такой способ 
есть. При нажатии клавиши [F1] или кнопки "?" активному окну посылаются два 
сообщения: WM_COMMANDHELP и WM_HELPINFO. А когда пользователь выполняет щелчок 
правой кнопки мыши на окне или на содержащемся в нем элементе управления, то 
данному окну посылается сообщение WM_CONTEXTMENU. От правильной обработки этих 
трех сообщений зависит корректная реализация всей интерактивной помощи. В 
последующих параграфах будет описано каждое из этих сообщений. 

    Обработка сообщения WM_COMMANDHELP 

    Поскольку MFC выполняет лишь самые необходимые действия по обработке 
вызовов помощи, в некоторых случаях приходится создавать собственный 
обработчик сообщения WM_COMMANDHELP. Это сообщение определено в MFC как 
закрытое. Чтобы получить к нему доступ, нужно выполнить несколько действий. 
Во-первых, требуется включить в программу стандартные библиотечные файлы 
AFXPRIV.H и AFXEXT.H. Затем в очередь сообщений каждого окна, для которого 
осуществляется обработка данного сообщения, должна быть включена макрокоманда 

    ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp) 

    И наконец, необходимо переопределить функцию OnCommandHelpO, которая имеет 
следующий прототип: 

    afx msg LRESULT CWnd::OnCommandHelp(WPARAM wParam, LPARAM 1 Par am}; 

    Параметр wParam в данном случае не используется. В параметре IParam 
содержится текущий контекстный идентификатор. Функция должна вернуть ненулевое 
значение, чтобы остановить дальнейшую обработку сообщения WM_COMMANDHELP. Т.е. 
если сообщение с таким идентификатором адресовано именно этой функции, то она 
должна вернуть ненулевое значение. Если же она возвращает 0, то сообщение 
будет передано окну более высокого уровня. 
    Как будет показано, реализация собственного обработчика OnCommandHelpO 
позволяет более точно управлять системой контекстной помощи. 

    Обработка сообщения WM.CONTEXTMENU 

    Каждый раз, когда пользователь выполняет щелчок правой кнопки мыши, 
программе посылается сообщение WM_CONTEXTMENU. Обработчик этого сообщения 
называется OnContextMenu(), и его прототип таков: 

    afx_msg void CWnd::OnContextMenu(CWnd *0wner, CPoint Loc); 

    Здесь параметр Owner является указателем на объект окна, в котором 
произошел щелчок мыши. В параметре Loc содержатся координаты курсора мыши в 
момент щелчка. Для обработки сообщения WM_CONTEXTMENU необходимо вызывать 
функцию ::WinHelp(), где в качестве первого параметра должна быть передана 
переменная m_hWnd, содержащая дескриптор того объекта, на который указывает 
параметр Owner. Кроме того, в третьем параметре функции ::WinHelp() должно быть 

    16. Система помощи 447 

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

    Примечание: Сообщение WM_CONTEXTMENU не поддерживается в Windows 3.1. 


    Обработка Сообщения WM_HELPINFO 

    Каждый раз, когда пользователь нажимает клавишу [F1] или кнопку "?", 
программе посылается сообщение WM_HELPINFO. Оно обрабатывается с помощью 
функции OnHelpInfoO, которая имеет такой прототип: 

    afx_msg BOOL CWnd::OnHelpInfo(HELPINFO *HelpInfo); 

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

    Тип HELPINFO определен следующим образом: 
    typedef struct tagHELPINFO 
    ( 
    UINT cbSize; 
    int iContextType; 
    int iCtrlId; 
    HANDLE hItemHandle; 
    DWORD dwContextId; 
    POINT MousePos; 
    } HELPINFO; 

    В поле cbSize содержится размер структуры. 
    Поле iContextType определяет тип объекта, для которого вызывается помощь. 
Если таковым является элемент меню, то в данном поле будет содержаться 
значение HELPINFO_MENUITEM. Если же это окно или элемент управления, то в 
данном поле будет содержаться значение HELPINFO_WINDOW. В поле iCtrlId 
содержится идентификатор элемента управления, окна или элемента меню. 
    Поле hItemHandle хранит дескриптор элемента управления, окна или меню. 
Поле dwContextId содержит контекстный идентификатор, связанный с окном или 
элементом управления. В поле MousePos содержатся текущие координаты курсора мыши. 
    Если в программе переопределяется обработчик OnHelpInfoO, то одним из 
действий, которые им выполняются, обычно является отображение всплывающего 
окна, содержащего контекстную подсказку. Для этого необходимо вызвать функцию 
::WinHelp(), которой в качестве дескриптора окна (т.е. первым параметром) 
нужно передать значение поля hItemHandle. Кроме того, в третьем параметре 
функции должно быть указано значение HELP_WM_HELP и, соответственно, ей должен 
быть передан адрес массива идентификаторов. В этом случае функция ::WinHelp() 
будет искать в массиве идентификатор того элемента, дескриптор которого 
содержится в поле hItemHandle. После этого функция использует соответствующий 
контекстный идентификатор для вызова контекстной подсказки, которая 
отображается во всплывающем окне. Стандартное окно помощи при этом не вызывается. 

    448                                    MFC: основы программирования 

    Хотя, как правило, программа реагирует на сообщение WM_HELPINFO путем 
отображения контекстной подсказки, это происходит не всегда. Как уже 
говорилось, при нажатии клавиши [F1] может быть вызвана либо справочная 
помощь, либо контекстная подсказка. Различие между двумя вызовами таково: 
когда главное окно имеет фокус ввода (и ни одно из порожденных окон или меню 
неактивно), то при нажатии [F1] на экране отображается стандартное окно 
помощи. Если же какой-либо элемент управления, меню или диалоговое окно были 
активны, то вызывается контекстная подсказка. За всем этим стоит следующая 
концепция: считается, что если пользователь нажимает [F1] в окне верхнего 
уровня, то он хочет получить ин4)ормацию о всей программе, а не о ее части. В 
этом случае необходимо вызывать всю систему помощи. Если же при нажатии [F1] 
активен какой-то элемент управления (или диалоговое окно), значит пользователь 
желает узнать о конкретном элементе, и ему предоставляется контекстная подсказка. 
    Вам, наверное, интересно, каким образом программа различает два этих 
запроса. Ведь при нажатии клавиши [F1], независимо от типа запроса, 
генерируется одно и то же сообщение WM_HELPINFO. Ответ довольно прост: если 
дескриптор элемента, содержащийся в поле hItemHandle, относится к главному 
окну, то вызывается справочная помощь; в противном случае отображается 
контекстная подсказка. 

    Включение меню Help 

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

    Включение кнопки "У 

    Один из способов вызова контекстной подсказки заключается в использовании 
кнопки "?". Чтобы отобразить эту кнопку, необходимо при создании окна указать 
константу расширенного стиля WS_EX_CONTEXTHELP. В этом случае окно должно быть 
создано с помощью функции CreateExQ, а не CreateQ. Если кнопку "?" необходимо 
отобразить в диалоговом окне, то при его описании необходимо указать стиль DS_CONTEXTHELP. 

    16. Система помощи                                               449 


    Демонстрационная программа 

    Когда вся методика создания интерактивной помощи известна, пора приступить 
к ее практической реализации. В следующей программе демонстрируется 
использование как справочной помощи, так и контекстных подсказок. В программе 
используется созданный ранее файл помощи. В ней также демонстрируются 
различные варианты вызова этого файла как через функцию ::WinHelp(), так и 
через функцию CWinApp::WinHelp(). В меню Help программы реализованы все 
необходимые команды, позволяющие пользователю просмотреть содержимое файла 
помощи, список индексов файла, а также информацию о самой системе помощи. В 
программе также создано окно About. Пример работы программы показан на рис. 16.3. 
    Ниже приведен текст файла ресурсов программы. Заметьте, что в нем 
используется расширенный вариант оператора DIALOG — DIALOGEX. Он позволяет 
указывать в описании диалогового окна спецификатор контекстной помощи (DS_CONTEXTHELP). 

    ; HELPTEST.RC 
    ; Демонстрация работы с системой помощи 
    #include <afxres.h> 
    #include "ids.h" 
    HelpMenu MENU 
    { 
    POPUP "SDialog" 
    ( 
    MENUITEM "&Dialog\tF2", IDM_DIALOG 
    MENUITEM "E&xit\tF3", IDM_EXIT 
    1 
    POPUP "SHelp" 
    ( 
    MENUITEM "SHelp Topics\tF4", IDM_HELP_INDEX 
    MENUITEM "SUsing Help\tF5", IDM_HELP_USING 
    MENUITEM "SHelp Finder\tF6", IDM_HELP_FINDER 
    MENUITEM "&About\tF7", IDM_ABOUTTHIS 
    } 
    } 
    HelpTest MENU 
    ( 
    MENUITEM "SDialog", IDM_DIALOG 
    MENUITEM "SExit", IDM_EXIT 
    } 
    
    HelpMenu ACCELERATORS 
    { 
    VK_F1, IDM_HELP, VIRTKEY 
    VK_F2, IDM_DIALOG, VIRTKEY 
    VK_F3, IDM_EXIT, VIRTKEY 
    VK_F4, IDM_HELP_INDEX, VIRTKEY 
    VK_F5, IDM_HELP_USING, VIRTKEY 


    450                                     MFC: основы программирования 


    VK_F6, IDM_HELP_FINDER, VIRTKEY 
    VK_F7, IDM_ABOUTTHIS, VIRTKEY 
    ) 
    HelpDialog DIALOGEX 10, 10, 142, 110, IDH_DLG 
    CAPTION "Help Demonstration Dialog" 
    STYLE WS_POPUP | WS_SYSMENU | WS_VISIBLE | DS_CONTEXTHELP 
    ( 
    DEFPUSHBUTTON "Button I", IDD_PB1, 11, 10, 32, 14, 
    
    WS_CHILD I WS_VISIBLE | WS_TABSTOP 
    PUSHBUTTON "Button 2", IDD_PB2, 11, 34, 32, 14, 
    
    WS_CHILD | WS_VISIBLE I WS_TABSTOP 
    PUSHBUTTON "Button 3", IDD_PB3, 11, 58, 32, 14, 
    
    WS_CHILD | WS_VISIBLE I WS_TABSTOP 
    PUSHBUTTON "Cancel", IDCANCEL, 8, 82, 38, 16, 
    
    WS_CHILD I WS_VISIBLE I WS_TABSTOP 
    AUTOCHECKBOX "Checkbox I", IDD_CB1, 66, 50, 60, 30, 
    
    WS_CHILD | WS_VISIBLE I WS_TABSTOP 
    AUTOCHECKBOX "Checkbox 2", IDD_CB2, 66, 70, 60, 30, 
    
    WS_CHILD I WS_VISIBLE I WS_TABSTOP 
    LISTBOX IDD_LB1, 66, 5, 63, 33, LBS_NOTIFY I 
    WS_VISIBLE | WS_BORDER I WSJ/SCROLL I WS_TABSTOP 
    ) 

    Вот текст библиотечного файла IDS.H: 

    // IDS.H 
    #define IDM_DIALOG     100 
    ftdefine IDM_EXIT       101 
    #define IDM_ABOUTTHIS  102 
    #define IDD_PB1        200 
    #define IDD_PB2        201 
    ^define IDD_PB3        202 
    #define IDD_LB1        203 
    #define IDD_CB1        205 
    #define IDD_CB2        206 
    #define IDH_PB1        700 
    #define IDH_PB2        701 
    #define IDH_PB3        702 
    #define IDH_LB1        703 
    #define IDH_CB1        704 
    #define IDH_MAIN       705 
    #define IDH_DLG        706 


    16. Система помощи                                               451 

    Это текст 4)айла HELPTEST.H, содержащего объявления порождаемых классов: 

    // HELPTEST.H 
    
    // Это класс для создания главного окна 
    class CMainWin : public CFrameWnd 
    { 
    public: 
    CMainWin () ; 
    afx_msg LRESULT OnCommandHelp(WPARAM, LPARAM); 
    
    // объявления обработчиков меню 
    afx msg void OnDialogO; 
    afx msg void OnExitO; 
    afx_msg void OnAboutThis (); 
    DECLARE_MESSAGE_MAP() 
    ); 
    
    // Это класс для создания приложения 
    class CApp : public CWinApp 
    ( 
    public: 
    BOOL Initlnstance (); 
    DECLARE_MESSAGE_MAP() 
    ); 
    
    // Это класс для создания диалогового окна 
    class CSampleDialog : public CDialog 
    ( 
    public: 
    CSampleDialog(char *DialogName, CWnd *0wner) : 
    CDialog(DialogName, Owner) () 
    BOOL OnInitDialog() ; 
    afx_msg BOOL OnHelpInfo(HELPINFO *p) ; 
    afx_msg LRESULT OnCommandHelp(WPARAM, LPARAM); 
    afx msg void OnContextMenu(CWnd *0wner, CPoint Loc) ; 
    DECLARE_MESSAGE_MAP() 
    }; 

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

    452                                     MFC: основы программирования 


    // Демонстрация работы с системой помощи. 
    // Назовите этот файл HELPTEST.CPP 
    #include <afxwin.h> 
    #include <afxext.h> 
    #include <afxpriv.h> 
    tinclude <strinq.h> 
    #include "helptest.h" 
    #include "ids.h" 
    DWORD HelpArray[] = { 
    IDD_PB1, IDH_PB1, 
    IDD_PB2, IDH_PB2, 
    IDD_PB3, IDH_PB3, 
    IDD_LB1, IDH_LB1, 
    IDD CB1, IDH CB1, // обоим контрольным переключателям 
    IDD CB2, IDH CB1, // соответствует один и тот же // контекстный идентификатор 
    О, О 
    1; 
    САрр Арр; // создание экземпляра приложения 
    CMainWin::CMainWin() ( 
    
    Create(NULL, "Demonstrate the Help System", WS_OVERLAPPEDWINDOW, 
rectDefault, NULL, "HelpMenu") ; 
    
    // Загрузка таблицы быстрого доступа 
    if('LoadAccelTable("HelpMenu")) 
    MessageBox("Cannot Load Accelerators", "Error"); 
    } 
    
    // Инициализация приложения 
    BOOL САрр::Initlnstance() 
    ( 
    m_pMainWnd = new CMainWin; 
    m_pMainWnd->ShowWindow(m_nCmdShow) ; 
    m_pMainWnd->UpdateWindow() ; 
    return TRUE; 
    ) 
    
    // Это очередь сообщений главного окна 
    BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd) 
    ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp) 
    ON_COMMAND(IDM_DIALOG, OnDialoq) 
    ON_COMMAND(IDM_EXIT, OnExit) 


    16. Система помощи                                               453 


    ON_COMMAND(IDM_ABOUTTHIS, OnAboutThis) 
    END_MESSAGE_MAP() 
    
    // Это очередь сообщений приложения 
    BEGIN_MESSAGE_MAP(CApp, CWinApp) 
    ON_COMMAND(ID_HELP, OnHelp) 
    ON_COMMAND(ID_HELP_FINDER, OnHelpFinder) 
    ON_COMMAND(ID_HELP_INDEX, OnHelpIndex) 
    
    ON_COMMAND(ID_HELP_USING, OnHelpUsing) 
    END_MESSAGE_MAP() 
    
    // Обработка сообщения IDM_DIALOG 
    afx msg void CMainWin::OnDialog() 
    ( 
    CSampleDialog diagOb ("HelpDialog", this); 
    diagOb.DoModal(); // активизирует модальное диалоговое окно 
    
    // Обработка сообщения IDM EXIT 
    afx msg void CMainWin::OnExit () 
    ( 
    int response; 
    response = MessageBox ("Quit the Program?", "Exit", MB_YESNO) ; 
    if(response == IDYES) 
    SendMessage(WM_CLOSE); // завершение приложения 
    } 
    
    // Обработка сообщения IDM_ABOUTTHIS 
    afx msg void CMainWin::OnAboutThis() 
    { 
    MessageBox("Help System Demo VI.O", "About"); 
    } 
    
    // Это очередь сообщений диалогового окна 
    BEGIN_MESSAGE_MAP(CSampleDialog, CDialog) 
    ON_WM_CONTEXTMENU() 
    
    ON_WM_HELPINFO() 
    END_MESSAGE_MAP() 
    
    // Инициализация диалогового окна 
    BOOL CSampleDialog::OnInitDialog() 
    { 
    CDialog::OnInitDialogО; // Вызов функции базового класса 
    CListBox *lbptr = (CListBox *) GetDlgItem(IDD_LB1) ; 


    454                                    MFC: основы программирования 


    // инициализация списка lbptr->AddString("One") ; 
    lbptr->AddString("Two") ; 
    lbptr->AddString("Three") ; 
    lbptr->AddString("Four") ; 
    lbptr->AddString("Five") ; 
    lbptr->Add3tring("Six") ; 
    return TRUE; 
    // Обработка вызова контекстной помощи для диалогового окна 
    afx msg void CSampleDialog::OnContextMenu(CWnd *0wner, CPoint Loc) 
    ( 
    
    ::WinHelp(Owner->m_hWnd, App.m_pszHelpFilePath, 
    HELP_CONTEXTMENU, (DWORD)HelpArray) ; 
    } 
    // Обработка нажатия клавиши [Fl] или кнопки "?" в диалоговом окне 
    afx_msg BOOL CSampleDialog::OnHelpInfо(HELPINFO *ObPtr) 
    ( 
    
    // если пользователь выполняет щелчок на диалоговом окне 
    if((HWND) ObPtr->hItemHandle == m_hWnd) 
    
    ::WinHelp((HMND) ObPtr->hItemHandle, App.m_pszHelpFilePath, 
    HELP_CONTEXTPOPUP, IDH_DLG) ; 
    else // если пользователь выполняет щелчок 
    // на элементе управления 
    
    ::WinHelp((HWND) ObPtr->hItemHandle, App.m_pszHelpFilePath, 
    HELP_WM_HELP, (DWORD) HelpArray) ; 
    return 1; 
    \ 
    
    // Обработка нажатия клавиши [Fl] в главном окне 
    afx_msg LRESULT CMainWindow::OnCommandHelp(WPARAM wParam, 
    LPARAM IParam) 
    ( 
    App.WinHelp((DWORD) "Main Window", HELP_KEY) ; 
    return 1; 
    } 


    16. Система помощи                                               455 


    11 Л Sample Help File ' 
    File, Edit Bookmark Qptions H.elp 
    UPtente	„jndgx: 1 Beck j Pnnt 
    i Contents of Sample Help FileMain Window 
    Pu?h...But.ton..l. Push .Button 2 Push Button3 
    List Вт 
    Check Bi:ix 
    Select a Topic. 
    \Л Sample Help File 
    |J|e Edit Bookmark Options Help 
    , igontents	Index	Sack	Print | ^<	У 
    Push Button TwoThis is help for the second push button. See also Push 
Button 3 

    Рис. 16.3. Пример работы демонстрационной программы 


    456 MFC: основы программирования 


    В Demonstrate the Help System 

    Рис. 16.3. Пример работы демонстрационной программы (продолжение) 


    16. Система помощи  457 


    Подробнее о работе программы 

    Большая часть программы должна быть вам понятна. Однако о некоторых ее 
моментах нужно все же упомянуть. Во-первых, обратите внимание на объявление 
массива HelpArray. В этом массиве устанавливается соответствие между 
идентификаторами элементов управления и контекстными идентификаторами. В файле 
IDS. И константам с префиксом IDH присвоены те же значения, которые были 
определены в файле HELPTEST.PRJ при создании файла помоши. Заметьте, что с 
обоими контрольными переключателями связан один и тот же контекстный 
идентификатор. Это вполне допускается. Если одна контекстная подсказка будет 
отображена для двух или более элементов, то нет и необходимости дублировать ее. 
    Вторым интересным моментом программы является то, каким образом в функции 
OnHelpInfo() обрабатываются вызовы помощи. Если дескриптор объекта 
соответствует диалоговому окну, то отображается контекстная подсказка, 
относящаяся к этому окну. В противном случае вызывается функция ::WinHelp(), 
которой в качестве параметра передается опция HELP_WM_HELP. При этом 
отображается контекстная подсказка, относящаяся к выбранному элементу. 
    В-третьих, обратите внимание на то, как функция CWinApp::WinHelp() 
вызывается для главного окна программы. Здесь используется механизм поиска 
ключевых слов для нахождения информации о главном окне. Попробуйте задать 
другие опции функции WinHelpO и оцените результат. 

    С чем стоит поэкспериментировать? 

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

    458                                    MFC: основы программирования