メニュー・オーナードロー

メニューバーのオーナードロー1

前回までは、ポップアップメニューのオーナードローをしました。
今回は、メニューバーのオーナードローをします。

メニュー・オーナードロー2 - インコのWindowsSDK で作成したソースを修正します。

流れ

関数: MyRegisterClass()

WNDCLASSEX構造体のlpszMenuNameメンバをNULLにします。
これにより、メニューバーが表示されなくなります。
リソースも、メニューに関する箇所を削除します。

WM_CREATE

1.CreateMenu()でメニューを作成

2.CreatePopupMenu()で、ポップアップメニューを作成

3.MENUITEMINFO構造体をセット。
先に構造体を初期化しておきます。

4.MInsertMenuItem()で、メニューの項目を追加。

5.SetMenu()で、新しいメニューを指定されたウィンドウに割り当てます。

BOOL SetMenu(
    HWND  hWnd,    // ウィンドウハンドル
    HMENU hMenu    // メニューハンドル
);

ソースコードの入力

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

test.cpp
#define _WIN32_WINNT 0x0501

#include <windows.h>
#include "resource.h"

#define MENU_WIDTH_PLUS 5

// グローバル変数:
HINSTANCE hInst;                          // 現在のインターフェイス
HMENU hMenu;                              // メニューのハンドル
HMENU hSubMenu1;                          // メニューのハンドル
HMENU hSubMenu2;                          // メニューのハンドル
LPMEASUREITEMSTRUCT lpMI;                 // LPMEASUREITEMSTRUCT構造体
LPDRAWITEMSTRUCT lpDI;                    // DRAWITEMSTRUCT構造体

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, 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 = NULL;
    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_COMMAND - アプリケーション メニューの処理
//  WM_DESTROY - 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    HDC hdc;
    RECT rc;
    SIZE sz;
    LPCTSTR str[] = {TEXT("アプリケーションの終了(&X)"), TEXT("バージョン情報(&A)...")};
    NONCLIENTMETRICS NCMetrics;
    HFONT hFont, hFontOld;
    static LOGFONT g_menufont;
    static int g_icon_vx, g_icon_vy;
    static DWORD g_menu_backcolor;
    static DWORD g_menu_textcolor;
    static HICON hIcon;
    HBRUSH hBrush;
    MENUITEMINFO mi;

    switch (message)
    {
        case WM_CREATE:
            hMenu = CreateMenu();
            hSubMenu1 = CreatePopupMenu();
            hSubMenu2 = CreatePopupMenu();

            memset(&mi, 0, sizeof(MENUITEMINFO));
            mi.cbSize = sizeof(MENUITEMINFO);
            mi.fMask = MIIM_TYPE | MIIM_SUBMENU;
            mi.fType = MFT_STRING;
            mi.fState = MFS_ENABLED;
            mi.wID = 0;
            mi.hSubMenu = hSubMenu1;
            mi.dwTypeData = TEXT("ファイル(&F)");
            InsertMenuItem(hMenu, 0, TRUE, &mi);

            mi.wID = 1;
            mi.hSubMenu = hSubMenu2;
            mi.dwTypeData = TEXT("ヘルプ(&H)");
            InsertMenuItem(hMenu, 1, TRUE, &mi);

            // サブメニュー
            mi.fMask = MIIM_TYPE | MIIM_ID;
            mi.fType = MFT_STRING | MFT_OWNERDRAW;
            mi.wID = IDM_EXIT;
            InsertMenuItem(hSubMenu1, 0, TRUE, &mi);
            mi.wID = IDM_ABOUT;
            InsertMenuItem(hSubMenu2, 0, TRUE, &mi);

            SetMenu(hWnd, hMenu);

            NCMetrics.cbSize = sizeof(NONCLIENTMETRICS);
            SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS),
                                   &NCMetrics, 0);
            g_menufont = NCMetrics.lfMenuFont;
            g_icon_vx = (int)GetSystemMetrics(SM_CXSMICON);
            g_icon_vy = (int)GetSystemMetrics(SM_CYSMICON);
            hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_TEST));
            g_menu_backcolor = GetSysColor(COLOR_HIGHLIGHT);
            g_menu_textcolor = GetSysColor(COLOR_HIGHLIGHTTEXT);
            break;

        case WM_MEASUREITEM:
            lpMI = (LPMEASUREITEMSTRUCT)lParam;
            hdc = GetDC(hWnd);
            hFont = CreateFontIndirect(&g_menufont);
            hFontOld = (HFONT)SelectObject(hdc, hFont);
            GetTextExtentPoint32(hdc,
                str[lpMI->itemData],
                lstrlen(str[lpMI->itemData]) - 1,
                &sz);
            lpMI->itemWidth = sz.cx + g_icon_vx + MENU_WIDTH_PLUS;
            lpMI->itemHeight = sz.cy + 5;
            ReleaseDC(hWnd, hdc);
            break;

        case WM_DRAWITEM:
            lpDI = (LPDRAWITEMSTRUCT)lParam;
            rc = lpDI->rcItem;
            hdc = lpDI->hDC;
            hFont = CreateFontIndirect(&g_menufont);
            hFontOld = (HFONT)SelectObject(hdc, hFont);
            switch (lpDI->itemID)
            {
                case IDM_EXIT:
                    if (lpDI->itemState & ODS_SELECTED)
                    {
                        hBrush = CreateSolidBrush(g_menu_backcolor);
                        SetBkColor(hdc, g_menu_backcolor);
                        SetTextColor(hdc, g_menu_textcolor);
                    }
                    else
                    {
                        hBrush = CreateSolidBrush(GetBkColor(hdc));
                    }
                    FillRect(hdc, &rc, hBrush);
                    DeleteObject(hBrush);
                    DrawIconEx(hdc, rc.left, rc.top + 1, hIcon, g_icon_vx, g_icon_vy, 0,
                      NULL, DI_IMAGE | DI_MASK);
                    TextOut(hdc, rc.left + g_icon_vx + MENU_WIDTH_PLUS, rc.top + 2,
                              str[0], lstrlen(str[0]));
                    break;
                case IDM_ABOUT:
                    if (lpDI->itemState & ODS_SELECTED)
                    {
                        hBrush = CreateSolidBrush(g_menu_backcolor);
                        SetBkColor(hdc, g_menu_backcolor);
                        SetTextColor(hdc, g_menu_textcolor);
                    }
                    else
                    {
                        hBrush = CreateSolidBrush(GetBkColor(hdc));
                    }
                    FillRect(hdc, &rc, hBrush);
                    DeleteObject(hBrush);
                    DrawIconEx(hdc, rc.left, rc.top + 1, hIcon, g_icon_vx, g_icon_vy, 0,
                      NULL, DI_IMAGE | DI_MASK);
                    TextOut(hdc, rc.left + g_icon_vx + MENU_WIDTH_PLUS, rc.top + 2,
                              str[1], lstrlen(str[1]));
                    break;
            }
            SelectObject(hdc, hFontOld);
            DeleteObject(hFont);
            break;

        case WM_COMMAND:
            wmId = LOWORD(wParam);
            wmEvent = HIWORD(wParam);
            // 選択されたメニューの解析:
            switch (wmId)
            {
                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;
}

上記の太線で示している箇所を追加し、右クリックされたときにメニューを表示させる機能を削除しました。

resource.h
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_TEST 107
#define IDC_HP 109

未使用の変数を削除しました。

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

/////////////////////////////////////////////////////////////////////////////
//
// アイコン
//

IDI_TEST       ICON         "test.ico"

メニューを削除しました。