How To Implement HTML Help Text Pop-Ups in an MFC Application

Exclusion de responsabilité du contenu obsolète de la base de connaissances

Cet article a été rédigé sur les produits pour lesquels Microsoft n’offre plus aucune prise en charge. Par conséquent, cet article est proposé « en l’état » et ne sera plus mis à jour.


This article describes how to implement HTML Help text pop-up windows. It assumes that you are familiar with HTML Help and Microsoft Foundation Classes (MFC).
For additional information on preparing an MFC application to useHTML Help, click the article number below to view the article in the Microsoft Knowledge Base:

186907 How To Set Up Visual C++ to Use the HTML Help API
For additional information on converting an MFC application that is using Winhelp to use HTML Help, click the article number below to view the article in the Microsoft Knowledge Base:

241209 How To Convert a New MFC Application to HTML Help Using WinHelp

More Information

Text pop-up windows are small windows containing only text. They are most often used with "What's This" Help where the user clicks on the "What's This" question mark and then clicks on a control.

There are two different methods you can use to implement text pop-up windows using the HTML Help API.

The first method allows you to pass an array of Help IDs and one control ID to the HTML Help API. HTML Help determines which topic to display by using the window handle of the control to get the control ID. Then it uses the control ID to find the Help ID, which maps to text in a text file. The text file is compiled into the HTML Help .chm file.

The second method requires that the address of an HH_POPUP structure containing information about the pop-up window be passed to the HTML Help API. The type of information passed in the array is the foreground and background colors, the size of the text box, the font, and the resource ID of the string to display or the actual string itself.

This article demonstrates both methods of implementing text pop-up windows using the HTML Help API: by using an array of help IDs and by using an HH_POPUP structure.

