TN028: suporte à ajuda contextual

Esta nota descreve as regras para atribuir IDs de contextos de ajuda e outros problemas de ajuda no MFC. O suporte à ajuda contextual requer o compilador de ajuda disponível no Visual C++.

Observação

Além de implementar a ajuda contextual usando o WinHelp, o MFC também dá suporte ao uso da ajuda HTML. Para saber mais sobre esse suporte e a programação com a ajuda HTML, confira Ajuda HTML: ajuda contextual para seus programas.

Tipos de ajuda com suporte

Há dois tipos de ajuda contextual implementados em aplicativos do Windows. A primeira, conhecida como "Ajuda F1", envolve a inicialização do WinHelp com o contexto apropriado baseando-se no objeto ativo atualmente. A segundo é o modo "Shift + F1". Nesse modo, o cursor do mouse muda para o cursor de ajuda e o usuário clica em um objeto. Nesse momento, o WinHelp é iniciado para fornecer ajuda com relação ao objeto em que o usuário clicou.

O Microsoft Foundation Classes implementa ambas as formas de ajuda. Além disso, a estrutura dá suporte a dois comandos de ajuda simples: Índice de Ajuda e Ajuda de Uso.

Arquivos de Ajuda

O Microsoft Foundation Classes assume um único arquivo de ajuda. Esse arquivo de ajuda deve ter o mesmo nome e caminho que o aplicativo. Por exemplo, se o executável for C:\MyApplication\MyHelp.exe, o arquivo de ajuda deverá ser C:\MyApplication\MyHelp.hlp. Você define o caminho por meio da variável de membro m_pszHelpFilePath da classe CWinApp.

Intervalos do contexto de ajuda

A implementação padrão do MFC requer que um programa siga algumas regras sobre a atribuição de IDs de contexto de ajuda. Essas regras são um intervalo de IDs alocadas a controles específicos. É possível substitui-las fornecendo implementações diferentes das várias funções de membro relacionadas à ajuda.

0x00000000 - 0x0000FFFF : user defined
0x00010000 - 0x0001FFFF : commands (menus/command buttons)
0x00010000 + ID_
(note: 0x18000-> 0x1FFFF is the practical range since command IDs are>=0x8000)
0x00020000 - 0x0002FFFF : windows and dialogs
0x00020000 + IDR_
(note: 0x20000-> 0x27FFF is the practical range since IDRs are <= 0x7FFF)
0x00030000 - 0x0003FFFF : error messages (based on error string ID)
0x00030000 + IDP_
0x00040000 - 0x0004FFFF : special purpose (non-client areas)
0x00040000 + HitTest area
0x00050000 - 0x0005FFFF : controls (those that are not commands)
0x00040000 + IDW_

Comandos simples de "ajuda"

Há dois comandos de ajuda simples que são implementados pelo Microsoft Foundation Classes:

O primeiro comando mostra o índice de ajuda do aplicativo. O segundo mostra a ajuda do usuário durante o uso do programa WinHelp.

Ajuda contextual (Ajuda F1)

A tecla F1 geralmente é movida para um comando com uma ID de ID_HELP por um acelerador colocado na tabela de aceleradores da janela principal. O comando ID_HELP também pode ser gerado por um botão com uma ID de ID_HELP na janela principal ou na caixa de diálogo.

Independentemente de como o comando ID_HELP é gerado, ele é roteado como um comando normal até chegar a um manipulador de comandos. Para saber mais sobre a arquitetura de roteamento de comando do MFC, confira a Nota técnica 21. Se o aplicativo tiver a ajuda habilitada, o comando ID_HELP será manipulado por CWinApp::OnHelp. O objeto de aplicativo recebe a mensagem de ajuda e, em seguida, roteia o comando adequadamente. Isso é necessário, pois o roteamento de comando padrão não é adequado para determinar contextos mais específicos.

CWinApp::OnHelp tenta iniciar o WinHelp na seguinte ordem:

  1. Verifica se há uma chamada AfxMessageBox ativa com uma ID de ajuda. Se uma caixa de mensagem estiver ativa no momento, o WinHelp será iniciado com o contexto apropriado para ela.

  2. Envia uma mensagem WM_COMMANDHELP à janela ativa. Se essa janela não responder inicializando o WinHelp, a mesma mensagem será enviada aos ancestrais dela até ser processada ou até a janela atual se transformar em uma janela de nível superior.

  3. Envia um comando ID_DEFAULT_HELP à janela principal. Isso invoca a ajuda padrão. Esse comando é geralmente mapeado para CWinApp::OnHelpIndex.

