第258章 レバーコントロールの実際


前章では、原始的なツールバーをつけてみました。 今回は、フラットツールバーにして、ボタンもファイル関係と編集関係に分けて レバーコントロールにのせてみました。レバーコントロールについてはすでに 第182章で解説してあります。しかし、 実際のプログラミングではいろいろ問題が生じてきます。これが、表示されたときと 非表示の時、また複数列になったときにエディットコントロールや、書き込み用 ダイアログをうまく調整しなくてはいけません。

第182章のサンプルプログラムではメニューがありませんでした。 メニューをつけてレバーコントロールをつけると、この境目がなくなり 何となく見栄えのしない外観となります。レバーコントロールのスタイルから CCS_NODIVIDERスタイルをはずすと、メニューとレバーコントロールの間に 隙間が空いて、これまたみっともないことになります。そこでメニューバーのすぐ下に 高さ2の細長いスタティックウィンドウをおくことにします。 このウィンドウのスタイルをSS_SUNKEN(くぼみ)に すると左の図のような感じになります。

メニューの「表示」「ツールバー」でツールバーを非表示にすることもできます。 また、レバーコントロールをドラッグして2列に表示することもできます。

これまでは、書き込みダイアログが表示されていない状態でメインウィンドウを 小さくしておいて、書き込みダイアログを表示するとダイアログの一部しか表示されませんでした。 今回は、これも改善します。

// mailslot09.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "新規作成(&N)...", IDM_NEW MENUITEM "開く(&O)...", IDM_OPEN MENUITEM "上書き保存(&S)", IDM_SAVE MENUITEM "名前を付けて保存(&A)...", IDM_SAVEAS MENUITEM SEPARATOR MENUITEM "タスクトレーに格納(&T)", IDM_TASK MENUITEM SEPARATOR MENUITEM "終了(&X)...", IDM_END END POPUP "編集(&E)" BEGIN MENUITEM "元に戻す(&U)", IDM_UNDO, GRAYED MENUITEM SEPARATOR MENUITEM "切り取り(&T)", IDM_CUT, GRAYED MENUITEM "コピー(&C)", IDM_COPY, GRAYED MENUITEM "張り付け(&P)", IDM_PASTE, GRAYED MENUITEM "削除(&D)", IDM_DELETE, GRAYED MENUITEM SEPARATOR MENUITEM "すべて選択(&L)", IDM_ALL END POPUP "表示(&V)" BEGIN MENUITEM "書き込み用ウィンドウ", IDM_WRITE MENUITEM "ツールバー", IDM_TOOL END POPUP "オプション(&O)" BEGIN MENUITEM "IDを表示する(&I)", IDM_ID MENUITEM SEPARATOR MENUITEM ".chtを関連づける(&R)", IDM_REG END END RTRAYMENU MENU DISCARDABLE BEGIN POPUP " ダミーです" BEGIN MENUITEM "タスクトレーから出す", IDM_SHOW MENUITEM "終了", IDM_END END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // MAILSLOTNAME DIALOG DISCARDABLE 0, 0, 118, 61 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "メールスロット名" FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT1,7,19,104,16,ES_AUTOHSCROLL DEFPUSHBUTTON "OK",IDOK,34,39,50,14 LTEXT "自分のメールスロットの名前",IDC_STATIC,7,7,83,8 END MYWRITE DIALOG DISCARDABLE 0, 0, 163, 153 STYLE DS_MODALFRAME | WS_CHILD FONT 9, "MS Pゴシック" BEGIN EDITTEXT IDC_EDIT3,70,23,86,14,ES_AUTOHSCROLL EDITTEXT IDC_EDIT2,70,44,86,14,ES_AUTOHSCROLL EDITTEXT IDC_EDIT1,7,69,149,56,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN DEFPUSHBUTTON "送信",IDOK,56,132,50,14 LTEXT "相手のメールスロット",IDC_STATIC,7,45,62,8 LTEXT "送信先コンピュータ",IDC_STATIC,7,25,56,8 CONTROL "他のコンピュータにメッセージを送る",IDC_CHECK1,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,7,119,10 END ///////////////////////////////////////////////////////////////////////////// // // Icon // MYICON ICON DISCARDABLE "myicon.ico"

メニューの「表示」に「ツールバー」が加わっただけです。

