ツールバー

ツールバー1

ツールバーのボタンを、既成のボタンにします。リッチエディットに付けます。

ファイルの読み書き2:コモンダイアログ - インコのWindowsSDK で作成したソースを修正します。
ツールバー2: ボタンにビットマップを貼り付ける - インコのWindowsSDK で作成したソースから流用します。

流れ

1.TBBUTTON(ツールバーボタン)型の配列を作成
ビットマップのインデックスは、既成のボタンにする場合は、次のようにする

ビットマップのインデックスビットマップ
STD_FILEOPENファイルを開く
STD_FILESAVEファイルを保存する
STD_COPYコピー
STD_CUT切り取り
STD_DELETE削除
STD_PASTE貼り付け
STD_REDOWやり直し
STD_UNDO元に戻す

2.TBADDBITMAP構造体に ツールバーに追加するためのビットマップの情報をセットする

typedef struct {
    HINSTANCE hInst;  // モジュールのインスタンスハンドル
    UINT nID;         // リソースIDまたはビットマップハンドル
} TBADDBITMAP, *LPTBADDBITMAP;

WM_CREATE

1.1.メンバ hInstに、 システム定義のボタンのビットマップ[HINST_COMMCTRL]をセット。
1.2.メンバ nIDに、 システム標準ビットマップ(小)[IDB_STD_SMALL_COLOR]をセット。

2.TB_ADDBITMAPメッセージでツールバーに追加するための ビットマップの情報を格納

lResult = SendMessage(
    (HWND) hWndControl, // ツールバーのハンドル
    (UINT) TB_ADDBITMAP,
    (WPARAM) wParam,    // ビットマップに含まれるボタンイメージの数
                        //  システム定義のビットマップを指定した場合は無視
    (LPARAM) lParam     // TBADDBITMAP構造体
);

3.LoadString で、文字列リソース(IDC_BUTTON1など)をロードし、バッファ(szBuf)へコピーし、 TB_ADDSTRING で文字列のリストに文字列を追加。
( ツールバー1: 文字だけのフラットツールバー を参照。)

WM_SIZE

1.WM_SIZEで、ツールバーの高さだけ、リッチエディットのy座標を変えます。
※これを忘れると、ツールバーが表示されなくなります。

TB_AUTOSIZEメッセージを送信します。
※これを忘れると、ウインドウサイズを初期値よりも大きくした場合、大きくした箇所のツールバーが表示されなくなります。

WM_COMMAND

1.WM_COMMANDで、メニューを選択されたときの動作を入れます。

ソースコードの入力

ソースコードは下記のように入れてください。

test.cpp
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"

#define TEXTMAX 10000
#define TOOLBAR_BOTTON 8

#pragma comment(lib, "comctl32.lib")      // ツールバーの作成に必要

// グローバル変数:
HINSTANCE hInst;                          // 現在のインターフェイス
HWND hToolBar;        // ツールバーのウィンドウハンドル
WNDPROC defProc;

