SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

デザイン性に優れた拡張メニューコントロール

LuxMenuで見栄えのよいメニューを作ろう

デザイン性に優れた拡張メニューコントロール 第1回


VC++でLuxMenuを実装する

 冒頭で説明したとおり、LuxMenuコントロールはABライブラリとは別に、COM DLLとしての提供も行っています。そこで、今回はVC++からの利用例を提示し、さまざまな言語環境でも、ABで開発されたLuxMenuコントロールが実装可能であることを証明したいと思います。

準備

 まずは、Win32プロジェクトを作成します(ここでは「LuxMenuTest」としています)。次に、EXEが生成されるディレクトリ(またはSystem32ディレクトリなど)に「LuxMenu.dll」をコピーします。

 リソーススクリプトを作成し、適当にアイコンリソース(16*16、24ビットフルカラー)を挿入していきます。ここでは、先ほどの解説と同様、IDI_OPEN、IDI_SAVE、IDI_OPTIONを使っていきます。

LuxMenu.hのコーディング

 ILuxMenuインターフェイスの定義を行います。基本的には、ABのソースコードをC++用に移植しただけなので、特筆すべき点はありません。

インターフェイスの定義
extern "C++"
{
class ILuxSubMenu;

class ILuxMenu:public IUnknown{
public:
    virtual void _stdcall ImportMenu(HMENU hMenu);
    virtual HMENU _stdcall GetMenuHandle(void);
    virtual BOOL _stdcall MeasureItem(LPARAM lParam);
    virtual BOOL _stdcall DrawItem(LPARAM lParam);

    virtual BOOL _stdcall CreateItem(void);
    virtual BOOL _stdcall EnableItem(DWORD itemIDorPosition,
        DWORD fEnable);
    virtual BOOL _stdcall CheckMenu(DWORD itemIDorPosition,
         DWORD fCheck);
    virtual BOOL _stdcall IsChecked(DWORD itemIDorPosition,
         DWORD fByPosition);
    virtual BOOL _stdcall RemoveItem(DWORD itemIDorPosition,
         DWORD fByPosition);
    virtual BOOL _stdcall InsertItem(int item_index, DWORD dwItemID,
         LPSTR pszText);
    virtual BOOL _stdcall InsertPopupItem(int item_index,
         LPSTR pszText, ILuxSubMenu *lpSubMenu);

    virtual BOOL _stdcall SetIcon(DWORD dwItemID, HICON hIcon);
};

class ILuxSubMenu:public ILuxMenu{};
}// extern "C++"

typedef ILuxMenu *(_stdcall *PROC_LuxMenu_CreateInstance)(void);
typedef ILuxSubMenu *(_stdcall *PROC_LuxSubMenu_CreateInstance)(void);

LuxMenu.cppのコーディング

 この「LuxMenu.cpp」がソースコードの中核です。WinMain関数の定義、WndProc関数によるウィンドウプロシージャの定義を行います。

LuxMenu.cppのコーディング
#include "resource.h"
#include "LuxMenu.h"