// mailslot09.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include "resource.h" #define MYMSG_TRAY WM_USER #define ID_MYEDIT 100 #define ID_MYTRAY 101 #define ID_TOOL1 102 #define ID_TOOL2 103 #define ID_REBAR 104 #define ID_STATIC 105 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyNameProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyWriteProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK MyEditProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); DWORD WINAPI ReadFunc(LPVOID); HANDLE MakeMySlot(HWND, BOOL *); void MyTaskTray(HWND, PNOTIFYICONDATA); int MakeRTrayMenu(HWND); int SaveAsMyFile(HWND); int OverWriteMyFile(HWND); int OpenMyFile(HWND); int OpenMyFile2(HWND); int MyReg(void); HWND MakeMyToolbar(HWND, int, TBBUTTON *, int); int MakeNewFile(HWND); int CheckMyMenu(HWND); BOOL CanPaste(HWND); char szClassName[] = "mailslot09"; //ウィンドウクラス char szMailSlot[128];//メールスロットの名前(フルパス付き) char szSlotName[64];//メールスロットの名前(パスなし) HANDLE hSlot; HINSTANCE hInst; HWND hMainEdit; BOOL bID = FALSE;//メッセージIDを表示するかどうか BOOL bIsTask = FALSE;//タスクトレーに格納されているかどうか HWND hWriteDlg;//書き込み用モードレスダイアログボックス int DlgX, DlgY;//書き込み用ダイアログの大きさ int RebarY;//レバーコントロールの高さ int ClientX, ClientY;//親ウィンドウのクライアント領域の大きさ BOOL bWriteDlg = FALSE;//書き込み用ダイアログが表示されいるかどうか char szFileName[MAX_PATH];//パス付きファイル名 char szFile[64];//ファイルタイトル BOOL bCmdLine;//コマンドライン引数があるかどうか WNDPROC Org_EditProc;//エディットコントロールのオリジナルプロシージャ HWND hTool1, hTool2; BOOL bTool = TRUE;//ツールバーが表示されているかどうか TBBUTTON tbButton1[] = { {STD_FILENEW, IDM_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_FILEOPEN, IDM_OPEN, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_FILESAVE, IDM_SAVE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0} }; TBBUTTON tbButton2[] = { {STD_COPY, IDM_COPY, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_CUT, IDM_CUT, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_PASTE, IDM_PASTE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_DELETE, IDM_DELETE, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0}, {STD_UNDO, IDM_UNDO, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0} };

ツールバーを2つに分けたのでIDも2つになりました。TBBUTTON構造体も 2つに分けました。

MakeMyToolbar関数の引数も変更しました。