// TBBUTTON(ツールバーボタン)型の配列
TBBUTTON tbButton[] = {
  { STD_FILEOPEN, ID_BUTTON1, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
  { STD_FILESAVE, ID_BUTTON2, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
  { STD_COPY,     ID_BUTTON3, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
  { STD_CUT,      ID_BUTTON4, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
  { STD_DELETE,   ID_BUTTON5, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
  { STD_PASTE,    ID_BUTTON6, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
  { STD_REDOW,    ID_BUTTON7, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0},
  { STD_UNDO,     ID_BUTTON8, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, 0, 0, 0}
};
TBBUTTON tbSPACE = {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0L};

// リッチエディットの使用するために用いる変数宣言
TCHAR strPath[MAX_PATH + 1];    // DLLのパス
HINSTANCE hRtLib;               // インスタンスハンドル
HWND hRichEdit;                 // ウィンドウハンドル

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
DWORD CALLBACK MySaveProc(DWORD, LPBYTE, LONG, LONG *);
DWORD CALLBACK MyReadProc(DWORD, LPBYTE, LONG, LONG *);
LRESULT CALLBACK ToolbarProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR lpCmdLine,
                     int nCmdShow)
{
    MSG msg;
    MyRegisterClass(hInstance);

    // アプリケーションの初期化を実行します:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }
    // メイン メッセージ ループ:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return (int) msg.wParam;
}

//
//  関数: MyRegisterClass()
//
//  目的: ウィンドウ クラスを登録します。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(NULL , IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName = MAKEINTRESOURCE(IDC_HP);
    wcex.lpszClassName = TEXT("HP");
    wcex.hIconSm = LoadIcon(NULL , IDI_APPLICATION);

    return RegisterClassEx(&wcex);
}

//
//   関数: InitInstance(HINSTANCE, int)
//
//   目的: メイン ウィンドウを作成します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // グローバル変数にインスタンス処理を格納します。

   hWnd = CreateWindow(TEXT("HP"), TEXT("HP"), WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:  メイン ウィンドウのメッセージを処理します。
//
//  WM_CREATE  - ウインドウ作成時の処理
//  WM_SIZE    - ウインドウサイズ変更時の処理
//  WM_COMMAND - アプリケーション メニューの処理
//  WM_DESTROY - 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    OPENFILENAME of; // OPENFILENAME構造体
    TCHAR szText[TEXTMAX] = TEXT("");
    static TCHAR szFile[MAX_PATH] = TEXT("");
    HANDLE hFile;
    EDITSTREAM eds; // EDITSTREAM構造体
    int wmax;
    int iString[TOOLBAR_BOTTON];
    TCHAR szBuf[128];
    static UINT uToolStyle;
    UINT i; 
    TBADDBITMAP tb; 

    switch (message)
    {
        case WM_CREATE:
            InitCommonControls();
            wmax = GetSystemMetrics(SM_CXSCREEN);
            hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
            hToolBar = CreateWindowEx(
                0,                          // 拡張スタイルなし
                TOOLBARCLASSNAME,           // クラスネーム
                NULL,                       // ウィンドウタイトル
                WS_CHILD | WS_VISIBLE,      // ウィンドウスタイル
                0, 0,                       // ウィンドウ位置
                wmax, 40,                   // ウィンドウ幅、高さ
                hWnd,                       // 親ウィンドウ
                (HMENU)IDW_TOOL,            // コントロール識別子
                hInst,                      // インスタンスハンドル
                NULL);
            tb.hInst = HINST_COMMCTRL;    // ボタンをシステム定義のビットマップ
            tb.nID = IDB_STD_SMALL_COLOR; // システム標準ビットマップ(小)
            SendMessage(hToolBar, TB_ADDBITMAP, 0, (LPARAM)&tb); 

            SendMessage(hToolBar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
            for(i = 0; i < TOOLBAR_BOTTON; i++)
            {
                LoadString(hInst, tbButton[i].idCommand, (LPTSTR)&szBuf, sizeof(szBuf) - 1);
                iString[i] = SendMessage(hToolBar, TB_ADDSTRING, 0, (LPARAM)szBuf);
                tbButton[i].iString = iString[i];
            }

            /* ツールバーにボタンを挿入 */
            SendMessage(hToolBar, TB_ADDBUTTONS, (WPARAM)TOOLBAR_BOTTON, (LPARAM)(LPTBBUTTON)&tbButton);
            // ボタンの区切りを挿入
            SendMessage(hToolBar, TB_INSERTBUTTON, 2, (LPARAM)&tbSPACE);

            /* ツールバーサブクラス化 */
            defProc = (WNDPROC)GetWindowLong(hToolBar, GWL_WNDPROC);
            SetWindowLong(hToolBar, GWL_WNDPROC, (LONG)ToolbarProc);
            SetWindowLong(hToolBar, GWL_USERDATA, (LONG)defProc);

            /* フラットツールバー */
            uToolStyle = (UINT)GetWindowLong(hToolBar, GWL_STYLE);
            uToolStyle |= (TBSTYLE_FLAT);
            SetWindowLong(hToolBar, GWL_STYLE, (LONG)uToolStyle);
            SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);
            InvalidateRect(hToolBar, NULL, TRUE);

            // DLLのロード
            GetSystemDirectory(strPath , MAX_PATH + 1);
            wsprintf(strPath, TEXT("%s\\%s"), strPath, TEXT("RICHED20.DLL"));
            hRtLib = LoadLibrary((LPCTSTR)strPath);

            hRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE, // 拡張ウィンドウスタイル
                TEXT("RichEdit20A"), // 登録されているクラス名
                TEXT(""),            // ウィンドウ名
                WS_CHILD             // 子ウィンドウを作成
                | WS_VISIBLE         // 初期状態で可視のウィンドウを作成
                | WS_BORDER          // 境界を持つウィンドウを作成
                | ES_MULTILINE       // 複数行入力
                | WS_HSCROLL         // 水平スクロールバーを持つウィンドウ
                | WS_VSCROLL         // 垂直スクロール バーを持つウィンドウ
                | ES_AUTOVSCROLL     // 自動縦スクロール(ES_MULTILINE のときのみ有効)
                | ES_NOHIDESEL,      // 選択されているテキストは、コントロールが...
                                     //  フォーカス持っていない場合も反転表示
                0,                   // ウィンドウの横方向の位置
                0,                   // ウィンドウの縦方向の位置
                0,                   // ウィンドウの幅
                0,                   // ウィンドウの高さ
                hWnd,                // 親ウィンドウまたはオーナーウィンドウのハンドル
                (HMENU)IDC_RICHEDIT, // メニューハンドルまたは子識別子
                hInst,               // アプリケーションインスタンスのハンドル
                NULL);               // ウィンドウ作成データ

            break;

        case WM_SIZE:
            MoveWindow(hToolBar, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
            MoveWindow(hRichEdit, 0, 40, LOWORD(lParam), HIWORD(lParam), TRUE);
            break;

        case WM_COMMAND:
            wmId = LOWORD(wParam);
            wmEvent = HIWORD(wParam);
            // 選択されたメニューの解析:
            switch (wmId)
            {
                case IDM_OPEN:
                case ID_BUTTON1:
                    // OPENFILENAME構造体のサイズをセット
                    memset(&of, 0, sizeof(OPENFILENAME));
                    of.lStructSize = sizeof(OPENFILENAME);
                    // ダイアログボックスを所有するウィンドウへのハンドル
                    of.hwndOwner = hRichEdit;
                    of.lpstrFilter = TEXT("TEXT(*.txt)\0 *.txt\0RTF(*.rtf)\0 *.rtf\0\0");
                    // ファイル名を格納したバッファのアドレス
                    of.lpstrFile = (LPTSTR)szFile; 
                    // lpstrFileメンバで指定されるバッファのサイズ
                    of.nMaxFile = MAX_PATH;
                    // ダイアログボックスの初期化に使用されるビットフラグ
                    // OFN_PATHMUSTEXIST:ユーザーが有効なパス
                    //  およびファイル名のみを入力できるように指定
                    of.Flags = OFN_PATHMUSTEXIST;
                    // デフォルトの拡張子を格納したバッファのアドレス
                    of.lpstrDefExt = TEXT("txt");
                    // コモンダイアログの表示
                    GetOpenFileName( &of );
                    hFile = CreateFile(szFile, // ファイル名
                        GENERIC_READ,          // アクセス指定 GENERIC_READ:読み取り
                        0,                     // 共有方法 0:共有しない
                        NULL,                  // セキュリティ属性 0:デフォルト
                        OPEN_EXISTING,         // 動作指定 OPEN_EXISTING:ファイルをオープン。
                                               //  ファイルが存在していない場合、
                                               //  関数が失敗
                        FILE_ATTRIBUTE_NORMAL, // フラグと属性
                                               // FILE_ATTRIBUTE_NORMAL:属性設定なし
                        NULL);                 // テンプレートファイル
                    if (hFile != INVALID_HANDLE_VALUE)
                    {
                        eds.dwCookie = (DWORD)hFile; // ファイルハンドルを渡す
                        eds.dwError = 0; // 読み込み操作の結果 0はエラーなし
                        eds.pfnCallback = MyReadProc; // コールバック関数アドレス
                        SendMessage(hRichEdit,
                            EM_STREAMIN,   // 読み込み
                            SF_TEXT,       // テキスト形式
                            (LPARAM)&eds); // EDITSTREAM 構造体のアドレス
                        SendMessage(hRichEdit,
                            EM_SETMODIFY,  // エディットコントロールの変更フラグを設定または解除
                            (WPARAM)FALSE, // 解除
                            0);
                        CloseHandle(hFile);
                        // ウインドウタイトルをファイル名にする
                        SetWindowText(hWnd, (LPCTSTR)szFile);
                        // メニューの選択可
                        EnableMenuItem(GetMenu(hWnd), IDM_SAVE, MF_ENABLED);
                    }
                    break;
                case IDM_SAVE:
                case ID_BUTTON2:
                    hFile = CreateFile(szFile,    // ファイル名
                        GENERIC_WRITE,            // アクセス指定 GENERIC_WRITE:書き込み
                        0,                        // 共有方法 0:共有しない
                        NULL,                     // セキュリティ属性 0:デフォルト
                        OPEN_ALWAYS,              // 動作指定 OPEN_ALWAYS:ファイルをオープン。
                                                  //  ファイルが存在していない場合、
                                                  //  新しいファイルを作成
                        FILE_ATTRIBUTE_NORMAL     // フラグと属性
                                                  //  FILE_ATTRIBUTE_NORMAL:属性設定なし
                        | FILE_FLAG_WRITE_THROUGH,// データをそのまま直接ディスクに書き込む
                        NULL);                    // テンプレートファイル
                    eds.dwCookie = (DWORD)hFile; // ファイルハンドルを渡す
                    eds.dwError = 0; // 書き込み操作の結果 0はエラーなし
                    eds.pfnCallback = MySaveProc; // コールバック関数アドレス
                    SendMessage(hRichEdit,
                        EM_STREAMOUT,    // 書き込み
                        (WPARAM)SF_TEXT, // テキスト形式
                        (LPARAM)&eds); // EDITSTREAM 構造体のアドレス
                    SendMessage(hRichEdit,
                        EM_SETMODIFY,  // エディットコントロールの変更フラグを設定または解除
                        (WPARAM)FALSE, // 解除
                        0);
                    CloseHandle(hFile);
                    break;
                case IDM_SAVE2:
                    // OPENFILENAME構造体のサイズをセット
                    memset(&of, 0, sizeof(OPENFILENAME));
                    of.lStructSize = sizeof(OPENFILENAME);
                    // ダイアログボックスを所有するウィンドウへのハンドル
                    of.hwndOwner = hRichEdit;
                    of.lpstrFilter = TEXT("TEXT(*.txt)\0 *.txt\0RTF(*.rtf)\0 *.rtf\0\0");
                    // ファイル名を格納したバッファのアドレス
                    of.lpstrFile = (LPTSTR)szFile; 
                    // lpstrFileメンバで指定されるバッファのサイズ
                    of.nMaxFile = MAX_PATH;
                    of.Flags = OFN_OVERWRITEPROMPT;
                    // デフォルトの拡張子を格納したバッファのアドレス
                    of.lpstrDefExt = TEXT("txt");
                    // コモンダイアログの表示
                    GetSaveFileName( &of );
                    hFile = CreateFile(szFile,    // ファイル名
                        GENERIC_WRITE,            // アクセス指定 GENERIC_WRITE:書き込み
                        0,                        // 共有方法 0:共有しない
                        NULL,                     // セキュリティ属性 0:デフォルト
                        OPEN_ALWAYS,              // 動作指定 OPEN_ALWAYS:ファイルをオープン。
                                                  //  ファイルが存在していない場合、
                                                  //  新しいファイルを作成
                        FILE_ATTRIBUTE_NORMAL     // フラグと属性
                                                  //  FILE_ATTRIBUTE_NORMAL:属性設定なし
                        | FILE_FLAG_WRITE_THROUGH,// データをそのまま直接ディスクに書き込む
                        NULL);                    // テンプレートファイル
                    eds.dwCookie = (DWORD)hFile; // ファイルハンドルを渡す
                    eds.dwError = 0; // 書き込み操作の結果 0はエラーなし
                    eds.pfnCallback = MySaveProc; // コールバック関数アドレス
                    SendMessage(hRichEdit,
                        EM_STREAMOUT,    // 書き込み
                        (WPARAM)SF_TEXT, // テキスト形式
                        (LPARAM)&eds); // EDITSTREAM 構造体のアドレス
                    SendMessage(hRichEdit,
                        EM_SETMODIFY,  // エディットコントロールの変更フラグを設定または解除
                        (WPARAM)FALSE, // 解除
                        0);
                    CloseHandle(hFile);
                    break;
                case ID_BUTTON3:
                    SendMessage(hRichEdit, WM_COPY, 0, 0);
                    break;
                case ID_BUTTON4:
                    SendMessage(hRichEdit, WM_CUT, 0, 0);
                    break;
                case ID_BUTTON5:
                    SendMessage(hRichEdit, WM_CLEAR, 0, 0);
                    break;
                case ID_BUTTON6:
                    SendMessage(hRichEdit, WM_PASTE, 0, 0);
                    break;
                case ID_BUTTON7:
                    SendMessage(hRichEdit, EM_REDO, 0, 0);
                    break;
                case ID_BUTTON8:
                    SendMessage(hRichEdit, EM_UNDO, 0, 0);
                    break;
                case IDM_EXIT:
                    DestroyWindow(hWnd);
                    break;
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
            }
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    return 0;
}

DWORD CALLBACK MySaveProc(DWORD dwCookie, LPBYTE pbbuf, LONG cb, LONG *pcb)
{
    if (WriteFile((HANDLE)dwCookie, pbbuf, cb, (LPDWORD)pcb, NULL))
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

DWORD CALLBACK MyReadProc(DWORD dwCookie, LPBYTE pbBuf, LONG cb, LONG *pcb)
{
    ReadFile((HANDLE)dwCookie, pbBuf, cb, (LPDWORD)pcb, NULL);
    return(FALSE);
}


/* ツールバーサブクラス */
LRESULT CALLBACK ToolbarProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_RBUTTONDOWN:
        case WM_RBUTTONUP:
            if (SendMessage(hWnd, TB_GETHOTITEM, 0, 0) >= 0)
            {
                ReleaseCapture();
            }
            return 0;
    }
    return CallWindowProc(defProc, hWnd, msg, wParam, lParam);
}

上記の太線で示している箇所は追加で、 文字で示している箇所は、 ツールバー2: ボタンにビットマップを貼り付ける - インコのWindowsSDK からの流用です。

resource.h
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDM_SAVE 110
#define IDM_SAVE2 112
#define IDM_OPEN 111
#define IDC_HP 109
#define IDC_RICHEDIT 101
#define IDW_TOOL 150
#define ID_BUTTON1 151
#define ID_BUTTON2 152
#define ID_BUTTON3 153
#define ID_BUTTON4 154
#define ID_BUTTON5 155
#define ID_BUTTON6 156
#define ID_BUTTON7 157
#define ID_BUTTON8 158

上記の太線で示している箇所は追加で、 文字で示している箇所は、 ツールバー2: ボタンにビットマップを貼り付ける - インコのWindowsSDK からの流用です。

test.rc リソースファイル
#include "resource.h"

/////////////////////////////////////////////////////////////////////////////
//
// メニュー
//

IDC_HP MENU
BEGIN
    POPUP "ファイル(&F)"
    BEGIN
        MENUITEM "開く(&O)", IDM_OPEN
        MENUITEM "上書き保存(&S)", IDM_SAVE
        MENUITEM "名前を付けて保存(&A)", IDM_SAVE2
        MENUITEM "アプリケーションの終了(&X)", IDM_EXIT
    END
    POPUP "ヘルプ(&H)"
    BEGIN
        MENUITEM "バージョン情報(&A)...", IDM_ABOUT
    END
END


/////////////////////////////////////////////////////////////////////////////
//
// ストリング テーブル
//

STRINGTABLE
BEGIN
   ID_BUTTON1   "開く"
   ID_BUTTON2   "保存"
   ID_BUTTON3   "コピー"
   ID_BUTTON4   "切り取り"
   ID_BUTTON5   "削除"
   ID_BUTTON6   "貼り付け"
   ID_BUTTON7   "やり直し"
   ID_BUTTON8   "元に戻す"
END

上記の太線で示している箇所は追加で、 文字で示している箇所は、 ツールバー2: ボタンにビットマップを貼り付ける - インコのWindowsSDK からの流用です。