Para substituir globalmente os valores básicos de ID padrão (por exemplo, 0x10000 para comandos e 0x20000 para recursos como diálogos), o aplicativo deve substituir CWinApp::WinHelp.

Para substituir essa funcionalidade e a maneira como um contexto de ajuda é determinado, você deve lidar com a mensagem WM_COMMANDHELP. Recomenda-se fornecer um roteamento de ajuda mais específico do que o fornecido pela estrutura, que é tão profundo quanto a janela filho atual de MDI. Também é recomendado fornecer uma ajuda mais específica para uma determinada janela ou caixa de diálogo, talvez com base no estado interno atual desse objeto ou no controle ativo na caixa de diálogo.

WM_COMMANDHELP

afx_msg LRESULT CWnd::OnCommandHelp(WPARAM wParam, LPARAM lParam)

WM_COMMANDHELP é uma mensagem privada do Windows MFC recebida pela janela ativa quando a ajuda é solicitada. Quando a janela recebe essa mensagem, ela pode chamar CWinApp::WinHelp com um contexto que corresponda ao estado interno da janela.

lParam
Contém o contexto de ajuda disponível no momento. lParam será zero se nenhum contexto de ajuda for determinado. Uma implementação de OnCommandHelp pode usar a ID de contexto em lParam para determinar um contexto diferente ou simplesmente transmiti-la a CWinApp::WinHelp.

wParam
Não é usado e será zero.

Se a função OnCommandHelp chamar CWinApp::WinHelp, deverá ter como retorno TRUE. O retorno de TRUE interrompe o roteamento desse comando para outras classes e outras janelas.

Modo de ajuda (Ajuda Shift + F1)

Esta é a segunda forma de ajuda contextual. Geralmente, esse modo é inserido pressionando SHIFT + F1 ou por meio do menu/barra de ferramentas. Ele é implementado como um comando (ID_CONTEXT_HELP). O gancho do filtro de mensagens não é utilizado para mover esse comando enquanto uma caixa de diálogo ou um menu modal está ativo, portanto, este comando só está disponível para o usuário quando o aplicativo está executando a bomba de mensagens principal (CWinApp::Run).

Depois de entrar nesse modo, o cursor do mouse de ajuda é exibido sobre todas as áreas do aplicativo, mesmo que o aplicativo normalmente exiba o próprio cursor para essa área (como a borda de dimensionamento ao redor da janela). O usuário pode usar o mouse ou o teclado para selecionar um comando. Em vez de executar o comando, a ajuda nesse comando é exibida. Além disso, o usuário pode clicar em um objeto visível na tela, como um botão na barra de ferramentas, e a ajuda será exibida para ele. Esse modo de ajuda é fornecido por CWinApp::OnContextHelp.

Durante a execução desse loop, nenhuma tecla do teclado fica ativa, exceto as que acessam o menu. Além disso, a movimentação de comando ainda é realizada por meio de PreTranslateMessage para permitir que o usuário pressione uma tecla aceleradora e receba ajuda nesse comando.

Se houver movimentações ou ações específicas ocorrendo na função PreTranslateMessage que não devem ocorrer durante o modo de ajuda SHIFT + F1, verifique o membro m_bHelpModede CWinApp antes de executar essas operações. A implementação CDialog de PreTranslateMessage verifica isso antes de chamar IsDialogMessage, por exemplo. Isso desabilita as teclas de "navegação da caixa de diálogo" em caixas de diálogo sem modo durante o modo SHIFT + F1. Além disso, CWinApp::OnIdle ainda é chamado durante esse loop.

Se o usuário escolher um comando no menu, ele será tratado como ajuda nesse comando por meio de WM_COMMANDHELP (consulte abaixo). Se o usuário clicar em uma área visível da janela do aplicativo, será feita uma determinação sobre se o clique foi feito ou não pelo cliente. OnContextHelp manipula automaticamente o mapeamento de cliques não feitos pelo cliente para cliques feitos pelo cliente. Se for um clique feito pelo cliente, ele enviará um WM_HELPHITTEST para a janela clicada. Se essa janela retornar um valor diferente de zero, esse valor será usado como contexto para a ajuda. Se ela retornar zero, OnContextHelp tentará a janela pai (e, em caso de falha, o respectivo pai e assim por diante). Se não for possível determinar um contexto de ajuda, o padrão será enviar um comando ID_DEFAULT_HELP à janela principal, que é (geralmente) mapeado para CWinApp::OnHelpIndex.