Implementing Text Pop-Up Windows by Using an Array of Help IDs

  1. Using a text-editor, create a .txt file with the following format:

    .topic help-id
    text to be displayed
    The following, named "Popups.txt", is an example:
    .topic IDH_HT_VSCROLL
    Vertical Scroll

    .topic IDH_FILE_OPEN
    Open a File

    .topic IDH_FILE_NEW
    Create A New File

    .topic IDH_FILE_SAVE
    Save a File
  2. Include the text pop-up file in the [TEXT POPUPS] section of your HTML Help project file. To do so, click the HTML Help API Information button and then click Text-popups and Text File to add the text file. Save the project.
  3. The IDs referenced in the text file, such as HID_FILE_SAVE and HID_FILE_NEW in the previous step, must be defined in an include file, such as this one named "Context.h:"
    #define IDH_FILE_NEW 1
    #define IDH_FILE_OPEN 2
    #define IDH_FILE_SAVE 3
    #define IDH_EDIT_CUT 4
    #define IDH_EDIT_COPY 5
    #define IDH_EDIT_PASTE 6
    #define IDH_FILE_PRINT 7
    #define IDH_APP_ABOUT 8
    #define IDH_BUTTON1 10
  4. The file "Context.h" must be compiled into your HTML Help project. To do this, click the HTML Help API Information button and then click Text-popups and Header File to add the header file. After this step, your [TEXT POPUPS] section should have two files. It should have the text file of text popups and the include file, such as:

    Save the project and compile it.

    The next steps involve changing your MFC application, so close the HTML Help Workshop and open up your application in Visual Studio.
  5. Declare an array in whichever module is using the API to display text pop-up windows (see step 7 for more information regarding where this should be). The array contains pairs of control IDs and their matching Help IDs. The array must end in a 0. The following is an example:
    //Declare an array of control id - help id pairs. The array must have 0 as the last element.

    DWORD ids[7] ;
    ids[0] = ID_FILE_OPEN; ids[1] = IDH_FILE_OPEN;
    ids[2] = ID_FILE_NEW; ids[3] = IDH_FILE_NEW;
    ids[4] = ID_FILE_SAVE; ids[5] = IDH_FILE_SAVE;
    ids[6]= 0;
    #define numHelpIDs 3
  6. Include the header file for the Help IDs. For this example it would be as follows:
    #include "context.h"
  7. There are several different places where "What's This" Help could be implemented. This step describes methods to add such Help in three places:

    1. To add “What's This” Help to a dialog box, make sure the Context Help option is selected in the Extended Styles property box in the Resource Editor. Then override the OnHelpInfo() method using the Class Wizard. The following is an example:
      BOOL CMyDialog::OnHelpInfo(HELPINFO* pHelpInfo) 
      HtmlHelp((HWND)pHelpInfo->hItemHandle, "sample.chm::/popups.txt",HH_TP_HELP_WM_HELP,(DWORD) ids);
      return CDialog::OnHelpInfo(pHelpInfo);

    2. To add "What's This" Help to your main window, override CWinApp::Winhelp, test the nCmd parameter to see if it is HELP_CONTEXT. If it is, then it could be F1 Help or "What's This Help". If you want to handle these types of Help the same way, then you don't have to know which one it is. If you want to change the type of Help that will be displayed for each of the commands, then you must determine which type of Help is being invoked. One way to do this to override your CMainFrame::OnContextHelp command. When the “What's This” cursor is clicked on the frame window, the framework calls this routine. Override this function to set a flag to indicate that “What's This” Help was invoked. When the user then clicks on a control, the CWinApp::Winhelp function is invoked. In your CWinApp::Winhelp function, if HELP_CONTEXT is the received command, check the flag. The following is an example of the CMainFrame::OnContextHelp method and the CWinApp::WinHelp method:
      void CMainFrame::OnContextHelp()
      ((CNEWTEXTPOPApp *) AfxGetApp())->m_bWhatsThisHelp = TRUE;

      void CNEWTEXTPOPApp::WinHelp(DWORD dwData, UINT nCmd)
      DWORD i;
      DWORD ids[3];


      switch (nCmd)
      case HELP_CONTEXT:
      for (i= 0; i < numHelpIDs*2; i+=2)
      if( (aMenuHelpIDs[i] == LOWORD (dwData) ) )
      if (m_bWhatsThisHelp)
      m_bWhatsThisHelp = FALSE;

      ids[1] = aMenuHelpIDs[i];
      ids[2] = 0;

      ids[0]= ((CMainFrame *)m_pMainWnd)->GetDlgCtrlID();
      HWND atest = ((CMainFrame *)m_pMainWnd)->m_hWnd;

      HtmlHelp(atest, "sample.chm::/popups.txt",HH_TP_HELP_WM_HELP,(DWORD) ids);

      // If F1 help was selected, use HH_HELP_CONTEXT..
      HtmlHelp(m_pMainWnd->m_hWnd, "F:\\HTML H Context Help\\test\\sample.chm",HH_HELP_CONTEXT, aMenuHelpIDs[i+1]);
    3. "What's This" Help for a view such as a form view follows the same command path as for the frame window. Control goes to the CFrameWindow::OnContextHelp and then to CWinApp::Winhelp. It is necessary to intercept the framework between these two functions in order to set the appropriate control ID. You can do this manually (you can't use the class wizard) by overriding the OnHelpHitTest method.

      This involves three steps:

      1. First, add the OnHelpHitTest method to the message map of the view class:
        BEGIN_MESSAGE_MAP(MyFormView, CFormView)
      2. Next, add the prototype for OnHelpHitTest to the view's include file:
        LRESULT OnHelpHitTest(WPARAM wParam, LPARAM lParam);
      3. Last, add the OnHelpHitTest method to your view class. The lParam passed contains the mouse position of the cursor. To determine the control ID, check to see if the mouse is on a control. If it is, you can return the control ID. The framework will then call CWinApp::CWinHelp with that control ID. Or, you can display the text popup from OnHelpHitTest and set a flag to stop WinHelp from handling the message again. The following is an example of the former:
        LRESULT MyFormView::OnHelpHitTest(WPARAM wParam, LPARAM lParam)
        CWnd *pCtrl;
        RECT ctrlRect;
        CRect ctrlCRect;
        CPoint HitPt;
        int i;
        CRect rectView;

        // Get View's Rectangle

        // HitPt is where the mouse clicked in screen coordinates but
        // relative to the view window.
        HitPt.x = LOWORD (lParam);
        HitPt.y = HIWORD (lParam);

        // Make the screen coordinates relative to the main window
        // since controls coords will be.
        HitPt.x+= rectView.left;

        // Look at the screen coords for each control
        for (i=0; i < NUM_CONTROLS; i++){
        pCtrl = GetDlgItem(ViewControlIds[i]); // get a ptr to a control id
        if (pCtrl == NULL) return (0);
        pCtrl->GetWindowRect(&ctrlRect); // get control's rectangle
        `ctrlCRect = ctrlRect; // convert to CRect for next

        if (ctrlCRect.PtInRect(HitPt)){ // if point was in Control's rect
        ((CNEWTEXTPOPApp *) AfxGetApp())->m_bWhatsThisHelp = TRUE;
        return (ViewControlIds[i]); // pass help id to Winhelp

        i++; // point past help control id
        return 0; // if not on control pass 0 to let winhelp handle

Implementing Text Pop-Up Windows by Using an HH_POPUP Structure

An HH_POPUP structure is defined in the Htmlhelp.h file as:

typedef struct tagHH_POPUP
int cbStruct; // sizeof this structure
HINSTANCE hinst; // instance handle for string resource
UINT idString; // string resource ID, or text ID if szFile is specified in HtmlHelp call
LPCTSTR pszText; // used if idString is zero
POINT pt; // top center of popup window
COLORREF clrForeground; // use -1 for default
COLORREF clrBackground; // use -1 for default
RECT rcMargins; // amount of space between edges of window and text, -1 for each member to ignore
LPCTSTR pszFont; // facename, point size, char set, BOLD ITALIC UNDERLINE
There are two different ways to use this structure with context-sensitive Help: You can pass the text to be displayed in the pop-up in the idString parameter or you can pass a string resource ID in the idString parameter.

The following example illustrates the first method of passing the string in the IdString parameter.

// Define a structure to save the control IDs and the text strings for<BR/>
// them.

struct MyStrings_Struct
DWORD control_id;
CHAR myString[80];
} MyStrings[2];

// Initialize the structure.
MyStrings[0].control_id = ID_FILE_OPEN;
strcpy(MyStrings[0].myString , "This opens the file.\n");
MyStrings[1].control_id = ID_FILE_NEW;
strcpy(MyStrings[1].myString , "This opens a new file.\n");

// Declare the popup structure and initialize it.
HH_POPUP myPopup;

memset(&amp;myPopup, 0, sizeof(HH_POPUP) ); // Fill in the popup
myPopup.cbStruct = sizeof(HH_POPUP); = r.left; = r.bottom; = 5;
myPopup.rcMargins.bottom = 5;
myPopup.rcMargins.left = 5;
myPopup.rcMargins.right = 5;
myPopup.idString = 0; // set the ID string to 0

// search for the control id in the control array, put the help control ID in the HH_POPUP array.

for( i=0; i < MY_ARRAY_SIZE; i+=2 )
if (MyControlId == MyStrings[i].control_id )
strcpy(MyPopup.pszText, MyStrings[i].myString);
HtmlHelp( this->m_hWnd, NULL, HH_DISPLAY_TEXT_POPUP, (DWORD) &myPopup);

The other approach is similar to the previous example except you set myPopup.pszText to NULL and set myPopup.idString to the ID of the string resource.

ID d'article : 241218 - Dernière mise à jour : 19 juin 2014 - Révision : 1