Visual Basic 中学校 掲示板 投稿内容
タグのない投稿を抽出 統計 RSS

Visual Basic 中学校 > 投稿一覧 >

タスクトレイのアイコンを取得することは可能でしょうか? 解決済み

タグの編集...

投稿者 しゃかりこ   (その他)   投稿日時 2022/3/21 07:57:14
こちらのサイトへの投稿で大丈夫か迷ったのですが、以前も優しく教えていただけたので...。
System.Drawing.Iconへ、タスクトレイのアイコンを取得することは可能でしょうか?

ウィンドウアイコンや、実行ファイルの埋め込みアイコンではなく、
タスクトレイ内でリアルタイムに表示が変わっているアイコンです。
自力だと、
Shell_TrayWnd.TrayNotifyWnd.SysPager.ToolbarWindow32
NotifyIconOverflowWindow.ToolbarWindow32
のウィンドウから、各トレイアイコンのツールチップの取得はできたのですが、そこまでしか探せませんでした。
強引にPrintWindowによるキャプチャも試してみましたが、後者のウィンドウ(ポップアップで隠されているタスクトレイ)は、真っ黒なビットマップしか取れませんでした。

ウィジェットのようなアプリを作っていて、可能だったらタスクトレイの情報の一部をそちらに表示したいと思ったのですが、
アイコンの取得というのは難しいでしょうか。

windows10で、vb dot net,vs2017で書いてます。

投稿者 るきお   (社会人)   投稿日時 2022/3/21 09:32:44
私はこの分野は詳しくありませんが、
ここにタスクトレイのアイコンを列挙するプログラムがありました。
https://github.com/erik434/TrayIconBuster

このプログラムは画像そのものを取得しているわけではありませんがタスクトレイのボタンを列挙してハンドルを取得するところまだはやっているようです。参考にならないでしょうか?

一部を抜粋して引用
uint itemCount = (uint)SendMessage(toolbarHandle, TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero);
totalItemCount += itemCount;

for (uint item = 0; item < itemCount; item++)
{
    //Get info for this toolbar button
    if ((uint)SendMessage(toolbarHandle, TB_GETBUTTON, new IntPtr(index), remoteButtonPtr) == 0) throw new ApplicationException("TB_GETBUTTON failed");
    process.Read(toolbarButton, remoteButtonPtr);
    process.Read(extraData, toolbarButton.dwData);

    IntPtr buttonHandle = extraData.hWnd;
}


投稿者 しゃかりこ   (その他)   投稿日時 2022/3/21 12:07:04
るきお様、返信ありがとうございます。

私の文の「ツールチップの取得はできたのですが」の部分が、
紹介頂いた引用と似たような、タスクトレイのウィンドウ宛に "TB_" で始まるウィンドウメッセージを送って取得するものでした。
私の場合、TB_GETBITMAP で取得したのですが、2桁程度の数字(ビットマップID??)しか得られず、そのIDからどうやってアイコンのデータ(ハンドル?)まで辿るのかがわかりませんでした。

引用の方では、
process.Read が何なのか理解が曖昧ですが、
dwData を使ってるのが気になりました。
私も TB_GETBUTTON は取得してたのですが dwData にはいつも 0 しか入ってませんでした。
toolbarButton の構成も、私のコードの TBBUTTON と少し違っていて、そこの記述の仕方もあっているか自信がありません。
toolbarButton に少し似通わせてみましたが、取得できるデータは同じようで、よくわかりません。

「ツールチップの取得はできた」のコードですが、一応下記に記載しておきます。
文字数が長すぎてしまったので、APIの宣言と定数だけ省いてしまっています。
見様見真似で書いてるので、間違った記述や書き方してるところもありましたら、指摘いただけるとありがたいです。
また最初に書き忘れていたのですが、Windowsフォームアプリケーションです。

