0
votes

I'm rewriting old application written in C++ and MFC. One of new features I'm adding is help based on a .chm file. Let's say that file is called myHelp.chm. When I open it as user from the folder by double clicking on it, everything is OK. But if I start it using:

::HtmlHelp( NULL, _T("myHelp.chm"), HH_HELP_CONTEXT, uiNumber ) 

in my application, internal links between parts of help don't work (all help in one .chm file).

What I have:

In InitInstance() i've got:

EnableHtmlHelp();

And I run my HtmlHelp in CMainFrame::OnHelp().

Problem is probably not in the .chm file - I replaced it with other, from working application, and it works same - it opens, but non of internal links work.

Maybe it's something in project configuration or initialization? The project is really old - 1995 - and now I'm rewriting it in VS2012. I'm working under win 10.

1
Hi VioletPL, welcome to Stack Overflow! It would be helpful if you added some more context to the program you are trying to run the file from. - thesecretmaster
It's quite simple program with few dialogs. Each of them, when pressing F1 or Help button should open different page of help. And this part is working correctly. How can I give you wider context? - VioletPL
You write but non of internal links work. What exactly happens when you click on one of these links? There must be some problems in your html file or the way it is built. Very hard to tell for us what's going. Do the internal links work if you open the .chm file by double clicking on it from an Explorer window? - Jabberwocky
When i open chm file from Exploer window: - links are working perfect. When i open chm file via application: - links not working, when clicked they change color from blue to violet and nothing happens. No message box, no enter bad url, no refresh, nothing. I use Doc-To-Help 2012 to create chm file. - VioletPL
Just try to run your stuff on another computer and look if it works there. If yes, then there is probably some configuration problem on your computer. - Jabberwocky

1 Answers

1
votes

In your InitInstance handler you can do something like this:

#ifdef _WIN64 // AJT v11.3.4
    CString strHelp = m_pszHelpFilePath;

    strHelp.MakeLower();
    strHelp.Replace(_T("_x64.chm"), _T(".chm"));

    free((void*)m_pszHelpFilePath);//Change the name of the .HLP file.

    m_pszHelpFilePath = _tcsdup(strHelp);
#endif // _WIN64

So you can update the path to the help file.

Then, in the various windows that you want to show help, you can do this:

void CMinistryInfoDlg::OnButtonHelp() 
{
    HtmlHelp( (DWORD_PTR)_T("HelpMinistry.htm"),HH_DISPLAY_TOPIC );
}

That works for me.

Context Help

Your question alludes to context help. In my application I do it like this:

BOOL CCommunityTalksApp::ShowContextHelp(CWnd *pParent, HELPINFO* pHelpInfo)
{
    CPoint          ptControl ;
    CRect           rctControl ;
    CWnd            *pControl ;
    CString         strNoHelp, strHelpCommand ;
    HWND            hPopup ;
    HH_POPUP        sPop;
    BOOL            bOK = FALSE;

    if( pParent != NULL && pHelpInfo != NULL )
    {
        memset( &sPop, 0, sizeof(sPop) );

        sPop.clrBackground = GetSysColor( COLOR_INFOBK );

        sPop.clrForeground = -1;
        sPop.rcMargins.top = 5;
        sPop.rcMargins.left = 5;
        sPop.rcMargins.bottom = 5;
        sPop.rcMargins.right = 5;
        sPop.pt = pHelpInfo->MousePos;
        sPop.idString = pHelpInfo->iCtrlId;
        sPop.pszFont = NULL;

        pControl = pParent->GetDlgItem( pHelpInfo->iCtrlId );
        if( pControl != NULL )
        {
            pControl->GetWindowRect( &rctControl ); // Screen co-ords.

            ptControl.x = rctControl.left + (rctControl.Width() / 2);
            ptControl.y = rctControl.bottom ;    // Below control.

            sPop.pt = ptControl;
        }

        if( pHelpInfo->iCtrlId == IDC_STATIC ||
            pHelpInfo->iCtrlId == IDOK ||
            pHelpInfo->iCtrlId == IDCANCEL ||
            pHelpInfo->iCtrlId == IDCLOSE ||
            pHelpInfo->iCtrlId == IDC_HOME_STATIC ||
            pHelpInfo->iCtrlId == IDC_AWAY_STATIC ||
            pHelpInfo->iCtrlId == IDC_TALK_STATIC ||
            pHelpInfo->iCtrlId == ID_STATIC_WEEKS ||
            pHelpInfo->iCtrlId == IDC_STATIC_ENTRIES ||
            pHelpInfo->iCtrlId == IDC_STATIC_AWAY ||
            pHelpInfo->iCtrlId == IDC_STATIC_HOME ||
            pHelpInfo->iCtrlId == IDC_STATIC_TALK_HIST ||
            pHelpInfo->iCtrlId == IDC_LBL_STATIC ||
            pHelpInfo->iCtrlId == IDC_LBL_STATIC2 ||
            pHelpInfo->iCtrlId == ID_LBL_SORT_FIELD_LEGEND ||
            pHelpInfo->iCtrlId == IDC_STATIC_CONG_NOTES ||
            pHelpInfo->iCtrlId == IDC_STATIC_SPK_NOTES ||
            pHelpInfo->iCtrlId == IDC_STATIC_ADD_NEW_TALK ||
            pHelpInfo->iCtrlId == IDC_STATIC_MODIFY_NEW_TALK ||
            pHelpInfo->iCtrlId == ID_BTN_CONGS_SHOW_BOOKED)
        {
            // These control IDs do not have any associated help strings
            // so we use our own, otherwise we get a nasty HtmlHelp
            // error message displayed to the user.
            strNoHelp.LoadString( IDS_STR_NO_CONTEXT_HELP );
            sPop.idString = 0;
            sPop.pszText = strNoHelp;

            hPopup = ::HtmlHelp((HWND)pHelpInfo->hItemHandle,
                m_pszHelpFilePath,
                HH_DISPLAY_TEXT_POPUP,
                (DWORD_PTR)&sPop );
        }
        else
        {
            // This control ID _should_ be in the help strings.
            switch( GetProgramLanguage() )
            {
            case LANGUAGE_SPANISH:
                strHelpCommand.Format( _T("%s::/cshelpESP.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_GERMAN:
                strHelpCommand.Format( _T("%s::/cshelpDEU.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_ITALIAN:
                strHelpCommand.Format( _T("%s::/cshelpITA.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_DUTCH:
                strHelpCommand.Format( _T("%s::/cshelpDEU.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_PORTUGUESE:
                strHelpCommand.Format( _T("%s::/cshelpPTB.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_SWEDISH:
                strHelpCommand.Format( _T("%s::/cshelpSVE.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_DANISH:
                strHelpCommand.Format( _T("%s::/cshelpDAN.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_RUSSIAN:
                strHelpCommand.Format( _T("%s::/cshelpRUS.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_TURKISH:
                strHelpCommand.Format( _T("%s::/cshelpTRK.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_FRENCH:
                strHelpCommand.Format( _T("%s::/cshelpFRA.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_FINNISH:
                strHelpCommand.Format( _T("%s::/cshelpFIN.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_ALBANIAN:
                strHelpCommand.Format( _T("%s::/cshelpALB.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_ROMANIAN:
                strHelpCommand.Format( _T("%s::/cshelpROM.txt"), m_pszHelpFilePath );
                break;
            case LANGUAGE_ENGLISH:
            default:
                strHelpCommand.Format( _T("%s::/cshelpENG.txt"), m_pszHelpFilePath );
                break;
            }
            
            hPopup = ::HtmlHelp( (HWND)pHelpInfo->hItemHandle,
                            strHelpCommand,
                            HH_DISPLAY_TEXT_POPUP,
                            (DWORD_PTR)&sPop );
        }

        if( hPopup != NULL )
            bOK = TRUE;
    }

    return bOK;
}

My method is lengthy because I support multiple translations. But you should be able to see the principles.

I see you are using HH_HELP_CONTEXT which works a bit differently. I don't use that invocation anymore, but when I did:

void CMainFrame::HtmlHelp(DWORD_PTR dwData, UINT nCmd)
{
    HWND hWnd;

    hWnd = ::HtmlHelp(GetDesktopWindow()->GetSafeHwnd(), theApp.m_pszHelpFilePath,
                    HH_HELP_CONTEXT, nCmd == HELP_CONTEXT ? dwData : 0);

    if(hWnd == NULL)    // show default topic
        ::HtmlHelp(GetDesktopWindow()->GetSafeHwnd(), theApp.m_pszHelpFilePath,
                    HH_HELP_FINDER, 0 );

//  CMDIFrameWndEx::HtmlHelp(dwData, nCmd);
}