WinMain, InitApp, InitInstanceの各関数に変更はありません。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static BOOL bEnd; static HANDLE hThread; static HMENU hMenu; MENUITEMINFO mi; static NOTIFYICONDATA ni; RECT rc; MINMAXINFO *lpmm; INITCOMMONCONTROLSEX ic; static HWND hRebar, hStatic; REBARINFO ri; REBARBANDINFO rbinfo; LPNMHDR lpnmhdr; switch (msg) { case WM_CREATE: ic.dwSize = sizeof(INITCOMMONCONTROLSEX); ic.dwICC = ICC_BAR_CLASSES | ICC_COOL_CLASSES; InitCommonControlsEx(&ic); hMenu = GetMenu(hWnd); hRebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_BANDBORDERS | RBS_VARHEIGHT, 0, 0, 0, 0, hWnd, (HMENU)ID_REBAR, hInst, NULL); GetWindowRect(hRebar, &rc); RebarY = rc.bottom - rc.top; hStatic = CreateWindow("STATIC", "", WS_CHILD | WS_VISIBLE | SS_SUNKEN, 0, 0, 0, 0, hWnd, (HMENU)ID_STATIC, hInst, NULL); hTool1 = MakeMyToolbar(hRebar, 3, tbButton1, ID_TOOL1); hTool2 = MakeMyToolbar(hRebar, 5, tbButton2, ID_TOOL2); if (!bCmdLine) { EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | MF_GRAYED); SendMessage(hTool1, TB_ENABLEBUTTON, (WPARAM)IDM_SAVE, (LPARAM)MAKELONG(FALSE, 0)); } hMainEdit = CreateWindow("EDIT", "", WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN | ES_NOHIDESEL | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_HSCROLL | WS_VSCROLL, 0, RebarY, 0, 0, hWnd, (HMENU)ID_MYEDIT, hInst, NULL); memset(&ri, 0, sizeof(REBARINFO)); memset(&rbinfo, 0, sizeof(REBARBANDINFO)); ri.cbSize = sizeof(REBARINFO); ri.fMask = 0; ri.himl = NULL; SendMessage(hRebar, RB_SETBARINFO, 0, (LPARAM)&ri); rbinfo.cbSize = sizeof(REBARBANDINFO); rbinfo.fMask = RBBIM_TEXT | RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; rbinfo.fStyle = RBBS_CHILDEDGE; rbinfo.lpText = "ファイル"; rbinfo.hwndChild = hTool1; rbinfo.cxMinChild = 0; rbinfo.cyMinChild = 25; GetWindowRect(hTool1, &rc); rbinfo.cx = 120; SendMessage(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbinfo); GetWindowRect(hRebar, &rc); rbinfo.lpText = "編集"; rbinfo.hwndChild = hTool2; rbinfo.cxMinChild = 0; rbinfo.cyMinChild = 25; rbinfo.cx = (rc.right - rc.left) - rbinfo.cx; SendMessage(hRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbinfo); Org_EditProc = (WNDPROC)GetWindowLong(hMainEdit, GWL_WNDPROC); SetWindowLong(hMainEdit, GWL_WNDPROC, (LONG)MyEditProc); DialogBox(hInst, "MAILSLOTNAME", hWnd, (DLGPROC)MyNameProc); bEnd = FALSE; hThread = MakeMySlot(hWnd, &bEnd); if (bCmdLine) { if (OpenMyFile2(hWnd) == 0) { EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | MF_ENABLED); SendMessage(hTool1, TB_ENABLEBUTTON, (WPARAM)IDM_SAVE, (LPARAM)MAKELONG(TRUE, 0)); } } SetFocus(hMainEdit); CheckMyMenu(hMainEdit); memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STATE; mi.fState = MFS_CHECKED; SetMenuItemInfo(hMenu, IDM_TOOL, FALSE, &mi); break; case WM_SIZE: ClientX = LOWORD(lp); ClientY = HIWORD(lp); MoveWindow(hStatic, 0, 0, ClientX, 2, TRUE); SendMessage(hRebar, WM_SIZE, wp, lp); if (bTool) { GetWindowRect(hRebar, &rc); RebarY = rc.bottom - rc.top; } if (!bWriteDlg) { MoveWindow(hMainEdit, 0, RebarY + 2, ClientX, ClientY - RebarY - 2, TRUE); } else { MoveWindow(hMainEdit, 0, RebarY + 2, ClientX - DlgX, ClientY - RebarY - 2, TRUE); MoveWindow(hWriteDlg, ClientX - DlgX, RebarY + 2, DlgX, ClientY - RebarY - 2, TRUE); } break; case WM_GETMINMAXINFO: lpmm = (MINMAXINFO *)lp; if (bWriteDlg) { lpmm->ptMinTrackSize.y = 281 + RebarY; lpmm->ptMinTrackSize.x = 450; return 0; } else if (bTool){ lpmm->ptMinTrackSize.y = 140; lpmm->ptMinTrackSize.x = 300; } else { return (DefWindowProc(hWnd, msg, wp, lp)); } break; case MYMSG_TRAY: if (wp == ID_MYTRAY) { switch (lp) { case WM_RBUTTONDOWN: MakeRTrayMenu(hWnd); break; case WM_LBUTTONDBLCLK: bIsTask = FALSE; Shell_NotifyIcon(NIM_DELETE, &ni); ShowWindow(hWnd, SW_SHOWNORMAL); default: break; } } break; case WM_NOTIFY: switch (wp) { case ID_REBAR: lpnmhdr = (LPNMHDR)lp; switch (lpnmhdr->code) { case RBN_HEIGHTCHANGE: if (bTool) { GetWindowRect(hRebar, &rc); RebarY = rc.bottom - rc.top; } MoveWindow(hMainEdit, 0, RebarY + 2, ClientX - DlgX, ClientY - RebarY - 2, TRUE); if (bWriteDlg) MoveWindow(hWriteDlg, ClientX - DlgX, RebarY + 2, DlgX, ClientY - RebarY - 2, TRUE); GetWindowRect(hWnd, &rc); MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); break; } break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_WRITE: if (!IsWindow(hWriteDlg)) { hWriteDlg = CreateDialog(hInst, "MYWRITE", hWnd, (DLGPROC)MyWriteProc); if (hWriteDlg != NULL) { bWriteDlg = TRUE; ShowWindow(hWriteDlg, SW_SHOW); GetWindowRect(hWriteDlg, &rc); DlgX = rc.right - rc.left; DlgY = rc.bottom - rc.top; MoveWindow(hWriteDlg, ClientX - DlgX, RebarY + 2, DlgX, ClientY - RebarY - 2, TRUE); MoveWindow(hMainEdit, 0, RebarY + 2, ClientX - DlgX, ClientY - RebarY - 2, TRUE); memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STATE; mi.fState = MFS_CHECKED; SetMenuItemInfo(hMenu, IDM_WRITE, FALSE, &mi); GetWindowRect(hWnd, &rc); MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); } else { MessageBox(hWnd, "ダイアログボックス作成失敗です", "Error", MB_OK); return 0; } } else { DestroyWindow(hWriteDlg); bWriteDlg = FALSE; MoveWindow(hMainEdit, 0, RebarY + 2, ClientX, ClientY - RebarY - 2, TRUE); memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STATE; mi.fState = MFS_UNCHECKED; SetMenuItemInfo(hMenu, IDM_WRITE, FALSE, &mi); DlgX = 0; DlgY = 0; } break; case IDM_TOOL: memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STATE; if (bTool) { ShowWindow(hRebar, SW_HIDE); RebarY = 0; bTool = FALSE; mi.fState = MFS_UNCHECKED; SetMenuItemInfo(hMenu, IDM_TOOL, FALSE, &mi); GetWindowRect(hWnd, &rc); MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom- rc.top + 1, TRUE); } else { ShowWindow(hRebar, SW_SHOW); GetWindowRect(hRebar, &rc); RebarY = rc.bottom - rc.top; bTool = TRUE; mi.fState = MFS_CHECKED; SetMenuItemInfo(hMenu, IDM_TOOL, FALSE, &mi); GetWindowRect(hWnd, &rc); SendMessage(hWnd, WM_SIZE, (WPARAM)SIZE_RESTORED, 0); MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top - 1, TRUE); } break; case IDM_NEW: MakeNewFile(hWnd); EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | MF_GRAYED); SendMessage(hTool1, TB_ENABLEBUTTON, (WPARAM)IDM_SAVE, (LPARAM)MAKELONG(FALSE, 0)); CheckMyMenu(hMainEdit); break; case IDM_OPEN: if (OpenMyFile(hWnd) == 0) { EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | MF_ENABLED); SendMessage(hTool1, TB_ENABLEBUTTON, (WPARAM)IDM_SAVE, (LPARAM)MAKELONG(TRUE, 0)); } break; case IDM_SAVE: OverWriteMyFile(hWnd); break; case IDM_SAVEAS: SaveAsMyFile(hWnd); break; case IDM_ID: memset(&mi, 0, sizeof(MENUITEMINFO)); mi.cbSize = sizeof(MENUITEMINFO); mi.fMask = MIIM_STATE; if (!bID) { mi.fState = MFS_CHECKED; SetMenuItemInfo(hMenu, IDM_ID, FALSE, &mi); bID = TRUE; break; } else { mi.fState = MFS_UNCHECKED; SetMenuItemInfo(hMenu, IDM_ID, FALSE, &mi); bID = FALSE; } break; case IDM_TASK: MyTaskTray(hWnd, &ni); ShowWindow(hWnd, SW_HIDE); bIsTask = TRUE; break; case IDM_SHOW: Shell_NotifyIcon(NIM_DELETE, &ni); ShowWindow(hWnd, SW_SHOWNORMAL); bIsTask = FALSE; break; case IDM_REG: MyReg(); break; case IDM_COPY: SendMessage(hMainEdit, WM_COPY, 0, 0); CheckMyMenu(hMainEdit); break; case IDM_CUT: SendMessage(hMainEdit, WM_CUT, 0, 0); CheckMyMenu(hMainEdit); break; case IDM_PASTE: SendMessage(hMainEdit, WM_PASTE, 0, 0); break; case IDM_ALL: SendMessage(hMainEdit, EM_SETSEL, 0, -1); CheckMyMenu(hMainEdit); break; case IDM_DELETE: SendMessage(hMainEdit, WM_CLEAR, 0, 0); CheckMyMenu(hMainEdit); break; case IDM_UNDO: if (SendMessage(hMainEdit, EM_CANUNDO, 0, 0)) SendMessage(hMainEdit, WM_UNDO, 0, 0); CheckMyMenu(hMainEdit); break; } break; case WM_CLOSE: if (SendMessage(hMainEdit, EM_GETMODIFY, 0, 0)) { id = MessageBox(hWnd, "チャットの内容が更新されています。\n" "保存せずに終了しますか", "確認", MB_YESNO | MB_ICONQUESTION); if (id == IDNO) break; } id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if (hThread) { bEnd = TRUE; WaitForSingleObject(hThread, INFINITE); if (CloseHandle(hThread)) MessageBox(hWnd, "hThreadをクローズしました", "OK", MB_OK); } if (hSlot) { if (CloseHandle(hSlot)) MessageBox(hWnd, "メールスロットを削除しました", "OK", MB_OK); } if (bIsTask) Shell_NotifyIcon(NIM_DELETE, &ni); SetWindowLong(hMainEdit, GWL_WNDPROC, (LONG)Org_EditProc); DestroyWindow(hStatic); DestroyWindow(hMainEdit); DestroyWindow(hTool1); DestroyWindow(hTool2); DestroyWindow(hRebar); if (hWriteDlg) DestroyWindow(hWriteDlg); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

