【VBA×WindowsAPI】AppendMenu関数の使い方
AppendMenu関数
AppendMenu関数は指定のメニューの末尾に新規の項目を作成するための関数です。
ここでいうメニューとはメニューバー、ドロップダウンメニュー、サブメニュー、またはコンテキスト(ショートカット)メニューなどを指します。AppendMenu関数で追加するメニュー項目は下画像の通り、文字列の設定だけではなくアイコン設定やサブメニューを設定することができます。
この関数を使うことでCreateMenu関数やCreatePopupMenu関数などで新規作成したメニューに対して、新規メニュー項目を追加することができます。このとき、追加されるメニュー項目はメニューの最後尾に追加されます(イメージとしてはCollectionのAddメソッド)。位置を指定して追加したい場合はInsertMenu関数を使うことでインデックスを指定したメニュー項目の追加が可能になります。
VBAで本関数を使う場合、ユーザーがクリックしたイベントを検知する必要があるためUserFormやControlのClickイベントやMouseUpイベントなどを利用するのが一般的です。
使用方法
AppendMenu関数を使用するにはあらかじめ関数の宣言しておく必要があります。
※宣言をしないと関数は使えずにエラーとなるので書き忘れに注意しましょう。
使用しているWindowsが32bitか64bitかによって宣言時に書く文言が違います。
環境に合わせて以下のいずれかをコードの一番初め(Option Explicitの次の行あたり)に書いておくことで、そのモジュール内で各関数を使うことができるようになります。
Declare PtrSafe Function AppendMenu Lib “user32” Alias “AppendMenuA” _
(ByVal hMenu As LongPtr, ByVal wFlags As Long, _
ByVal wIDNewItem As LongPtr, ByVal lpNewItem As Any) As Long
Declare Function AppendMenu Lib “user32” Alias “AppendMenuA” _
(ByVal hMenu As Long, ByVal wFlags As Long, _
ByVal wIDNewItem As Long, ByVal lpNewItem As Any) As Long
上記のどちらを書けばいいかわからない場合は以下のコードをコピペして、モジュールの最上部に書いておきましょう。この構文を書いておくことで自動的に使うことのできる方の構文が使用されます。
VBE上では使えない方の構文が赤色で表示される場合がありますが、実行に影響はありません。
1 2 3 4 5 |
#If VBA7 Then Declare PtrSafe Function AppendMenu Lib "user32" Alias "AppendMenuA" (ByVal hMenu As LongPtr, ByVal wFlags As Long, ByVal wIDNewItem As LongPtr, ByVal lpNewItem As Any) As Long #Else Declare Function AppendMenu Lib "user32" Alias "AppendMenuA" (ByVal hMenu As Long, ByVal wFlags As Long, ByVal wIDNewItem As Long, ByVal lpNewItem As Any) As Long #End If |
各関数の宣言文は「Private/Public」を付けて各関数の有効範囲を指定することもできます。
・Public Declare PtrSafe Function~ :モジュール外で呼び出し有効
構文
AppendMenu関数の構文は下記のように書きます。
lRet = AppendMenu(hMenu, wFlags, wIDNewItem, lpNewItem)
引数
hMenu (64bit:LongPtr型 / 32bit:Long型)
項目を追加するメニューのハンドルです。
通常、CreateMenu関数やCreatePopupMenu関数等で作成されたメニューハンドルを入力します。
wFlags (Long型)
追加する項目の外観や動作を制御するフラグです。
下表の定数値を組み合わせて設定することが可能です。(※その他のフラグはMicrosoft公式を参照)
フラグ (定数) | 説明 |
MF_STRING (&H0) | メニュー項目に文字列を設定する |
MF_DISABLED (&H2) | メニュー項目を選択不可状態にする |
MF_BITMAP (&H4) | メニュー項目にBMP画像を設定する |
MF_CHECKED (&H8) | メニュー項目をチェック付与状態にする |
MF_POPUP (&H10) | メニュー項目にサブメニューを付与する |
MF_SEPARATOR (&H800) | メニュー項目に水平分割線を設定する |
フラグを複数設定させたい場合はOr演算子を使って設定が可能です。
ただし、下記のフラグの組み合わせについては設定することが出来ません。
1 2 3 4 |
・wFlags = MF_BITMAP Or MF_STRING Or MF_OWNERDRAW ・wFlags = MF_CHECKED Or MF_UNCHECKED ・wFlags = MF_DISABLED Or MF_ENABLED Or MF_GRAYED ・wFlags = MF_MENUBARBREAK Or MF_MENUBREAK |
wIDNewItem (64bit:LongPtr型 / 32bit:Long型)
追加する項目の識別IDです。ユーザーが選択した項目はこの識別IDをして取得が可能です。
wFlagsに「MF_POPUP」を設定する場合、識別IDではなくサブメニューとして設定するメニューのハンドルを入力します。これにより、追加される項目はここで入力したハンドルが指すメニューをサブメニューをして持つ項目として追加されます。(この場合、項目自体の識別IDは存在しない)
lpNewItem (Any型)
追加する項目の内容です。wFlagsに設定するフラグにより入力内容は変化します。
wFlagsに「MF_STRING」を設定する場合は、項目名となる文字列(String型)を入力します。
wFlagsに「MF_BITMAP」を設定する場合は、項目に設定する画像のハンドル(64bit:LongPtr型 / 32bit:Long型)を入力します。画像のハンドルはLoadImage関数等を利用することで取得可能です。
入力する引数がwFlagsにより文字列、数値と変化するため特定の型で宣言ができないことから、少し特殊な「Any型」として宣言されます。(ここでいう宣言とはDeclare~で始まる宣言文のこと)
Any型ではなくVariant型で宣言した場合、アプリケーションが強制終了するので注意が必要です。設定する項目が文字列だけの場合は「As Any」部分を「As String」としても正常に動作します。
戻り値
lRet (Long型)
戻り値は関数が成功すると「0以外」、失敗すると「0」が返ります。
サンプルコード
以下はAppendMenu関数とFindWindow関数、CreatePopupMenu関数、DestroyMenu関数、GetCursorPos関数、TrackPopupMenu関数を使って、UserForm上で右クリックをしたらコンテキストメニューを表示するサンプルコードです。(※より詳細なAppendMenu関数実装例はコチラ)
下記コードをUserFormのコードにコピーペーストしてからUserFormを表示すれば、Initializeイベントでメニューがメモリ上に作成され、右クリックをするとそのメニューを表示することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Private Declare PtrSafe Function CreatePopupMenu Lib "user32" () As LongPtr Private Declare PtrSafe Function DestroyMenu Lib "user32" (ByVal hMenu As LongPtr) As Long Private Declare PtrSafe Function AppendMenu Lib "user32" Alias "AppendMenuA" (ByVal hMenu As LongPtr, ByVal wFlags As Long, ByVal wIDNewItem As LongPtr, ByVal lpNewItem As Any) As Long Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long Private Declare PtrSafe Function TrackPopupMenu Lib "user32" (ByVal hMenu As LongPtr, ByVal wFlags As Long, ByVal X As Long, ByVal Y As Long, ByVal nReserved As Long, ByVal hwnd As LongPtr, lprc As Long) As Long Private Const MF_STRING As Long = &H0 '文字列設定フラグ Private Const TPM_RETURNCMD As Long = &H100 '戻り値を選択された項目のIDとする 'カーソル座標取得用構造体 Private Type POINTAPI X As Long Y As Long End Type Dim hWndForm As LongPtr 'UserFormウィンドウハンドル Dim hMenu As LongPtr 'ポップアップメニューハンドル '------------------------------------------------------------------ ' UserForm起動時イベント '------------------------------------------------------------------ Private Sub UserForm_Initialize() 'UserFormウィンドウハンドル取得 hWndForm = FindWindow("ThunderDFrame", Me.Caption) 'ポップアップメニュー作成 hMenu = CreatePopupMenu() 'メニュー項目に文字列追加 Call AppendMenu(hMenu, MF_STRING, 1, "文字列設定1") Call AppendMenu(hMenu, MF_STRING, 2, "文字列設定2") Call AppendMenu(hMenu, MF_STRING, 3, "文字列設定3") End Sub '------------------------------------------------------------------ ' UserForm終了時イベント '------------------------------------------------------------------ Private Sub UserForm_Terminate() 'ポップアップメニュー解放 Call DestroyMenu(hMenu) End Sub '------------------------------------------------------------------ ' UserFormマウスアップイベント '------------------------------------------------------------------ Private Sub UserForm_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single) '右クリック時 If Button = 2 Then Dim tPos As POINTAPI Dim lRet As Long '現在のカーソル位置の座標取得 Call GetCursorPos(tPos) 'カーソル位置にポップアップメニューを表示 lRet = TrackPopupMenu(hMenu, TPM_RETURNCMD, tPos.X, tPos.Y, 0, hWndForm, 0) If lRet <> 0 Then Call MsgBox("「ID:" & lRet & "」の項目が選択されました", vbInformation) End If End If End Sub |
VBA×WindowsAPIまとめページ
その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。
参考
Microsoft公式:AppendMenuA 関数 (winuser.h) – Win32 apps