
今回は、タスクトレイに表示されたアイコン上でマウスクリックされたときに、ショートカットメニューを表示するようにしてみましょう。
これまでの知識から、 Shell_NotifyIcon 関数と TrackPopupMenuEx 関数を使ってできるはずです。ところが、実際にやってみるとメニューを表示したときに、動作がおかしくなることがあります。
いったいどのようなことが起こるのかというと、トレイアイコンからショートカットメニューを表示したときに、表示されたメニューまたはそれを作成したウィンドウ以外の部分をクリックすると、メニューが表示されたまま残ってしまうことがある、というものです。
この問題を解決するには、まず、 SetForegroundWindow 関数を呼び出してウィンドウをフォアグラウンドに持ってきてから、 TrackPopupMenuEx 関数を呼び出して、ポップアップメニューを表示する、という手順をとります。
まずは SetForegroundWindow 関数を呼び出します。この関数は、指定されたウィンドウをフォアグラウンド(最前面)に持ってきます。
BOOL SetForegroundWindow(
HWND hWnd // ウィンドウハンドル
);
hWnd パラメータには、最前面に持ってくるウィンドウのハンドルを指定します。HSPウィンドウのハンドルを指定すればよいです。
次に、ショートカットメニューを表示します。ショートカットメニューの表示には TrackPopupMenuEx 関数を呼び出します。表示するメニューについては、あらかじめ作成しておきましょう。(表示する直前に作成してもいいですが。)
ショートカットメニューの表示については以前にもやったことがあるので、詳しい説明は省きます。
ショートカットメニューについては、『ショートカットメニューを表示してみる』を参照してください。
さて、実際にスクリプトを書いてみます。
#include "llmod.as"
#include "hsgetmsg.as"
; メニューアイテムIDを定義
#define CMD_SHOWWINDOW 1 ;「ウィンドウを表示」アイテムのID
#define CMD_HIDEWINDOW 2 ;「ウィンドウを隠す」アイテムのID
#define CMD_VERSION 3 ;「バージョン情報」アイテムのID
#define CMD_QUIT 4 ;「終了」アイテムのID
; トレイアイコン用のアイコンID
#define ID_TRAYICON 1
; トレイアイコン用のメッセージコード
#define MYWM_TRAYICON 0x1000
;--------------- ショートカットメニューの準備 ------------------
; ショートカットメニューの作成
dllproc "CreatePopupMenu", pm, 0, D_USER
hpopup = stat ; ショートカットメニューのハンドル
; メニューアイテムの追加
mesbuf = "ウィンドウを表示(&S)"
pm = hpopup, 0, CMD_SHOWWINDOW
getptr pm.3, mesbuf
dllproc "AppendMenuA", pm, 4, D_USER
mesbuf = "ウィンドウを隠す(&H)"
pm = hpopup, 0, CMD_HIDEWINDOW
getptr pm.3, mesbuf
dllproc "AppendMenuA", pm, 4, D_USER
pm = hpopup, $800, 0, 0 ; 区切り線を指定
dllproc "AppendMenuA", pm, 4, D_USER
mesbuf = "バージョン情報(&V)"
pm = hpopup, 0, CMD_VERSION
getptr pm.3, mesbuf
dllproc "AppendMenuA", pm, 4, D_USER
pm = hpopup, $800, 0, 0 ; 区切り線を指定
dllproc "AppendMenuA", pm, 4, D_USER
mesbuf = "終了(&Q)"
pm = hpopup, 0, CMD_QUIT
getptr pm.3, mesbuf
dllproc "AppendMenuA", pm, 4, D_USER
;------------------- メッセージ取得設定 ------------------------
;----- (ウィンドウハンドルを取得できるので先にサブクラス化) ----
; トレイアイコン用メッセージを取得するようにセット
set_subclass ; サブクラス化
hwnd = stat ; メインウィンドウのハンドル
set_message MYWM_TRAYICON ; MYWM_TRAYICON を取得するように設定
; メッセージパラメータ用変数
dup msg, msgval.1 ; メッセージが格納される変数
dup wprm, msgval.2 ; wParamパラメータが格納される変数
dup lprm, msgval.3 ; lParamパラメータが格納される変数
;--------------- タスクトレイアイコンの表示 --------------------
tooltext = "HSP Tray-Icon Test" ; ツールチップテキスト
; 自身の実行ファイル名取得
sdim exefile, 260 ; ファイル名を格納する変数
pm = 0 ; NULL
getptr pm.1, exefile ; バッファアドレス取得
pm.2 = 260 ; バッファサイズ
dllproc "GetModuleFileNameA", pm, 3, D_KERNEL
; 実行ファイルからアイコンを取得
getptr pm.0, exefile ; ファイル名
pm.1 = 0 ; アイコンインデックス
pm.2 = 0 ; 大きいアイコンは取得しない
getptr pm.3, hicon ; 小さいアイコンのハンドルを格納する変数
pm.4 = 1 ; 取得する数
dllproc "ExtractIconExA", pm, 5, D_SHELL
; NOTIFYICONDATA 構造体
dim nid, 22
nid.0 = 88 ; 構造体サイズ
nid.1 = hwnd ; ウィンドウハンドル
nid.2 = ID_TRAYICON ; アイコンID
nid.3 = 1 | 2 | 4 ; NIF_MESSAGE | NIF_ICON | NIF_TIP
nid.4 = MYWM_TRAYICON ; メッセージコード
nid.5 = hicon ; アイコンハンドル
poke nid, 24, tooltext ; ツールチップ文字列
; タスクトレイにアイコンを追加
pm.0 = 0 ; NIM_ADD
getptr pm.1, nid ; NOTIFYICONDATA 構造体アドレス
dllproc "Shell_NotifyIconA", pm, 2, D_SHELL
; 終了時にジャンプ
onexit *onQuit
;----------------------- メインループ --------------------------
*mainloop
get_message msgval
if msgval {
if msg == MYWM_TRAYICON : gosub *onTrayEvent
} else {
wait 10
}
goto *mainloop
*onTrayEvent
;--------------- トレイアイコンがクリックされたとき -------------
if lprm == 0x0205 { ; WM_RBUTTONUP
; ウィンドウをフォアグラウンドに
pm = hwnd ; ウィンドウハンドル
dllproc "SetForegroundWindow", pm, 1, D_USER
; ショートカットメニュー表示
ginfo 0 ; マウスカーソル座標取得
pm.0 = hpopup ; ショートカットメニューのハンドル
pm.1 = $182 ; TPM_RIGHTBUTTON | TPM_RETURNCMD
; | TPM_NONOTIFY
pm.2 = prmx ; スクリーンx座標
pm.3 = prmy ; スクリーンy座標
pm.4 = hwnd ; ウィンドウハンドル
pm.5 = 0 ; NULL
dllproc "TrackPopupMenuEx", pm, 6, D_USER
if stat {
itemid = stat ; 選択されたメニューアイテムID
if itemid == CMD_SHOWWINDOW {
gsel 0, 1
}
if itemid == CMD_HIDEWINDOW {
gsel 0, -1
}
if itemid == CMD_VERSION {
s = "タスクトレイのショートカットメニュー\n\n"
s += "サンプルスクリプト\n"
s += "Presented by ちょくと"
dialog s, 0, "バージョン情報"
}
if itemid == CMD_QUIT {
dialog "終了しますか", 2, "確認"
if stat == 6 : goto *onQuit
}
}
}
return
*onQuit
;----------------------- 終了時の処理 --------------------------
; NOTIFYICONDATA 構造体(cbSize, uID のみセット)
dim nid, 22
nid.0 = 88 ; 構造体サイズ(=88)
nid.1 = hwnd ; ウィンドウハンドル
nid.2 = ID_TRAYICON ; アイコンID
; タスクトレイからアイコンを削除
pm.0 = 2 ; NIM_DELETE
getptr pm.1, nid ; NOTIFYICONDATA 構造体アドレス
dllproc "Shell_NotifyIconA", pm, 2, D_SHELL
; アイコンの破棄
dllproc "DestroyIcon", hicon, 1, D_USER
; メニューの破棄
dllproc "DestroyMenu", hpopup, 1, D_USER
end