VB6.0にて常駐アプリを作成しているのですが、
Shell_NotifyIconAにてタスクトレイに登録した自アイコンの位置を知る方法はありますか?
ホットキーを押された時にメニューを表示したいのですが、タスクトレイのアイコンの位置に合わせたいと思っています。
よろしくお願いします。
タスクトレイのアイコン表示領域はツールバーと同じクラスなので
取得できるとしてもアイコンが並んでいる矩形領域しか取得できない
のではないでしょうか。(時計の表示領域はTrayClockWClassとかいう
別ウィンドウになっているみたいですね)
よって、アイコンのサイズと何番目に表示されているかが分かれば
おおよその位置は計算できると思いますが。
詳しいことは調べてないのでなんともいえません。
ちょと調べたところTB_GETRECTメッセージを送れば
ボタンの四隅がわかるみたいです。
参考URL
http://www.kumei.ne.jp/c_lang/sdk2/sdk_189.htm
>かぶさん
ありがとうございます。
TB_GETRECTについて調べてみたのですが、
TB_GETRECT=&H433でよいのでしょうか?
Dim typBtnRect As RECT
SendMessage(Me.hwnd,TB_GETRECT,?,typBtnRect)
第三引数に何を入れたらよいか分かりません。
0を入れて実行したら、typBtnRectには全て0が入っていました。
また、アイコンが何番目に表示されているのかというのは取得可能なのでしょうか?
よろしくお願いします。
いろいろ調べるうちに結構、奥が深いような予感がしてきました。
TB_GETRECTの値はそれでいいです。
しかしながら、これをそのまま実行しても情報はとれないようで
http://forums.belution.com/ja/vc/000/271/38.shtml
上記URLにタスクトレイのツールバーの情報にアクセスする方法がありますが
これを参考にしてみてはいかがでしょう。
ちなみに
SendMessageのウィンドウハンドルはフォームのウィンドウハンドルじゃなく
タスクトレイのツールバーのウィンドウハンドルです
タスクトレイのツールバーというのは、ここを参考にしてみて下さい。
http://homepage1.nifty.com/kazubon/progdoc/tclock/taskbarhistory.html
第3引数はCommandIDです。
詳しくはこのあたりをご覧下さい。
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/toolbar/messages/tb_getrect.asp
で、自分のアイコンを識別する方法ですが、アイコン作成時に何か識別
できるボタンテキストを仕込んでおいてGETBUTTONTEXT等で区別するとか
でしょうか。他にもあるかもしれません。
>かぶさん
ありがとうございます。
タスクバーのツールバー(?)のハンドルは以下のようにして取得することが出来ました。
Dim hwndTaskbar As Long
Dim hwndButton As Long
Dim hwndTray As Long
'タスクバーのハンドルを取得
hwndTaskbar = FindWindowEx(0&, 0&, "Shell_TrayWnd", vbNullString)
'トレイのハンドルを取得
hwndButton = FindWindowEx(hwndTaskbar, 0&, "TrayNotifyWnd", vbNullString)
'windows xp の場合、必要(トレイのアイコンのハンドルを取得)
If XPかどうかフラグ = True Then hwndButton = FindWindowEx(hwndButton, 0&, "SysPager", vbNullString)
'トレイのアイコンのハンドルを取得
hwndTray = FindWindowEx(hwndButton, 0&, "ToolbarWindow32", vbNullString)
ここから、トレイに登録されているアイコンボタンの情報を取得しようと
以下のような処理を書きました。
Public Const TB_GETBUTTON = WM_USER + 23
Public Const TB_BUTTONCOUNT = WM_USER + 24
Dim intButtonCount As Integer
Dim tbb As TBBUTTON
'/* ボタンの数を取得 */
intButtonCount = SendMessage(hwndTray, TB_BUTTONCOUNT, 0, 0)
For i = 0 To intButtonCount - 1
'/* i 番目のボタンの情報を取得 */
Call SendMessage(hwndTray, TB_GETBUTTON, i, tbb)
Next i
しかし、tbbに値が入ってきません。
どのようにしたら、ボタンの情報が取得できるのでしょうか?
よろしくお願いします。
前レスにも書いたようにそのままTB_GETRECTやTB_GETBUTTONを行っても
別プロセスで確保されたメモリにはアクセスできないようです。
http://forums.belution.com/ja/vc/000/271/38.shtml
前レスのアクセス方法のリンク先をVB流に書き直すと以下のようになるでしょうか。
このサンプルではタスクトレイの全てのボタンの情報を取得して、その中で可視状態
にあるボタンの四隅を取得し、最後にスクリーン座標でDebug.Printしています。
Dim hWnd As Long
Dim iCnt As Long
Dim i As Long
Dim lngRet As Long
Dim lngPtr As Long
Dim lngPID As Long
Dim hProc As Long
Dim oBtn() As TBBUTTON
Dim lngRdCnt As Long
Dim rctIcon() As RECT
Dim rctWin As RECT 'ツールバーのWindow Rect
Dim rctClient As RECT 'ツールバーのClient Rect
'タスクトレイのツールバー領域のウィンドウハンドルを取得(XP)の場合
hWnd = FindWindowEx( _
FindWindowEx( _
FindWindowEx( _
FindWindowEx(0&, 0&, "Shell_TrayWnd", ByVal 0) _
, 0&, "TrayNotifyWnd", ByVal 0) _
, 0&, "SysPager", ByVal 0) _
, 0&, "ToolbarWindow32", ByVal 0)
'ツールバーを作成したプロセスでメモリを確保
GetWindowThreadProcessId hWnd, lngPID
hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, lngPID)
lngPtr = VirtualAllocEx(hProc, ByVal 0&, 65536, MEM_COMMIT, PAGE_READWRITE)
'ボタンの数を取得
iCnt = SendMessage(hWnd, TB_BUTTONCOUNT, 0&, 0&)
'ツールバーのウィンドウ領域とクライアント領域を取得
GetWindowRect hWnd, rctWin
GetClientRect hWnd, rctClient
Debug.Print "Count=" & Format(iCnt)
ReDim oBtn(iCnt - 1) 'ボタン情報を取得する領域を確保
ReDim rctIcon(iCnt - 1) 'ボタンの位置を取得する領域を確保
For i = 0 To iCnt - 1
'ボタン情報の取得
lngRet = SendMessage(hWnd, TB_GETBUTTON, i, ByVal lngPtr)
ReadProcessMemory hProc, ByVal lngPtr, oBtn(i), Len(oBtn(i)), lngRdCnt
Debug.Print "Index=" & Format(i) & " idCommand=" & Format(oBtn(i).idCommand) & " Sate=" & Hex$(oBtn(i).fsState)
If (oBtn(i).fsState And TBSTATE_HIDDEN) = 0 Then
'ボタンが可視状態なら位置を取得
lngRet = SendMessage(hWnd, TB_GETRECT, oBtn(i).idCommand, ByVal lngPtr)
ReadProcessMemory hProc, ByVal lngPtr, rctIcon(i), Len(rctIcon(i)), lngRdCnt
'スクリーン座標に変換して出力
Debug.Print rctWin.Left + rctClient.Left + rctIcon(i).Left, rctWin.Top + rctClient.Top + rctIcon(i).Top, _
rctWin.Left + rctClient.Left + rctIcon(i).Right, rctWin.Top + rctClient.Top + rctIcon(i).Bottom
End If
Next
'後処理
VirtualFreeEx hProc, ByVal lngPtr, 0, MEM_RELEASE
CloseHandle hProc
>かぶさん
ありがとうございます。
私も少し前に、そのことに気がつき表示されているアイコンの各座標を取得するところまで出来ました。
TBBUTTONのiStringってどこの文字列ポインタが入っているのでしょうか?
自アプリを検索するには使えませんか?
よろしくお願いします。
>TBBUTTONのiStringってどこの文字列ポインタが入っているのでしょうか?
>自アプリを検索するには使えませんか?
前レスのコードにiStringの取得部分を追加し実行させたところ(下記コード参照)
どうもToolTipテキストの文字のような気がしますね。
他のアイコンのテキストとかぶらないものを設定しておけば
検索に使えるかもしれません。
For i = 0 To iCnt - 1
'ボタン情報の取得
lngRet = SendMessage(hWnd, TB_GETBUTTON, i, ByVal lngPtr)
ReadProcessMemory hProc, ByVal lngPtr, oBtn(i), Len(oBtn(i)), lngRdCnt
Debug.Print "Index=" & Format(i) & " idCommand=" & Format(oBtn(i).idCommand) & " Sate=" & Hex$(oBtn(i).fsState) & " iString=" & Hex$(oBtn(i).iString)
If (oBtn(i).fsState And TBSTATE_HIDDEN) = 0 Then
'ボタンが可視状態なら位置を取得
lngRet = SendMessage(hWnd, TB_GETRECT, oBtn(i).idCommand, ByVal lngPtr)
ReadProcessMemory hProc, ByVal lngPtr, rctIcon(i), Len(rctIcon(i)), lngRdCnt
'スクリーン座標に変換して出力
Debug.Print rctWin.Left + rctClient.Left + rctIcon(i).Left, rctWin.Top + rctClient.Top + rctIcon(i).Top, _
rctWin.Left + rctClient.Left + rctIcon(i).Right, rctWin.Top + rctClient.Top + rctIcon(i).Bottom
'-------------------------------------------------------------追加分
If oBtn(i).iString And &HFFFF0000 Then
'上位ワードが0で無い場合文字列のポインタが入っている
lngSize = SendMessage(hWnd, TB_GETBUTTONTEXTW, oBtn(i).idCommand, ByVal 0) 'テキストのサイズを取得
If lngSize > 0 Then
'テキストサイズはUnicodeの文字数で返ってくるみたいなので文字数×2バイト分の領域を確保
ReDim bytText(lngSize * 2 - 1)
ReadProcessMemory hProc, ByVal oBtn(i).iString, bytText(0), lngSize * 2, lngRdCnt
'文字列の表示
Debug.Print bytText
End If
End If
'-------------------------------------------------------------追加分 ここまで
End If
Next
>かぶさん
最後まで有難うございました。
とりあえず、ツールチップで判別し正しい座標を取得することができました。
サンプルソースもとても役に立ちました。
また、何かありましたらよろしくお願いします。
ツイート | ![]() |