MFC: Why is OnCommandHelp needed and how does it work?

1.4k Views Asked by At

I have a simple MFC Application: a dialog with a button. For both of them I've called SetWindowContextHelpId() and set their Context IDs to non-zero values.

Also I can implement two handlers for the help commands: OnCommandHelp(WPARAM wParam, LPARAM lParam) and OnHelpInfo(HELPINFO* pHelpInfo).

MSDN writes the following about OnCommandHelp:

lParam contains the currently available Help context. lParam is zero if no Help context has been determined

But in my case lParam is always zero, though pHelpInfo from OnHelpInfo(HELPINFO* pHelpInfo) handler contains correct non-zero information about ContextID of the control (it was set by calling SetWindowContextHelpId).

Now I have two questions:

1) Why is lParam always zero? What does MSDN's remark about "determining of the Help context" mean? What is "currently available Help context"?

2) Why do we need OnCommandHelp, if we can use OnHelpInfo?

Any explanation would be appreciated.

UPDATE:

#include <afxwin.h>
#include <afxpriv.h>

#define ID_BUTTON 125

#define FRAME_HELP 4000
#define BUTTON_HELP 5000

class CMainWnd : public CFrameWnd
{
public:
    CMainWnd();
protected:
    afx_msg LRESULT OnCommandHelp(WPARAM wParam, LPARAM lParam);
    afx_msg int OnCreate(LPCREATESTRUCT lpcs);
    DECLARE_MESSAGE_MAP()
private:
    CButton btn;
};

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)
    ON_WM_CREATE()
    ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
END_MESSAGE_MAP()

int CMainWnd::OnCreate(LPCREATESTRUCT lpcs)
{
    int res = CFrameWnd::OnCreate(lpcs);

    m_nIDHelp = FRAME_HELP;
    SetWindowContextHelpId(FRAME_HELP);

    CRect rc(0, 0, 100, 100);

    btn.Create(_T("Button"), WS_CHILD | WS_VISIBLE, rc, this, ID_BUTTON);

    btn.SetWindowContextHelpId(BUTTON_HELP);

    return res;
}

LRESULT CMainWnd::OnCommandHelp(WPARAM wParam, LPARAM lParam)
{
    wchar_t arr[20];
    _itow_s(lParam, arr, 10);
    MessageBox(arr);
    return TRUE;
}

CMainWnd::CMainWnd()
{
    Create(NULL, _T("Just a frame"));
}

class CApp : public CWinApp
{
public:
    virtual BOOL InitInstance() override;
    DECLARE_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()

BOOL CApp::InitInstance()
{
    m_pMainWnd = new CMainWnd();
    m_pMainWnd->ShowWindow(m_nCmdShow);
    m_pMainWnd->UpdateWindow();

    return TRUE;
}

CApp App;
1

There are 1 best solutions below

2
On

The easiest way to understand the nesting of the functions is to set breakpoints on CDialog::OnCommandHelp and CWnd::OnHelpInfo.

First WM_HELPINFO is sent to the window. The default implementation in CWnd::OnHelpInfo may handle it and in later OnCommandHelp is called. Here m_nIDHelp is used and the help screen is launched.

If you handle all the stuff in the OnHelpInfo handler by yourself there is no call to OnCommandHelp...

In fact this complex structure is a relict from times were we don't had SetWindowContextHelpId.

When I have a normal dialog and press, F1 I get a call OnCoammandHelp and lParam is never 0! May be because I don't handle OnHelpInfo. If you use OnHelpInfo the context is already determined... of cause you did it, by handling OnHelpInfo.