メインウィンドウのプロシージャです。

WM_CREATEメッセージが来たらいろいろな初期設定などをします。

レバーコントロールを使うのでINITCOMMONCONTROLSEX構造体のメンバが少し変更に なっています。レバーコントロール、スタティックコントロールの作り方は 特に問題ないと思います。最初にもちょっと書きましたがコモンコントロールのスタイルは くせ者です。いろいろ試行錯誤で試してみないとわからない部分が多いです。

WM_SIZEメッセージが来たら、スタティックコントロール、レバーコントロール、エディットコントロール、 書き込み用ダイアログの位置、大きさを調整します。

WM_GETMINMAXINFOメッセージが来た時の処理を少し変えました。 ツールバーが表示されているときはこれが隠れてしまうような大きさまで、メインウィンドウが 縮まらないようにしました。また、レバーコントロールの高さも考慮している点に注意して ください。

さて、レバーコントロールで一番やっかいなのは、ユーザーがレバーコントロールを ドラッグして複数行にするなど、その高さを変えてしまうことです。レバーコントロールの 高さが変わったときはRBN_HEIGHTCHANGE通知メッセージが来るので、これを 処理しなくてはいけません。 この通知メッセージの解説は第183章にありますので 参照してみてください。

さて、このメッセージが来たときにレバーコントロールの高さをグローバル変数に 格納してエディットコントロールや、ダイアログの位置大きさを調整します。 その後で親ウィンドウの大きさを調べて、MoveWindowしています。実際には 元の位置、大きさにしているのでウィンドウの見た目は変化がありません。 じつは、これを行うことによりWM_GETMINMAXINFOメッセージを出させて 親ウィンドウの最小の大きさを調整しているのです。 もし、この2行がないと書き込み用ダイアログが出ている状態で、レバーコントロールを 2行にした場合ダイアログの一部が欠けてしまいます。

