テクニカル ノート 28: 状況依存のヘルプのサポート
このノートでは、MFC におけるヘルプ コンテキスト ID の割り当て規則、およびその他のヘルプに関する問題について説明します。 状況依存のヘルプのサポートには、Visual C++ で使用できるヘルプ コンパイラが必要です。
Note
MFC では、WinHelp を使用した状況依存のヘルプの実装のほか、HTML ヘルプの使用もサポートしています。 このサポートと HTML ヘルプを使用したプログラミングの詳細については、「HTML ヘルプ: プログラムの状況依存のヘルプ」を参照してください。
サポートされているヘルプの種類
Windows アプリケーションに実装されている状況依存のヘルプには 2 種類あります。 1 つ目は "F1 ヘルプ" と呼ばれるもので、現在アクティブなオブジェクトに基づいて、適切なコンテキストを使用して WinHelp が起動します。 2 つ目は "Shift+ F1" モードです。 このモードでは、マウス カーソルがヘルプ カーソルに変わり、ユーザーはオブジェクトをクリックしながら進みます。 その時点で、WinHelp が起動し、ユーザーがクリックしたオブジェクトのヘルプが表示されます。
Microsoft Foundation Classes は、この両方の形式のヘルプを実装する必要があります。 さらに、フレームワークは、2 つのシンプルなヘルプ コマンド、Help Index と Using Help をサポートしています。
ヘルプ ファイル
Microsoft Foundation クラスでは、1 つのヘルプ ファイルが想定されます。 そのヘルプ ファイルの名前とパスは、アプリケーションと同じである必要があります。 たとえば、実行可能ファイルが C:\MyApplication\MyHelp.exe の場合、ヘルプ ファイルは C:\MyApplication\MyHelp.hlp でなければなりません。 パスは、CWinApp クラスの m_pszHelpFilePath メンバー変数を使用して設定します。
ヘルプ コンテキストの範囲
MFC の既定の実装では、プログラムが、ヘルプ コンテキスト ID の割り当てに関するいくつかの規則に従う必要があります。 これらの規則は、特定のコントロールに割り当てられた ID の範囲で、 これらの規則をオーバーライドするには、さまざまなヘルプ関連のメンバー関数のさまざまな実装を提供します。
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_
シンプルな "ヘルプ" コマンド
Microsoft Foundation Classes によって実装されるシンプルなヘルプ コマンドは 2 つあります。
ID_HELP_INDEX。CWinApp::OnHelpIndex によって実装されます
ID_HELP_USING。CWinApp::OnHelpUsing によって実装されます
最初のコマンドは、アプリケーションのヘルプ インデックスを表示します。 2 つ目は、WinHelp プログラムの使用に関するユーザー ヘルプを表示します。
状況依存のヘルプ (F1 ヘルプ)
F1 キーは通常、メイン ウィンドウのアクセラレータ テーブルに配置されたアクセラレータによって、ID_HELP の ID を持つコマンドに変換されます。 ID_HELP コマンドは、メイン ウィンドウまたはダイアログ ボックス上の ID_HELP の ID を持つボタンによって生成される場合もあります。
ID_HELP コマンドは、どのように生成されているかに関係なく、コマンド ハンドラーに到達するまでは、通常のコマンドとしてルーティングされます。 MFC コマンド ルーティング アーキテクチャの詳細については、テクニカル ノート 21 を参照してください。 アプリケーションでヘルプが有効になっている場合、ID_HELP コマンドは CWinApp::OnHelp によって処理されます。 アプリケーション オブジェクトは、ヘルプ メッセージを受信し、コマンドを適切にルーティングします。 これが必要なのは、既定のコマンド ルーティングでは、詳細なコンテキストを判断するには不十分であるためです。
CWinApp::OnHelp
は、次の順序で WinHelp を起動しようとします。
ヘルプ ID を使用してアクティブな
AfxMessageBox
呼び出しを確認します。 メッセージ ボックスが現在アクティブな場合、WinHelp は、そのメッセージ ボックスに適したコンテキストで起動されます。WM_COMMANDHELP メッセージをアクティブなウィンドウに送信します。 WinHelp を起動してもそのウィンドウが応答しない場合は、メッセージが処理されるか、現在のウィンドウが最上位のウィンドウになるまで、同じメッセージがそのウィンドウの先祖に送信されます。
ID_DEFAULT_HELP コマンドをメイン ウィンドウに送信します。 これにより、既定のヘルプが呼び出されます。 このコマンドは通常、
CWinApp::OnHelpIndex
にマップされます。
既定の ID ベース値 (例: コマンドの場合は 0x10000、ダイアログなどのリソースの場合は 0x20000) をグローバルにオーバーライドするには、アプリケーションは CWinApp::WinHelp をオーバーライドする必要があります。
この機能と、ヘルプ コンテキストの判断方法をオーバーライドするには、WM_COMMANDHELP メッセージを処理する必要があります。 現在の MDI の子ウィンドウよりも深いルーティングができないため、フレームワークが提供するよりも詳細なヘルプ ルーティングを提供したい場合があります。 また、特定のウィンドウやダイアログに対してより詳細なヘルプを、おそらく、そのオブジェクトの現在の内部状態やダイアログ内のアクティブなコントロールに基づいて、提供する必要が出てくることもあります。
WM_COMMANDHELP
afx_msg LRESULT CWnd::OnCommandHelp(WPARAM wParam, LPARAM lParam)
WM_COMMANDHELP は、ヘルプが要求されたときにアクティブ ウィンドウが受信するプライベート Winsows MFC メッセージです。 ウィンドウは、このメッセージを受信すると、ウィンドウの内部状態と一致するコンテキストで CWinApp::WinHelp
を呼び出す場合があります。
lParam
現在使用可能なヘルプ コンテキストを格納します。 ヘルプ コンテキストが決定されていない場合 lParam は 0 です。 OnCommandHelp
の実装では lParam 内のコンテキスト ID を使って、別のコンテキストを決定できます。また、それを単に CWinApp::WinHelp
に渡すこともできます。
wParam
使用されていません。0 になります。
OnCommandHelp
関数によって CWinApp::WinHelp
が呼び出されると、これは TRUE を返します。 TRUE が返されると、他のクラスや他のウィンドウへのこのコマンドのルーティングが停止します。
ヘルプ モード (Shift+F1 ヘルプ)
これは、状況依存のヘルプの 2 番目の形式です。 一般的に、このモードに入るには、SHIFT+F1 キーを押すか、メニュー/ツール バーを使用します。 これはコマンドとして実装されます (ID_CONTEXT_HELP)。 モーダル ダイアログ ボックスまたはメニューがアクティブなときは、このコマンドの変換に、メッセージ フィルター フックは使用されません。このため、このコマンドをユーザーが使用できるのは、アプリケーションによってメインのメッセージ ポンプが実行されているときのみです (CWinApp::Run
)。
このモードに入ると、ヘルプのマウス カーソルは、アプリケーションが通常その領域に独自のカーソルを表示していても、アプリケーションのすべての領域に表示されます (ウィンドウのサイズ調整の境界線など)。 ユーザーは、マウスまたはキーボードを使用してコマンドを選択できます。 コマンドを実行するのではなく、そのコマンドのヘルプが表示されます。 また、ユーザーが画面上に表示されるオブジェクト (ツール バー上のボタンなど) をクリックすると、そのオブジェクトの [ヘルプ] が表示されます。 このヘルプ モードは、CWinApp::OnContextHelp
によって提供されます。
このループの実行中は、すべてのキーボード入力が非アクティブになります (メニューにアクセスするキーを除く)。 また、PreTranslateMessage
によるコマンド変換が引き続き行われ、ユーザーはアクセラレータ キーを押して、そのコマンドのヘルプを受け取ることができます。
SHIFT+F1 ヘルプ モード中に実行すべきではない変換またはアクションで、PreTranslateMessage
関数内で行われているものがある場合は、それらの操作を行う前に、CWinApp
の m_bHelpMode メンバーを確認する必要があります。 PreTranslateMessage
の CDialog
実装では、たとえば IsDialogMessage
を呼び出す前にこれを確認します。 これにより、SHIFT+F1 モード中、モードレス ダイアログ上の "ダイアログ ナビゲーション" キーが無効になります。 さらに、このループ中、CWinApp::OnIdle
は引き続き呼び出されます。
ユーザーがメニューからコマンドを選択すると、それは、そのコマンドのヘルプとして処理されます (WM_COMMANDHELP を使用。以下を参照)。 ユーザーがアプリケーション ウィンドウの表示領域をクリックすると、クライアント以外のクリックかクライアント クリックかの判断が行われます。 OnContextHelp
によって、クライアント以外のクリックとクライアント クリックのマッピングが自動的に処理されます。 クライアント クリックの場合は、クリックされたウィンドウに WM_HELPHITTEST が送信されます。 そのウィンドウが 0 以外の値を返すと、その値は、ヘルプのコンテキストとして使用されます。 0 が返されると、OnContextHelp
は親ウィンドウを試します (失敗すると、その親ウィンドウ、以降同様に試します)。 ヘルプのコンテキストを特定できない場合、既定では ID_DEFAULT_HELP コマンドがメインウィンドウに送信され、メイン ウィンドウは (通常は) CWinApp::OnHelpIndex
にマップされます。
WM_HELPHITTEST
afx_msg LRESULT CWnd::OnHelpHitTest(
WPARAM, LPARAM lParam)
WM_HELPHITTEST は、SHIFT+F1 ヘルプ モード中にクリックされたアクティブ ウィンドウが受信する MFC プライベート ウィンドウ メッセージです。 ウィンドウは、このメッセージを受信すると、WinHelp が使用する DWORD ヘルプ ID を返します。
LOWORD(lParam) には、ウィンドウのクライアント領域を基準とした、マウスがクリックされた X 軸デバイス座標が含まれます。
HIWORD(lParam) には、Y 軸の座標が含まれています。
wParam
使用されていません。0 になります。 戻り値が 0 以外の場合、そのコンテキストで WinHelp が呼び出されます。 戻り値が 0 の場合、親ウィンドウに対して、ヘルプのクエリが実行されます。
多くの場合、既に存在する可能性があるヒット テスト コードを活用できます。 WM_HELPHITTEST メッセージを処理する例については、CToolBar::OnHelpHitTest
の実装を参照してください (コードで活用されるのは、CControlBar
内のボタンおよびヒント上で使用されたヒット テスト コードです)。
MFC アプリケーション ウィザードのサポートと MAKEHM
MFC アプリケーション ウィザードによって、ヘルプ ファイル (.cnt ファイルと .hpj ファイル) のビルドに必要なファイルが作成されます。 また、Microsoft ヘルプ コンパイラが受け入れる事前構築済み .rtf ファイルも多数含まれています。 トピックの多くは完了していますが、ご自身の特定のアプリケーションについて、変更が必要になるものがいくつか存在する可能性があります。
"ヘルプ マッピング" ファイルの自動作成は、MAKEHM と呼ばれるユーティリティによってサポートされています。 MAKEHM ユーティリティは、アプリケーションの RESOURCE.H ファイルをヘルプ マッピング ファイルに変換できます。 次に例を示します。
#define IDD_MY_DIALOG 2000
#define ID_MY_COMMAND 150
上記の例は次のように変換されます。
HIDD_MY_DIALOG 0x207d0
HID_MY_COMMAND 0x10096
この形式は、ヘルプ コンパイラのファシリティと互換性があり、コンテキスト ID (右側の数値) とトピック名 (左側の記号) をマップします。
MAKEHM のソース コードは、MFC プログラミング ユーティリティのサンプル MAKEHM 内で使用できます。
MFC アプリケーション ウィザード実行後のヘルプ サポートの追加
アプリケーションにヘルプを追加する最善の方法は、アプリケーションを作成する前に、MFC アプリケーション ウィザードの [高度な機能] ページ上で "状況依存のヘルプ" オプションを選択することです。 これにより MFC アプリケーション ウィザードによって、ヘルプをサポートするのに必要なメッセージ マップ エントリが、ご自身の CWinApp
派生クラスに自動的に追加されます。
メッセージ ボックスに関するヘルプ
(アラートと呼ばれることがある) メッセージ ボックスのヘルプは、AfxMessageBox
関数 (MessageBox
Windows API のラッパー) によってサポートされています。
AfxMessageBox
には 2 つのバージョンがあります。1 つは文字列 ID と共に使用し、もう 1 つは文字列 (LPCSTR
) へのポインターと共に使用します。
int AFXAPI AfxMessageBox(LPCSTR lpszText,
UINT nType,
UINT nIDHelp);
int AFXAPI AfxMessageBox(UINT nIDPrompt,
UINT nType,
UINT nIDHelp);
どちらの場合も、オプションのヘルプ ID があります。
最初のケースでは、nIDHelp の既定値は 0 です。これは、このメッセージ ボックスにはヘルプがないことを示します。 このようなメッセージ ボックスがアクティブのときに、ユーザーが F1 を押すと、(アプリケーションがヘルプをサポートしていても) そのユーザーにはヘルプが表示されません。 これが望ましくない場合は、nIDHelp にヘルプ ID を定義する必要があります。
2 番目のケースでは、nIDHelp の既定値は-1 です。これは、ヘルプ ID が nIDPrompt と同じであることを示します。 ヘルプは、もちろん、アプリケーションがヘルプ対応である場合にのみ機能します。 メッセージ ボックスでヘルプをサポートしないようにするには、nIDHelp には 0 を指定する必要があります。 メッセージをヘルプ対応にしたうえで、nIDPrompt とは異なるヘルプ ID を使用する必要がある場合は、nIDPrompt の値とは異なる正の値を nIDHelp に指定するだけです。