メニュー項目がアクティブになっている時(文字が反転強調されます)、F1キーを押すと
それに関連したヘルプが出ます。左の図では「ダイアログボックス(D)」
というメニュー項目がアクティブになっているのでこの時F1キーを
押すと、これに関連したヘルプが出てきます。
また、クライアント領域にボタンがありますが、これがフォーカスを持っている時 (ボタンの内側が点線で囲まれます)F1キーを押しても、これに関連した ヘルプが出てきます。
メニューの「ダイアログボックス」を選択すると、左の図のようなダイアログが
出てきます。この時右上に「?」マークのボタンがついていることに注意してください。
このボタンを押すとマウスカーソルが矢印と「?」マークがくっついた形状に変わります。 この状態で「氏名」「住所」などのスタティックコントロールや、エディットコントロール、 「OK」「キャンセル」ボタンをクリックするとそれぞれの説明が書かれたヘルプまたは、 メッセージボックスが出てきます。
では、その仕組みはどうなっているのでしょうか。
ユーザーがF1キーを押すとWM_HELPメッセージが来ます。また、?印カーソルが クリックされたときもWM_HELPメッセージが来ます。
この時lParamは、HELPINFO構造体のアドレスを表します。WM_HELP lphi = (LPHELPINFO) lParam;
HELPINFO構造体は、次のように定義されています。
cbSizeは、この構造体のサイズを表します。typedef struct tagHELPINFO { UINT cbSize; int iContextType int iCtrlId; HANDLE hItemHandle; DWORD dwContextId; POINT MousePos; } HELPINFO, FAR *LPHELPINFO;
iContextTypeは、要求されているヘルプのコンテキストの種類を表します。次のうちの 1つです。
HELPINFO_MENUITEM | メニュー項目に対するヘルプが要求されている |
HELPINFO_WINDOW | コントロールまたはウィンドウに対するヘルプが要求されている |
iCtrlIdは、iContextTypeがHELPINFO_WINDOWの時はウィンドウまたはコントロールのIDを
表します。
iContextTypeがHELPINFO_MENUITEMの時はメニュー項目のIDを表します。
hItemHandleは、iContextTypeがHELPINFO_WINDOWの時は子ウィンドウ、またはコントロールの
ウィンドウハンドルを表します。
iContextTypeがHELPINFO_MENUITEMの時は、メニュー項目のIDを表します。
dwContextIdは、ウィンドウまたはコントロールのコンテキストIDを表します。
MousePosは、マウスカーソルの座標のPOINT構造体です。
ついでにWM_CONTEXTMENUというメッセージの復習もしておいてください。 普段あまり使わないので忘れがちです。忘れた人は 第115章を参照してください。
では、プログラムを見てみましょう。
メニューと、ダイアログボックスのリソース・スクリプトです。 ダイアログボックスのスタイルにDS_CONTEXTHELP が含まれていることに注意してください。これで、ダイアログボックスの右上に 「?」マークのボタンが追加されます。VC++のリソースエディタでは ダイアログプロパティの「その他のスタイル」の「コンテキストヘルプ」に チェックを付けておきます。// help04.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "終了(&X)", IDM_END END POPUP "オプション(&O)" BEGIN MENUITEM "ダイアログボックス(&D)", IDM_DLG END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYDLG DIALOG DISCARDABLE 0, 0, 130, 73 STYLE DS_MODALFRAME | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "オプション" FONT 9, "MS Pゴシック" BEGIN DEFPUSHBUTTON "OK",IDOK,7,52,50,14 PUSHBUTTON "キャンセル",IDCANCEL,73,52,50,14 LTEXT "氏名",IDC_STATIC1,14,13,24,12 LTEXT "住所",IDC_STATIC2,15,35,26,11 EDITTEXT IDC_EDIT1,63,7,59,17,ES_AUTOHSCROLL EDITTEXT IDC_EDIT2,62,31,59,16,ES_AUTOHSCROLL END
このほかにHTMLヘルプを作ったときのコンテキストIDに番号をdefineした ヘッダファイル(test.h, 番外編第3章参照) も必要です。
HTMLヘルプAPIを使うときの前準備を忘れないでください。 また、test.hのインクルードはコンテキストIDを使うときに必要です。 ボタンのIDをdefineしている点にも注意してください。// help04.cpp #ifndef STRICT #define STRICT #endif #define ID_BUTTON 100 #include <windows.h> #include "resource.h" #include "htmlhelp.h" #include "test.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyDlgProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); char szClassName[] = "help04"; //ウィンドウクラス HINSTANCE hInst; DWORD dwCookie; //クッキー
インスタンスハンドルをグローバル変数にコピーしている点に注意してください。int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; // ヘルプシステムの初期化 HtmlHelp(NULL, NULL, HH_INITIALIZE, (DWORD)&dwCookie); while (GetMessage(&msg, NULL, 0, 0)) { if (!HtmlHelp(NULL, NULL, HH_PRETRANSLATEMESSAGE, (DWORD)&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; }
HTMLヘルプを使うときの初期化とメッセージループの処理に注意してください。
このへんはいつもと同じです。//ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst;//インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるヘルプ", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }
親ウィンドウのプロシージャです。//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; HELPINFO *lphi; static HWND hBut; switch (msg) { case WM_CREATE: hBut = CreateWindow("Button", "テスト", WS_VISIBLE | WS_CHILD, 10, 10, 60, 25, hWnd, (HMENU)ID_BUTTON, hInst, NULL); SetFocus(hBut); break; case WM_HELP: lphi = (HELPINFO *)lp; switch (lphi->iCtrlId) { case IDM_END: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO5); break; case IDM_DLG: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO6); break; case ID_BUTTON: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO7); } break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_DLG: DialogBox(hInst, "MYDLG", hWnd, (DLGPROC)MyDlgProc); break; } break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { DestroyWindow(hBut); DestroyWindow(hWnd); } break; case WM_DESTROY: HtmlHelp(NULL, NULL, HH_UNINITIALIZE, (DWORD)dwCookie); PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }
WM_CREATEメッセージが来たらボタンを作っています。そして、フォーカスを セットしています。
WM_HELPメッセージが来たらHELPINFO構造体のiCtrlIDメンバで場合分けしています。
メニューのIDM_ENDでF1が押されたらIHD_NO5に関連づけられたトピックを表示します。
IDM_DLGでF1が押されたときはIHD_NO6を表示します。
ボタンにフォーカスがあるときにF1が押されたときはIHD_NO7を表示します。
メニューからIDM_DLGが選択されたときは、ダイアログボックスを表示します。HH_HELP_CONTEXT コマンド pszFileには、マップ情報を持ったchmファイルを指定します。ウィンドウタイプを 指定する場合は>記号のあとにウィンドウタイプの名前を指定します。
dwDataには、表示したいトピックのコンテキストIDを指定します。
プログラム終了時HH_UNINITIALIZEコマンドの実行を忘れないでください。
ダイアログボックスのプロシージャです。LRESULT CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { HELPINFO *lphi; switch (msg) { case WM_HELP: lphi = (HELPINFO *)lp; switch (lphi->iCtrlId) { case IDOK: MessageBox(hDlg, "OKボタンです", "OK", MB_OK); return TRUE; case IDCANCEL: MessageBox(hDlg, "Cancel ボタンです", "OK", MB_OK); return TRUE; case IDC_STATIC1: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO1); return TRUE; case IDC_STATIC2: HtmlHelp(hDlg, "test.chm", HH_HELP_CONTEXT, IDH_NO2); return TRUE; case IDC_EDIT1: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO3); return TRUE; case IDC_EDIT2: HtmlHelp(NULL, "test.chm", HH_HELP_CONTEXT, IDH_NO4); return TRUE; } return FALSE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: case IDCANCEL: EndDialog(hDlg, IDOK); return TRUE; } return FALSE; } return FALSE; }
「?」印カーソルがクリックされたときHELPINFO構造体のiCtrlIDメンバで場合分けしています。
OKボタンとキャンセルボタンでクリックしたときはヘルプではなく、メッセージボックスを 出すようにしています。
今回は簡単なプログラムですが、使い道は広いです。
Update 18/Sep/2000 By Y.Kumei