メニューからIDM_WRITEが選択された時もWM_GETMINMAXINFOメッセージを出させるために 同様の処理をしています。

メニューからIDM_TOOLが選択されたら、いままでツールバーが見えていれば これをShowWindow関数で見えなくします。ツールバーが見えていなければ 見えるようにします。この時エディットコントロールや書き込み用ダイアログの 位置、大きさを調整しなくてはいけませんが面倒なので、WM_SIZEメッセージを 出させるようにしました。こうするとWM_SIZEメッセージのところで調整を してくれるので楽です。そのために親ウィンドウの大きさを少しだけ大きくしたり 小さくしたりしています。

ツールバーのウィンドウハンドルが変更になっているのでIDM_NEWや、IDM_OPENが 来たときのボタンの使用可否のコードがほんの少し変更になっています(hToolがhTool1)。

プログラム終了時にスタティックコントロールなどを破棄します。

MakeMySlot, MyNameProc, MyWriteProc, ReadFunc, MyTaskTray, MakeRTrayMenu, MakeNewFileの各関数に変更はありません。

int SaveAsMyFile(HWND hWnd) { OPENFILENAME ofn; HANDLE hFile; HGLOBAL hMem; DWORD dwAccBytes; char szWinTitle[64], *szTitle_org = "猫でもわかるメールスロット[%s][%s]"; char *lpszBuf; int nLen; HMENU hMenu; nLen = GetWindowTextLength(hMainEdit); hMem = GlobalAlloc(GHND, nLen + 1); if (hMem == NULL) { MessageBox(hWnd, "メモリの確保に失敗しました", "Error", MB_OK); return -1; } lpszBuf = (char *)GlobalLock(hMem); GetWindowText(hMainEdit, lpszBuf, nLen + 1); memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFilter = "chat(*.cht)\0*.cht\0text(*.txt)\0*.txt\0All files(*.*)\0*.*\0\0"; ofn.lpstrFile = szFileName; ofn.lpstrFileTitle = szFile; ofn.nFilterIndex = 1; ofn.nMaxFile = sizeof(szFileName); ofn.nMaxFileTitle = sizeof(szFile); ofn.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; ofn.lpstrDefExt = "cht"; ofn.lpstrTitle = "チャットを名前を付けて保存する"; if(GetSaveFileName(&ofn) == 0) return -1; hFile = CreateFile(szFileName, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); WriteFile(hFile, lpszBuf, strlen(lpszBuf) + 1, &dwAccBytes, NULL); SetEndOfFile(hFile); wsprintf(szWinTitle, szTitle_org, szSlotName, szFile); SetWindowText(hWnd, szWinTitle); if(CloseHandle(hFile) == 0) MessageBox(hWnd, "Error CloseHandle", "Error", MB_OK); if (GlobalUnlock(hMem) != 0) MessageBox(hWnd, "ロックカウントが0ではありません", "Warning", MB_OK); if (GlobalFree(hMem) != NULL) MessageBox(hWnd, "メモリ解放失敗に失敗しました", "Error", MB_OK); SendMessage(hMainEdit, EM_SETMODIFY, FALSE, 0); hMenu = GetMenu(hWnd); EnableMenuItem(hMenu, IDM_SAVE, MF_BYCOMMAND | MF_ENABLED); SendMessage(hTool1, TB_ENABLEBUTTON, (WPARAM)IDM_SAVE, (LPARAM)MAKELONG(TRUE, 0)); return 0; }

