TN028: Compatibilidad con la ayuda contextual
En esta nota, se describen las reglas para asignar identificadores de contextos de ayuda y otros problemas de ayuda en MFC. La compatibilidad con la ayuda contextual requiere el compilador de ayuda que está disponible en Visual C++.
Nota:
Además de implementar la ayuda contextual con WinHelp, MFC también admite el uso de la ayuda HTML. Para obtener más información sobre esta compatibilidad y la programación con la ayuda HTML, consulte Ayuda HTML: ayuda contextual para los programas.
Tipos de ayuda admitidos
Hay dos tipos de ayuda contextual implementada en las aplicaciones de Windows. La primera, llamada "Ayuda F1", implica iniciar WinHelp con el contexto adecuado en función del objeto activo actualmente. La segunda es el modo "Mayús+ F1". En este modo, el cursor del mouse cambia al cursor de ayuda y el usuario hace clic en un objeto. En ese momento, se inicia WinHelp para proporcionar ayuda sobre el objeto en el que el usuario ha hecho clic.
Microsoft Foundation Classes implementa ambas formas de ayuda. Además, el marco de trabajo admite dos comandos de ayuda simples, Índice de ayuda y Uso de la ayuda.
Archivos de ayuda
Microsoft Foundation Classes da por supuesto que hay un único archivo de Ayuda. Ese archivo de ayuda debe tener el mismo nombre y ruta de acceso que la aplicación. Por ejemplo, si el archivo ejecutable es C:\MyApplication\MyHelp.exe, el archivo de ayuda debe ser C:\MyApplication\MyHelp.hlp. La ruta de acceso se establece mediante la variable miembro m_pszHelpFilePath de la clase CWinApp.
Intervalos de contexto de ayuda
La implementación predeterminada de MFC requiere que un programa siga algunas reglas sobre la asignación de identificadores de contexto de ayuda. Estas reglas son un intervalo de identificadores asignados a controles específicos. Puede invalidar estas reglas proporcionando diferentes implementaciones de las distintas funciones miembro relacionadas con la ayuda.
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 de "Ayuda" sencillos
Microsoft Foundation Classes implementa dos comandos de ayuda sencillos:
ID_HELP_INDEX, implementado por CWinApp::OnHelpIndex
ID_HELP_USING, implementado por CWinApp::OnHelpUsing
El primer comando muestra el Índice de ayuda de la aplicación. El segundo muestra la ayuda del usuario sobre el uso del programa WinHelp.
Ayuda contextual (Ayuda F1)
Normalmente, la tecla F1 se traduce a un comando con un identificador de ID_HELP mediante un acelerador colocado en la tabla de aceleradores de la ventana principal. El comando ID_HELP también se puede generar mediante un botón con un identificador de ID_HELP en la ventana principal o el cuadro de diálogo.
Independientemente de cómo se genere el comando ID_HELP, se enruta como un comando normal hasta que llega a un controlador de comandos. Para obtener más información sobre la arquitectura de enrutamiento de comandos de MFC, consulte Nota técnica 21. Si la aplicación tiene habilitada la ayuda, CWinApp::OnHelp controlará el comando ID_HELP. El objeto de aplicación recibe el mensaje de ayuda y, a continuación, enruta el comando adecuadamente. Esto es necesario porque el enrutamiento de comandos predeterminado no es adecuado para determinar el contexto más específico.
CWinApp::OnHelp
intenta iniciar WinHelp en el orden siguiente:
Comprueba si hay una llamada activa a
AfxMessageBox
con un identificador de ayuda. Si un cuadro de mensaje está activo actualmente, WinHelp se inicia con el contexto adecuado para ese cuadro de mensaje.Envía un mensaje WM_COMMANDHELP a la ventana activa. Si esa ventana no responde iniciando WinHelp, se envía el mismo mensaje a los antecesores de esa ventana hasta que se procese el mensaje o la ventana actual sea una ventana de nivel superior.
Envía un comando ID_DEFAULT_HELP a la ventana principal. Esto invoca la ayuda predeterminada. Este comando se asigna generalmente a
CWinApp::OnHelpIndex
.
Para invalidar globalmente los valores base de identificador predeterminados (por ejemplo, 0x10000 para los comandos y 0x20000 para recursos como los cuadros de diálogo), la aplicación debe invalidar CWinApp::WinHelp.
Para invalidar esta funcionalidad y la forma en la que se determina un contexto de ayuda, debe controlar el mensaje WM_COMMANDHELP. Es posible que desee proporcionar un enrutamiento de ayuda más específico que el que proporciona el marco de trabajo, ya que solo llega tan profundo como la ventana secundaria MDI actual. También puede proporcionar ayuda más específica para una ventana o un cuadro de diálogo específicos, quizás en función del estado interno actual de ese objeto o del control activo en el cuadro de diálogo.
WM_COMMANDHELP
afx_msg LRESULT CWnd::OnCommandHelp(WPARAM wParam, LPARAM lParam)
WM_COMMANDHELP es un mensaje privado de Windows MFC que recibe la ventana activa cuando se solicita ayuda. Cuando la ventana recibe este mensaje, puede llamar a CWinApp::WinHelp
con un contexto que coincida con el estado interno de la ventana.
lParam
Contiene el contexto de ayuda disponible actualmente. lParam es cero si no se ha determinado ningún contexto de ayuda. Una implementación de OnCommandHelp
puede usar el identificador de contexto de lParam para determinar un contexto diferente o simplemente pasarlo a CWinApp::WinHelp
.
wParam
No se usa y será cero.
Si la función OnCommandHelp
llama a CWinApp::WinHelp
, debe devolver TRUE. Devolver TRUE detiene el enrutamiento de este comando a otras clases y a otras ventanas.
Modo de ayuda (Ayuda Mayús+F1)
Esta es la segunda forma de ayuda contextual. Por lo general, se entra a este modo al pulsar MAYÚS+F1 o mediante el menú o barra de herramientas. Se implementa como un comando (ID_CONTEXT_HELP). No se usa el enlace de filtro de mensajes para traducir este comando mientras un menú o un cuadro de diálogo modal estén activos, por lo que este comando solo está disponible para el usuario cuando la aplicación ejecuta el suministro de mensajes principal (CWinApp::Run
).
Después de entrar en este modo, se muestra el cursor del mouse de ayuda en todas las áreas de la aplicación, incluso si la aplicación mostraría normalmente su propio cursor para esa área (como el borde de ajuste de tamaño alrededor de la ventana). El usuario puede usar el mouse o el teclado para seleccionar un comando. En lugar de ejecutar el comando, se muestra la ayuda sobre ese comando. Además, el usuario puede hacer clic en un objeto visible de la pantalla, como un botón de la barra de herramientas, y se mostrará la ayuda para ese objeto. Este modo de ayuda lo proporciona CWinApp::OnContextHelp
.
Durante la ejecución de este bucle, toda la entrada del teclado está inactiva, excepto las teclas que acceden al menú. Además, la traducción de comandos se sigue realizando mediante PreTranslateMessage
para permitir al usuario pulsar una tecla de acelerador y recibir ayuda sobre ese comando.
Si hay traducciones o acciones específicas que se realizan en la función PreTranslateMessage
que no se deben realizar durante el modo de ayuda MAYÚS+F1, debe comprobar el miembro m_bHelpMode de CWinApp
antes de realizar esas operaciones. La implementación de CDialog
de PreTranslateMessage
comprueba esto antes de llamar a IsDialogMessage
, por ejemplo. Esto deshabilita las teclas de "navegación de cuadro de diálogo" en los cuadros de diálogo sin modo durante el modo MAYÚS+F1. Además, se sigue llamando a CWinApp::OnIdle
durante este bucle.
Si el usuario elige un comando en el menú, se controla como ayuda sobre ese comando (mediante WM_COMMANDHELP, consulte a continuación). Si el usuario hace clic en un área visible de la ventana de la aplicación, se determina si es un clic no de cliente o un clic de cliente. OnContextHelp
controla la asignación de clics que no son de cliente en clics de cliente automáticamente. Si es un clic de cliente, envía un mensaje WM_HELPHITTEST a la ventana en la que se hizo clic. Si esa ventana devuelve un valor distinto de cero, ese valor se usa como contexto de la ayuda. Si devuelve cero, OnContextHelp
lo intenta con la ventana primaria (y se produce un error, su elemento primario, etc.). Si no se puede determinar un contexto de ayuda, el valor predeterminado es enviar un comando ID_DEFAULT_HELP a la ventana principal, que se asigna (normalmente) a CWinApp::OnHelpIndex
.
WM_HELPHITTEST
afx_msg LRESULT CWnd::OnHelpHitTest(
WPARAM, LPARAM lParam)
WM_HELPHITTEST es un mensaje de ventana privada de MFC que recibe la ventana activa en la que se hace clic durante el modo de ayuda MAYÚS+F1. Cuando la ventana recibe este mensaje, devuelve un identificador de ayuda DWORD para que lo use WinHelp.
LOWORD(lParam) contiene la coordenada del dispositivo del eje X en la que se hizo clic con el mouse en relación con el área cliente de la ventana.
HIWORD(lParam) contiene la coordenada del eje Y.
wParam
no se usa y será cero. Si el valor devuelto es distinto de cero, se llama a WinHelp con ese contexto. Si el valor devuelto es cero, se consulta la ventana primaria para obtener ayuda.
En muchos casos, puede aprovechar el código de prueba de posicionamiento que pueda tener. Consulte la implementación de CToolBar::OnHelpHitTest
para obtener un ejemplo del control del mensaje WM_HELPHITTEST (el código aprovecha el código de prueba de posicionamiento usado en los botones y la información sobre herramientas de CControlBar
).
Compatibilidad con el Asistente para aplicaciones de MFC y MAKEHM
El Asistente para aplicaciones de MFC crea los archivos necesarios para compilar un archivo de Ayuda (archivos .cnt y .hpj). También incluye una serie de archivos .rtf creados previamente aceptados por el compilador de ayuda de Microsoft. Muchos de los temas están completos, pero es posible que se deban modificar algunos para su aplicación específica.
Una utilidad llamada MAKEHM permite la creación automática de un archivo de "asignación de ayuda". La utilidad MAKEHM puede traducir el archivo RESOURCE.H de una aplicación a un archivo de asignación de Ayuda. Por ejemplo:
#define IDD_MY_DIALOG 2000
#define ID_MY_COMMAND 150
se traducirá en:
HIDD_MY_DIALOG 0x207d0
HID_MY_COMMAND 0x10096
Este formato es compatible con la utilidad del compilador de ayuda, que asigna los identificadores de contexto (los números del lado derecho) a los nombres de tema (los símbolos del lado izquierdo).
El código fuente de MAKEHM está disponible en el ejemplo MAKEHM de utilidades de programación de MFC.
Adición de compatibilidad con la ayuda después de ejecutar el Asistente para aplicaciones de MFC
La mejor manera de agregar ayuda a la aplicación es marcar la opción "Ayuda contextual" en la página Características avanzadas del Asistente para aplicaciones de MFC antes de crear la aplicación. De este modo, el Asistente para aplicaciones de MFC agrega automáticamente las entradas de asignación de mensajes necesarias a la clase derivada de CWinApp
para admitir la ayuda.
Ayuda sobre cuadros de mensaje
La ayuda sobre cuadros de mensaje (a veces llamados alertas) se admite mediante la función AfxMessageBox
, un contenedor para la API MessageBox
de Windows.
Hay dos versiones de AfxMessageBox
, una para su uso con un identificador de cadena y otra para su uso con un puntero a una cadena (LPCSTR
):
int AFXAPI AfxMessageBox(LPCSTR lpszText,
UINT nType,
UINT nIDHelp);
int AFXAPI AfxMessageBox(UINT nIDPrompt,
UINT nType,
UINT nIDHelp);
En ambos casos, hay un identificador de ayuda opcional.
En el primer caso, el valor predeterminado de nIDHelp es 0, que indica que no hay ayuda para este cuadro de mensaje. Si el usuario pulsa F1 mientras un cuadro de mensaje de este tipo está activo, el usuario no recibirá ayuda (aunque la aplicación admita ayuda). Si esto no es deseable, se debe proporcionar un identificador de ayuda para nIDHelp.
En el segundo caso, el valor predeterminado de nIDHelp es -1, lo que indica que el identificador de ayuda es el mismo que nIDPrompt. La ayuda solo funcionará si la aplicación está habilitada para la ayuda, por supuesto). Debe proporcionar 0 para nIDHelp si desea que el cuadro de mensaje no tenga compatibilidad con la ayuda. Si desea que el mensaje tenga la ayuda habilitada, pero desea un identificador de ayuda diferente a nIDPrompt, simplemente proporcione un valor positivo para nIDHelp diferente al de nIDPrompt.