Imports System.Runtime.InteropServices
Public Class Form2
 <StructLayout(LayoutKind.Sequential)>
 Private Structure TBBUTTON
  Public iBitmap As Integer 'ビットマップのインデックス 
  Public idCommand As Integer 'コマンドID 
  Public fsState As Byte 'ボタンの状態 
  Public fsStyle As Byte 'ボタンのスタイル 
  Public bReserved1 As Byte  '予約(= 0 ) 
  Public bReserved2 As Byte  '予約(= 0 ) 
  Public dwData As Integer 'アプリケーション定義値 
  Public iString As Integer 'テキストのインデックス 
 End Structure

 Private Sub Button1_Click(ByVal sender As ObjectByVal e As EventArgs) Handles Button1.Click
  Dim hwnd As Integer = FindWindowEx(0, 0, "Shell_TrayWnd", vbNullString)
  If 0 < hwnd Then : hwnd = FindWindowEx(hwnd, 0, "TrayNotifyWnd", vbNullString)
   If 0 < hwnd Then : hwnd = FindWindowEx(hwnd, 0, "SysPager", vbNullString)
    If 0 < hwnd Then hwnd = FindWindowEx(hwnd, 0, "ToolbarWindow32", vbNullString)
   End If
  End If
  If 0 < hwnd Then
   Dim hProc As IntPtr = IntPtr.Zero
   Dim ptrVa As IntPtr = IntPtr.Zero
   Try : Dim hwnd_ As IntPtr = hwnd
    Dim pid As Integer = 0
    GetWindowThreadProcessId(hwnd_, pid)
    hProc = OpenProcess(PROCESS_ALL_ACCESS, 0, pid)
    ptrVa = VirtualAllocEx(hProc, 0, 256, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE)
    Dim buf As Byte() = Nothing
    Dim cnt As Integer = SendMessage(hwnd, TB_BUTTONCOUNT, 0, 0)
    Dim oBtn As TBBUTTON() = New TBBUTTON(cnt - 1) {}
    Dim sizTBBUTTON As Integer = Marshal.SizeOf(GetType(TBBUTTON))
    For i = 0 To cnt - 1 Step 1
     SendMessage(hwnd, TB_GETBUTTON, i, ptrVa)
     buf = New Byte(sizTBBUTTON - 1) {}
     ReadProcessMemory(hProc, ptrVa, buf, buf.Length, 0)

     Dim ptr As IntPtr = IntPtr.Zero
     Try : ptr = Marshal.AllocCoTaskMem(sizTBBUTTON)
      Marshal.Copy(buf, 0, ptr, sizTBBUTTON)
      oBtn(i) = Marshal.PtrToStructure(Of TBBUTTON)(ptr)
     Catch ex As Exception
     Finally
      If ptr <> IntPtr.Zero Then Try : Marshal.FreeCoTaskMem(ptr) : Catch : End Try
     End Try
     Debug.Print("Index: " & CStr(i) & " idCommand: " & CStr(oBtn(i).idCommand) & " Sate: " & Hex(oBtn(i).fsState) & " iString: " & Hex(oBtn(i).iString) & " dwData: " & Hex(oBtn(i).dwData))

     Dim strsiz As Integer = SendMessage(hwnd, TB_GETBUTTONTEXTW, oBtn(i).idCommand, 0) 'テキストのサイズを取得 
     Dim res As Integer = SendMessage(hwnd, TB_GETBUTTONTEXT, i, ptrVa)
     buf = New Byte(1024 - 1) {}
     ReadProcessMemory(hProc, ptrVa, buf, buf.Length, 0)
     Debug.Print("TB_GETBUTTONTEXT: " & System.Text.Encoding.GetEncoding("Shift_JIS").GetString(buf).Replace(vbNewLine, " "))
     Debug.Print("")

     Debug.Print("TB_GETBITMAP: " & SendMessage(hwnd, TB_GETBITMAP, oBtn(i).idCommand, 0))
     Debug.Print("")
    Next
   Catch ex As Exception
   Finally
    If ptrVa <> IntPtr.Zero Then Try : VirtualFreeEx(hProc, ptrVa, 0, MEM_RELEASE) : Catch : End Try
    If hProc <> IntPtr.Zero Then Try : CloseHandle(hProc) : Catch : End Try
   End Try
  End If
 End Sub
End Class



投稿者 しゃかりこ   (その他)   投稿日時 2022/3/29 18:42:54
ありがとうございました。諦めます。