WM_HELPHITTEST

afx_msg LRESULT CWnd::OnHelpHitTest(
WPARAM, LPARAM lParam)

WM_HELPHITTEST é uma mensagem de janela privada do MFC recebida pela janela ativa que é clicada durante o modo de ajuda SHIFT + F1. Quando a janela recebe essa mensagem, ela retorna uma ID de ajuda DWORD para uso pelo WinHelp.

LOWORD(lParam) contém a coordenada de dispositivo do eixo X em que o mouse foi clicado em relação à área do cliente da janela.

HIWORD(lParam) contém a coordenada do eixo Y.

wParam
Não é usado e será zero. Se o valor retornado não for zero, o WinHelp será chamado com esse contexto. Se o valor retornado for zero, a janela pai será consultada para obtenção de ajuda.

Em muitos casos, é possível utilizar o código de teste de ocorrência que você já tem. Confira a implementação de CToolBar::OnHelpHitTest para obter um exemplo de manipulação da mensagem WM_HELPHITTEST (o código utiliza o código de teste de ocorrência usado em botões e dicas de ferramentas em CControlBar).

Suporte ao assistente de aplicativo do MFC e ao MAKEHM

O assistente de aplicativo do MFC cria os arquivos necessários para a elaboração de um arquivo de ajuda (arquivos .cnt e .hpj). Ele também inclui uma série de arquivos .rtf predefinidos que são aceitos pelo Microsoft Help Compiler. Muitos dos tópicos estão completos, mas pode ser preciso modificar alguns deles para seu aplicativo específico.

Há suporte para a criação automática de um arquivo de "mapeamento de ajuda" por um utilitário chamado MAKEHM. Esse utilitário pode mover o arquivo RESOURCE.H de um aplicativo para um arquivo de mapeamento de ajuda. Por exemplo:

#define IDD_MY_DIALOG   2000
#define ID_MY_COMMAND   150

será movido para:

HIDD_MY_DIALOG    0x207d0
HID_MY_COMMAND    0x10096

Esse formato é compatível com o recurso do compilador de ajuda, que mapeia IDs de contexto (os números do lado direito) para nomes de tópicos (os símbolos do lado esquerdo).

O código-fonte para o MAKEHM está disponível no exemplo de Utilitários de Programação do MFC MAKEHM.

Adicionar o suporte de ajuda após a execução do assistente de aplicativo do MFC

A melhor maneira de adicionar ajuda ao seu aplicativo é, antes de criá-lo, marcar a opção "Ajuda contextual" na página "Recursos avançados" do assistente de aplicativo do MFC. Dessa forma, o assistente de aplicativo do MFC adiciona automaticamente as entradas de mapa de mensagens necessárias à classe derivada de CWinApp para dar suporte à ajuda.

Ajuda em caixas de mensagem

Há suporte para a ajuda em caixas de mensagens (também chamadas de alertas) por meio da função AfxMessageBox, um wrapper para a API do Windows MessageBox.

Há duas versões de AfxMessageBox, uma para uso com uma ID de cadeia de caracteres e outra para uso com um ponteiro para uma cadeia de caracteres (LPCSTR):

int AFXAPI AfxMessageBox(LPCSTR lpszText,
    UINT nType,
    UINT nIDHelp);

int AFXAPI AfxMessageBox(UINT nIDPrompt,
    UINT nType,
    UINT nIDHelp);

Em ambos os casos, há uma ID de ajuda opcional.

No primeiro caso, o padrão para nIDHelp é 0, o que indica que não há ajuda para essa caixa de mensagem. Se o usuário pressionar F1 enquanto essa caixa de mensagem estiver ativa, não receberá ajuda (mesmo que o aplicativo dê suporte a ela). Se isso não for desejável, uma ID de ajuda deverá ser fornecida para nIDHelp.

No segundo caso, o valor padrão de nIDHelp é -1, o que indica que a ID de ajuda é igual a nIDPrompt. (Obviamente, a ajuda funcionará somente se o aplicativo estiver habilitado para ela.) Forneça 0 para nIDHelp a fim de que a caixa de mensagem não dê suporte à ajuda. Para que a mensagem seja habilitada para ajuda com uma ID de ajuda diferente de nIDPrompt, basta fornecer um valor positivo para nIDHelp diferente daquele de nIDPrompt.

Confira também

Observações técnicas por número
Observações técnicas por categoria