この関数もほとんど変更はありませんが、最後のボタンの使用可否の変更で TB_ENABLEBUTTONメッセージをhToolではなく、hTool1に送っています。

OverWriteMyFile, OpenMyFile, OpenMyFile2の各関数に変更はありません。

int MyReg() { HKEY hKey; DWORD dwDisposition; LONG lResult; char szCommand[MAX_PATH]; char szIcon[MAX_PATH]; GetCurrentDirectory(sizeof(szCommand), szCommand); strcat(szCommand, "\\"); strcat(szCommand, szClassName); strcat(szCommand, " %1"); GetCurrentDirectory(sizeof(szIcon), szIcon); strcat(szIcon, "\\"); strcat(szIcon, szClassName); strcat(szIcon, ".exe,0"); lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, "MyChat\\shell\\猫チャット(&C)\\command", NULL,//予約済み "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition); if (lResult != ERROR_SUCCESS) { MessageBox(NULL, "RegCreateKeyExでエラーが発生しました", "Error", MB_OK); return -1; } lResult = RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)szCommand, strlen(szCommand)); RegCloseKey(hKey); lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, ".cht", NULL, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition); if (lResult != ERROR_SUCCESS) { MessageBox(NULL, "RegCreateKeyExでエラーが発生しました", "Error", MB_OK); return -1; } lResult = RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)"MyChat", strlen("MyChat")); RegCloseKey(hKey); lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, "MyChat\\DefaultIcon", NULL, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition); if (lResult != ERROR_SUCCESS) { MessageBox(NULL, "RegCreateKeyExでエラーが発生しました", "Error", MB_OK); return -1; } lResult = RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)szIcon, strlen(szIcon)); RegCloseKey(hKey); return 0; }

このプログラムのバージョン(?)が変わるたびに プログラム名が変わります(mailslot01.exe, mailslot02.exe, ....)。そのたびにこの関数も いちいち変更するのは面倒です。そこで、ウィンドウクラス名を流用しています。

HWND MakeMyToolbar(HWND hWnd, int n, TBBUTTON *tbButton, int id) { HWND hTool; TBADDBITMAP tbab; int stdid, i; hTool = CreateToolbarEx(hWnd, WS_VISIBLE | WS_CHILD| CCS_NODIVIDER | CCS_NORESIZE | TBSTYLE_FLAT, id , 0, NULL, NULL, tbButton, 0, 0, 0, 0, 0, sizeof(TBBUTTON)); tbab.hInst = HINST_COMMCTRL; tbab.nID = IDB_STD_SMALL_COLOR; stdid = SendMessage(hTool, TB_ADDBITMAP, n, (LPARAM)&tbab); for (i = 0; i < n; i++) tbButton[i].iBitmap += stdid; SendMessage(hTool, TB_ADDBUTTONS, n, (LONG)tbButton); SendMessage(hTool, TB_AUTOSIZE, 0, 0); return hTool; }

引数を変更して、少しだけ汎用性のあるものにしています。

int CheckMyMenu(HWND hWnd) { DWORD dwStart, dwEnd; HMENU hMenu; HWND hParent; hParent = GetParent(hWnd); hMenu = GetMenu(hParent); if (Edit_GetTextLength(hWnd) == 0) { EnableMenuItem(hMenu, IDM_ALL, MF_BYCOMMAND | MF_GRAYED); } else { EnableMenuItem(hMenu, IDM_ALL, MF_BYCOMMAND | MF_ENABLED); } SendMessage(hMainEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd); if (dwStart == dwEnd) { EnableMenuItem(hMenu, IDM_COPY, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | MF_GRAYED); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_COPY, (LPARAM)MAKELONG(FALSE, 0)); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_CUT, (LPARAM)MAKELONG(FALSE, 0)); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_DELETE, (LPARAM)MAKELONG(FALSE, 0)); } else { EnableMenuItem(hMenu, IDM_COPY, MF_BYCOMMAND | MF_ENABLED); EnableMenuItem(hMenu, IDM_CUT, MF_BYCOMMAND | MF_ENABLED); EnableMenuItem(hMenu, IDM_DELETE, MF_BYCOMMAND | MF_ENABLED); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_COPY, (LPARAM)MAKELONG(TRUE, 0)); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_CUT, (LPARAM)MAKELONG(TRUE, 0)); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_DELETE, (LPARAM)MAKELONG(TRUE, 0)); } if (SendMessage(hMainEdit, EM_GETMODIFY, 0, 0)) { EnableMenuItem(hMenu, IDM_UNDO, MF_BYCOMMAND | MF_ENABLED); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_UNDO, (LPARAM)MAKELONG(TRUE, 0)); } else { EnableMenuItem(hMenu, IDM_UNDO, MF_BYCOMMAND | MF_GRAYED); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_UNDO, (LPARAM)MAKELONG(FALSE, 0)); } if (CanPaste(hParent)) { EnableMenuItem(hMenu, IDM_PASTE, MF_BYCOMMAND | MF_ENABLED); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_PASTE, (LPARAM)MAKELONG(TRUE, 0)); } else { EnableMenuItem(hMenu, IDM_PASTE, MF_BYCOMMAND | MF_GRAYED); SendMessage(hTool2, TB_ENABLEBUTTON, (WPARAM)IDM_PASTE, (LPARAM)MAKELONG(FALSE, 0)); } return 0; }

「削除」ボタンが増えたのと、ツールバーが2つになったので少しずつ変更になっています。

MyEditProc, CanPasteの各関数に変更はありません。

今回も特に目新しいことはありませんでした。あと、ステータスバーをつけたり、 いろいろ見栄えをよくしてみてください。
[SDK第3部 Index] [総合Index] [Previous Chapter] [Next Chapter]

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