第147章 バージョン情報をつける


たいていのアプリケーションでは、メニューの「ヘルプ」 に「バージョン情報」というのがあります。また、最近の アプリケーションでは作者のホーム・ページとかE-Mailの アドレスが載っていてそこをクリックすると、ホーム・ページ にジャンプしたり、作者あてのメールが書けるようになっています。 さらに、エディタなどでは本文中にURLを見つけると 色が変わって下線がつくようになっているものも見かけます。 どのように実現すればよいのでしょうか。

まずは、昔ながらのバージョン情報ですが、これは ダイアログボックスやらメッセージボックスで 済ますこともできます。

一番簡単なのはShellAbout関数を使うことです。

int ShellAbout ( HWND hWnd, LPCTSTR szApp, LPCTSTR szOtherStuff, HICON hIcon );

hWndは親ウィンドウです。

szAppにはタイトルバーに表示するテキストです。#で区切ると そのあとの文字列が「Microsoft」のあとに続きます。

szOtherStuffはここにバージョンやら著作権を書きます。

hIconには表示したいアイコンのハンドルを書きます。NULLだと ウィンドウズのアイコンが表示されます。

自分でダイアログボックスで作ってもたいしてめんどうでは ありませんが、こんな関数も知っておくと便利です。



さて、次にURLをクリックしたらホーム・ページへジャンプするには どうしたらよいのでしょうか。

第104章105章で 「何でも」開ける(?)プログラムを作りましたが、ShellExecute関数は使えないでしょうか。 実は,これで大丈夫なのです。
では、ダイアログボックスに文字列(URL)を表示してこれをクリックなり ダブルクリックするとそのURLに飛んでいくにはどうすれば良いでしょうか。

文字列はスタティックコントロールに書きこむことにします。

これがクリックされたことを知るためにはいろいろな方法があります。 1つはこのコントロールにSS_NOTIFYスタイルをつけてやります。 これで、親に通知が行きます。しかし、それだけでは面白くありません。 色を変えたり下線をつけたりしたいですね。また、コントロールに カーソルが行ったときカーソル形状も変えなくては行けません。

前回までの成り行きを考えるとまた、サブクラス化が出てきそうですね。

1.ダイアログボックスを作る 2.ダイアログボックスができたらすぐにスタティックコントロールの   サブクラス化を実行する 3.サブクラス化したプロシージャの中でWM_PAINTメッセージを   捕まえて、URLを青色・下線付きで描画する 4.また、WM_LBUTTONDOWNを捕まえてShellExecuteを実行する 5.WM_SETCURSORを捕まえてカーソル形状を変化させる 6.ダイアログボックスのプロシージャでIDOKまたはIDCANCELが   来たらサブクラス化を解除する

ここでサブクラス化したプロシージャでWM_LBUTTONDOWNを捕まえるので コントロールのSS_NOTIFYは不要と考えがちですが、スタティックコントロールは これがないと何にもしません。

こう見ると簡単そうですが、実際作ってみると錯覚しやすいです。 特にダイアログのプロシージャの中を書いているのか、サブクラス化した プロシージャの中を書いているのかがわからなくなってしまいます。

URLの部分にカーソルが行くとカーソルがの ように変わります。

URLをコントロールに書きこむにはSetTextColorで青くして、MoveToEx, LineToで 下線を引いていましたがうまくいきません。GetTextMetrics関数で取得した tmAveCharWidthにURLの文字数をかけた長さの直線を引くと長くなりすぎます。

やはり下線付きフォントにすべきでしょう。



では、本文中でURLを見つけるにはどうしたらよいのでしょうか。

これは、かなりめんどうです。しかし、幸いなことにVC++6.0では リッチエディットコントロール2.0をサポートしています。 これだとWM_AUTOURLDETECTメッセージを サポートしているので簡単です。ところが、実際2.0を使うと他の部分で ちょっとまずいことが起こります。これについては後の章で解説することにします。

では、プログラムを見てみることにしましょう。ビットマップ,アイコン,カーソルは 自分で好きなように作って下さい。