LRESULT WINAPI WndProc(HWND hwnd, UINT message,
        WPARAM wParam, LPARAM lParam){
    static HINSTANCE hLib;
    static ILuxMenu *lpLuxMenu;

    switch(message){
    
        case WM_CREATE:
            hLib=LoadLibrary("LuxMenu.dll");
            if(!hLib){
                MessageBox(0,"LuxMenu.dllの読み込みに失敗しました。"
                    ,"LuxMenuTest error",MB_OK);
                return 0;
            }

            PROC_LuxMenu_CreateInstance LuxMenu_CreateInstance;
            LuxMenu_CreateInstance=
                (PROC_LuxMenu_CreateInstance)GetProcAddress(
                    hLib,"LuxMenu_CreateInstance");

            //LuxMenuインターフェイスを取得
            lpLuxMenu=LuxMenu_CreateInstance();

            //メニューを読み込ませる
            lpLuxMenu->ImportMenu(GetMenu(hwnd));

            //アイコンをセット
            lpLuxMenu->SetIcon(IDM_OPEN,
                (HICON)LoadImage(GetModuleHandle(0),
                    MAKEINTRESOURCE(IDI_OPEN),IMAGE_ICON,16,16,0));
            lpLuxMenu->SetIcon(IDM_SAVE,
                (HICON)LoadImage(GetModuleHandle(0),
                    MAKEINTRESOURCE(IDI_SAVE),IMAGE_ICON,16,16,0));
            lpLuxMenu->SetIcon(IDM_OPTION,
                (HICON)LoadImage(GetModuleHandle(0),
                    MAKEINTRESOURCE(IDI_OPTION),IMAGE_ICON,16,16,0));

            return 0;

        case WM_MEASUREITEM:
            lpLuxMenu->MeasureItem(lParam);
            return 0;

        case WM_DRAWITEM:
            lpLuxMenu->DrawItem(lParam);
            return 0;

        case WM_DESTROY:

            //LuxMenuインターフェイスを解放
            if(lpLuxMenu) lpLuxMenu->Release();

            //LuxMenu.dllモジュールを解放
            if(hLib) FreeLibrary(hLib);

            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc(hwnd,message,wParam,lParam);
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow )
{
     // TODO: この位置にコードを記述してください。

    //ウィンドウクラスを生成
    WNDCLASSEX wcl;
    wcl.cbSize=sizeof(WNDCLASSEX);
    wcl.hInstance=hInstance;
    wcl.lpszClassName="LuxMenuTest";
    wcl.lpfnWndProc=WndProc;
    wcl.style=0;
    wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wcl.hIconSm=LoadIcon(NULL,IDI_WINLOGO);
    wcl.hCursor=LoadCursor(NULL,IDC_ARROW);
    wcl.lpszMenuName=NULL;
    wcl.cbClsExtra=0;
    wcl.cbWndExtra=0;
    wcl.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
    RegisterClassEx(&wcl);

    //ウィンドウを生成
    CreateWindow("LuxMenuTest","LuxMenuTest",
        WS_OVERLAPPEDWINDOW|WS_VISIBLE,
        CW_USEDEFAULT ,CW_USEDEFAULT ,
        400,300 ,
        HWND_DESKTOP,LoadMenu(hInstance,
            MAKEINTRESOURCE(IDR_MAINMENU)),hInstance,NULL);

    MSG msg;
    while(GetMessage(&msg,NULL,0,0)){
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

 WinMain関数内では、一般的なウィンドウの生成およびメッセージループを行っているだけです。

 それでは、WndProc関数内の各イベントメッセージの流れをおさらいしてみましょう。

 まず、WM_CREATEメッセージが飛んできたら、LuxMenuコントロールの初期化を行います。LoadLibrary関数を呼び出し、「LuxMenu.dll」をプロセスイメージにロードします。そして、GetProcAddress関数でLuxMenu_CreateInstance関数を利用できるようにします。続けてLuxMenu_CreateInstance関数を呼び出し、ILuxMenuインターフェイスの生成を行います。インターフェイスポインタはlpLuxMenuになります。

 仕上げに、ImportMenuメソッドによる既存メニューのインポート、SetIconメソッドによるアイコンのセットを行います。

 WM_MEASUREITEMメッセージ、WM_DRAWITEMメッセージに関しては、メッセージ処理用のlpLuxMenuが提供するメソッド(それぞれ、MeasureItemDrawItem)を呼び出すだけです。

 最後に、WM_DESTROYメッセージにlpLuxMenu、hLibの解放処理を記述して完了です。

実行してみよう

 これでVC++によるコーディング作業は完了です。コンパイルして、問題がなければ実行してみましょう。

VC++による「LuxMenuTest.exe」の実行画面
VC++による「LuxMenuTest.exe」の実行画面

おわりに

 今回は、LuxMenuコントロールを利用してデザイン性の高いメニューコントロールの実装を行いました。呼び出さなければならないモジュールはあまり多くはありませんので、手軽に実装が可能かと思います。

 まずは、LuxMenuの使い勝手をご確認いただき、皆さまのアプリケーション上でご活躍いただければ幸いです。

 次回はもう少し踏み入り、LuxMenuコントロールがどのようなソースコードで書かれているのか、また、LuxMenu程度のモジュールを提供するためには、ABでどの程度のレベルのソースコードを書く必要が出てくるのかを解説していきます。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
デザイン性に優れた拡張メニューコントロール連載記事一覧

もっと読む

この記事の著者

山本 大祐(ヤマモト ダイスケ)

普段はActiveBasicと周辺ツールの開発を行っています。最近は諸先輩方を見習いながら勉強中の身。AB開発日記

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/500 2008/08/26 13:40

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー