I have been working through my app adding the OnHelpInfo
message handler. This is not because my app will support context help. Rather, I wanted to intercept the F1 key and then simply call the existing "Help" code that is triggered when then press the dialog button or menu item. Example:
#pragma warning (suppress : 26434)
BOOL CBrotherExcludeDlg::OnHelpInfo(HELPINFO* pHelpInfo)
{
OnButtonHelp();
// return CResizingDialog::OnHelpInfo(pHelpInfo);
return TRUE;
}
My problem is for the property pages. They handle the displaying on the help topics by using a different mechanism. Example:
void CCalendarSettingsGooglePage::OnPsnHelp(NMHDR* hdr, LRESULT* res)
{
theApp.DisplayHelpTopic(_T("msa-options-calendars.html"));
}
It uses the PSN_HELP
handler. When I add the OnHelpInfo
to the property page, I am now not sure how to simply run the OnPsnHelp
event. I am trying to avoid having two places where I call DisplayHelpTopic
.
How can we either directly call OnPsnHelp
(like I called the Help button click handler function) or invoke it via a message?
This is the boiler plate code:
BOOL CPropertyPage::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
ASSERT(pResult != NULL);
NMHDR* pNMHDR = (NMHDR*)lParam;
// allow message map to override
if (CDialog::OnNotify(wParam, lParam, pResult))
return TRUE;
// don't handle messages not from the page/sheet itself
if (pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd))
return FALSE;
// handle default
switch (pNMHDR->code)
{
case PSN_SETACTIVE:
{
CPropertySheet* pSheet = GetParentSheet();
if (pSheet != NULL && !(pSheet->m_nFlags & WF_CONTINUEMODAL) && !(pSheet->m_bModeless) && !(pSheet->m_psh.dwFlags & PSH_AEROWIZARD))
*pResult = -1;
else
*pResult = OnSetActive() ? 0 : -1;
}
break;
case PSN_KILLACTIVE:
*pResult = !OnKillActive();
break;
case PSN_APPLY:
*pResult = OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
break;
case PSN_RESET:
OnReset();
break;
case PSN_QUERYCANCEL:
*pResult = !OnQueryCancel();
break;
case PSN_WIZNEXT:
*pResult = MapWizardResult(OnWizardNext());
break;
case PSN_WIZBACK:
*pResult = MapWizardResult(OnWizardBack());
break;
case PSN_WIZFINISH:
*pResult = reinterpret_cast<LRESULT>(OnWizardFinishEx());
break;
case PSN_HELP:
SendMessage(WM_COMMAND, ID_HELP);
break;
default:
return FALSE; // not handled
}
return TRUE; // handled
}
So I don't get that. If I use SendMessage(WM_COMMAND, ID_HELP);
the response in the software is a popup Failed to launch help
.
As you mentioned in the comments, you could just call your OnPsnHelp
function with two nullptr
values, because that function doesn't actually use those parameters. However, this is asking for trouble if, in a future version of your software, the OnPsnHelp
is modified so that it does use those.
So, you should construct an appropriate PSHNOTIFY
structure and pass the address of that, and of a valid return-code variable, in your 'proxy' call of OnPsnHelp
. The construction of that PSHNOTIFY
structure is quite trivial; it is simply an NMHDR
structure followed by an unused lParam
item.
Here's a possible implementation:
BOOL CCalendarSettingsGooglePage::OnHelpInfo(HELPINFO*)
{
PSHNOTIFY psns;
psns.lParam = 0; // The docs say this contains no information.
psns.hdr.hwndFrom = GetParent()->GetSafeHwnd(); // The parent P/Sheet
psns.hdr.idFrom = IDHELP; // Not sure what this should REALLY be?
#pragma warning(suppress: 26454) // For: #define PSN_HELP (PSN_FIRST-5)
psns.hdr.code = PSN_HELP; // One would assume this is the correct code!
LRESULT result;
OnPsnHelp(&psns.hdr, &result); // Make the call.
return TRUE; // Or possibly: return static_cast<BOOL>(result);
}
From the M/S docs:
lParam
Pointer to a
PSHNOTIFY
structure that contains information about the notification code. This structure contains anNMHDR
structure as its first member, hdr. The hwndFrom member of thisNMHDR
structure contains the handle to the property sheet. The lParam member of thePSHNOTIFY
structure does not contain any information.
Here are the definitions of the PSHNOTIFY
and NMHDR
structures:
typedef struct _PSHNOTIFY
{
NMHDR hdr;
LPARAM lParam;
} PSHNOTIFY, *LPPSHNOTIFY;
typedef struct tagNMHDR
{
HWND hwndFrom;
UINT_PTR idFrom;
UINT code; // NM_ code
} NMHDR;