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関数によるウィンドウプロシージャの定義を行います。
#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が提供するメソッド(それぞれ、MeasureItem、DrawItem)を呼び出すだけです。
最後に、WM_DESTROYメッセージにlpLuxMenu、hLibの解放処理を記述して完了です。
実行してみよう
これでVC++によるコーディング作業は完了です。コンパイルして、問題がなければ実行してみましょう。

おわりに
今回は、LuxMenuコントロールを利用してデザイン性の高いメニューコントロールの実装を行いました。呼び出さなければならないモジュールはあまり多くはありませんので、手軽に実装が可能かと思います。
まずは、LuxMenuの使い勝手をご確認いただき、皆さまのアプリケーション上でご活躍いただければ幸いです。
次回はもう少し踏み入り、LuxMenuコントロールがどのようなソースコードで書かれているのか、また、LuxMenu程度のモジュールを提供するためには、ABでどの程度のレベルのソースコードを書く必要が出てくるのかを解説していきます。