// rich18.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "新規作成(&N)", IDM_NEW MENUITEM "開く(&O)", IDM_OPEN MENUITEM SEPARATOR MENUITEM "上書き保存(&S)", IDM_SAVE MENUITEM "名前をつけて保存(&A)", IDM_SAVEAS MENUITEM SEPARATOR MENUITEM "プリンターの設定(&U)", IDM_PRNSET MENUITEM "印刷(&P)", IDM_PRINT MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_END END POPUP "編集(&E)" BEGIN MENUITEM "元に戻す(&U)", IDM_UNDO MENUITEM SEPARATOR MENUITEM "横書き(&H)", IDM_HORIZONTAL MENUITEM "縦書き(&V)", IDM_VERTICAL MENUITEM SEPARATOR MENUITEM "フォントの変更(&F)", IDM_FONT POPUP "段落書式(&P)" BEGIN MENUITEM "中央揃え(&C)", IDM_CENTER MENUITEM "左揃え(&L)", IDM_LEFT MENUITEM "右揃え(&R)", IDM_RIGHT MENUITEM SEPARATOR POPUP "タブの設定(&T)" BEGIN MENUITEM "2cm毎", IDM_2CM MENUITEM "1cm毎", IDM_CM MENUITEM "0.5cm毎", IDM_05CM MENUITEM SEPARATOR MENUITEM "2インチ毎", IDM_2INCH MENUITEM "1インチ毎", IDM_INCH MENUITEM "0.5インチ毎", IDM_05INCH END MENUITEM SEPARATOR MENUITEM "段落マーク付け(&M)", IDM_NUM END MENUITEM SEPARATOR MENUITEM "コピー(&C)", IDM_COPY MENUITEM "切り取り(&T)", IDM_CUT MENUITEM "貼り付け(&P)", IDM_PASTE MENUITEM "削除(&D)", IDM_DELETE MENUITEM SEPARATOR MENUITEM "すべて選択(&L)", IDM_ALL END POPUP "表示(&V)" BEGIN MENUITEM "背景色の変更(&B)", IDM_BACKCOLOR MENUITEM "ツールバーのカスタマイズ(&C)", IDM_CUSTOMIZE MENUITEM SEPARATOR MENUITEM "ツールバー(&T)", IDM_TOOL MENUITEM "ステータスバー(&S)", IDM_STATUS MENUITEM "ルーラー(&R)", IDM_RULER END POPUP "ヘルプ(&H)" BEGIN MENUITEM "バージョン情報(&A)", IDM_ABOUT MENUITEM "サポート(&S)", IDM_SUPPORT END END MYPOPUP MENU DISCARDABLE BEGIN POPUP "ダミーです" BEGIN MENUITEM "新規作成", IDM_NEW MENUITEM "開く", IDM_OPEN MENUITEM SEPARATOR MENUITEM "上書き保存", IDM_SAVE MENUITEM "名前をつけて保存", IDM_SAVEAS MENUITEM SEPARATOR MENUITEM "横書き", IDM_HORIZONTAL MENUITEM "縦書き", IDM_VERTICAL MENUITEM SEPARATOR MENUITEM "フォントの変更", IDM_FONT MENUITEM SEPARATOR MENUITEM "左揃え", IDM_LEFT MENUITEM "右揃え", IDM_RIGHT MENUITEM "中央揃え", IDM_CENTER MENUITEM SEPARATOR MENUITEM "終了", IDM_END MENUITEM SEPARATOR MENUITEM "コピー", IDM_COPY MENUITEM "切り取り", IDM_CUT MENUITEM "貼り付け", IDM_PASTE MENUITEM "削除", IDM_DELETE MENUITEM "元に戻す", IDM_UNDO MENUITEM SEPARATOR MENUITEM "印刷", IDM_PRINT MENUITEM "プリンタの設定", IDM_PRNSET MENUITEM SEPARATOR MENUITEM "すべて選択", IDM_ALL MENUITEM SEPARATOR MENUITEM "背景色の変更", IDM_BACKCOLOR MENUITEM SEPARATOR POPUP "タブの設定" BEGIN MENUITEM "2cm毎", IDM_2CM MENUITEM "1cm毎", IDM_CM MENUITEM "0.5cm毎", IDM_05CM MENUITEM SEPARATOR MENUITEM "2インチ毎", IDM_2INCH MENUITEM "1インチ毎", IDM_INCH MENUITEM "0.5インチ毎", IDM_05INCH END MENUITEM SEPARATOR MENUITEM "段落マーク付け", IDM_NUM MENUITEM SEPARATOR MENUITEM "ツールバー", IDM_TOOL MENUITEM "ステータスバー", IDM_STATUS MENUITEM "ルーラー", IDM_RULER END END ///////////////////////////////////////////////////////////////////////////// // // Toolbar // ID_MYTOOLBAR TOOLBAR DISCARDABLE 16, 15 BEGIN BUTTON IDM_VERTICAL BUTTON IDM_HORIZONTAL BUTTON IDM_LEFT BUTTON IDM_CENTER BUTTON IDM_RIGHT BUTTON IDM_FONT BUTTON IDM_BACKCOLOR END ///////////////////////////////////////////////////////////////////////////// // // Bitmap // ID_MYTOOLBAR BITMAP DISCARDABLE "mytoolba.bmp" MYBMP BITMAP DISCARDABLE "MYBMP.bmp" ///////////////////////////////////////////////////////////////////////////// // // Dialog // MYSUPPORT DIALOG DISCARDABLE 0, 0, 114, 134 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION CAPTION "サポート情報" FONT 14, "System" BEGIN DEFPUSHBUTTON "OK",IDOK,32,112,50,14 LTEXT "",IDC_STATIC2,32,101,71,8,SS_NOTIFY LTEXT "URL: ",IDC_STATIC,7,101,20,8 CONTROL "MYBMP",IDC_STATIC,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_REALSIZEIMAGE,7,7,98,82 END ///////////////////////////////////////////////////////////////////////////// // // Cursor // MYCURSOR CURSOR DISCARDABLE "mycursor.cur" ///////////////////////////////////////////////////////////////////////////// // // Icon // MYICON ICON DISCARDABLE "icon1.ico"

メニュー項目に「ヘルプ」が加わりました。

カーソル,ビットマップ,アイコン,ダイアログも加わりました。 すこし、アプリケーションらしくなってきました。

// rich18.cpp ...省略... #define SZMYURL "http://www.kumei.ne.jp/" #define SZMYVERSION "猫でもわかるRTF#猫でもわかるRTF Ver1.08" #define SZMYCOPYRIGHT "Copyright (C) 1998 Y.Kumei" ...省略... LRESULT CALLBACK MyAboutProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyAboutStaticProc(HWND, UINT, WPARAM, LPARAM); ...省略... char szClassName[] = "rich18"; //ウィンドウクラス ...省略... WNDPROC Org_MyAboutStatic; ...省略...

URLやら著作権の文字列をdefineしてみみした。

WinMain関数に変更はありません。

//ウィンドウ・クラスの登録 BOOL 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(hInst, "MYICON"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(hInst, "MYICON"); return (RegisterClassEx(&wc)); }

せっかくアイコンを作ったのでここでも使ってみました。

InitInstance関数に変更はありません。

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { ...省略... HICON hIcon; ...省略... switch (LOWORD(wp)) { case IDM_ABOUT: hIcon = LoadIcon(hInst, "MYICON"); ShellAbout(hWnd, SZMYVERSION, SZMYCOPYRIGHT, hIcon); break; case IDM_SUPPORT: DialogBox(hInst, "MYSUPPORT", hWnd, (DLGPROC)MyAboutProc); break; ...省略...

プロシージャのところはWM_COMMANDのところでIDM_ABOUTとIDM_SUPPORTが増えました。 何をしているかは説明は不要ですね。

LRESULT CALLBACK MyAboutProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { static HWND hMyStatic; switch (msg) { case WM_INITDIALOG: hMyStatic = GetDlgItem(hDlg, IDC_STATIC2); if (!hMyStatic) MessageBox(NULL, "Error", "OK", MB_OK); Org_MyAboutStatic = (WNDPROC)GetWindowLong(hMyStatic, GWL_WNDPROC); SetWindowLong(hMyStatic, GWL_WNDPROC, (LONG)MyAboutStaticProc); return TRUE; case WM_COMMAND: switch (LOWORD(wp)) { case IDOK: if (SetWindowLong(hMyStatic, GWL_WNDPROC, (LONG)Org_MyAboutStatic) == 0) MessageBox(hDlg, "Error", "OK", MB_OK); EndDialog(hDlg, IDOK); return TRUE; } return FALSE; } return FALSE; }

ダイアログボックスのプロシージャです。ダイアログボックスができたらすぐに IDC_STATIC2をサブクラス化しています。

そして、IDOKが来たらサブクラスかを解除しています。

LRESULT CALLBACK MyAboutStaticProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; COLORREF cr; LOGFONT lf; HFONT hFont; HCURSOR hCursor; switch (msg) { case WM_SETCURSOR: hCursor = LoadCursor(hInst, "MYCURSOR"); SetCursor(hCursor); return 0; case WM_LBUTTONDOWN: ShellExecute(hWnd, NULL, SZMYURL, NULL, NULL, SW_SHOWNORMAL); return 0; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); memset(&lf, 0, sizeof(LOGFONT)); strcpy(lf.lfFaceName , "system"); lf.lfUnderline = TRUE; hFont = CreateFontIndirect(&lf); SelectObject(hdc, (HGDIOBJ)hFont); cr = GetSysColor(COLOR_MENU); SetBkColor(hdc, cr); SetTextColor(hdc, RGB(0, 0, 255)); SetBkMode(hdc, TRANSPARENT); TextOut(hdc, 0, 0, SZMYURL, 22); DeleteObject(hFont); EndPaint(hWnd, &ps); return 0; } return (CallWindowProc(Org_MyAboutStatic, hWnd, msg, wp, lp)); }

WM_SETCURSORはウィンドウの中にマウスカーソルが入ったら、そのウィンドウに 送られます。(当然マウスキャプチャーなんかされていないときです)

WM_SETCURSOR hwnd = (HWND) wParam; // カーソルを持つウィンドウハンドル nHittest = LOWORD(lParam); // ヒットテストコード wMouseMsg = HIWORD(lParam); // マウスメッセージID

というようになっています。

あと,まだまだ手直ししなくてはいけないところがたくさんあります。 このプログラムをもとに自分独自の物を作ってみて下さい。 また、リッチエディットコントロール2.0にも挑戦してみて下さい。


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 04/Oct/1998 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。