private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref TBBUTTONINFOW lpBuffer, IntPtr nSize, out IntPtr lpNumberOfBytesRead);
public static List <string> ScanToolbarButtons() { List <string> tooltips = new List <string>(); var handle = GetSystemTrayHandle(); if (handle == IntPtr.Zero) { return(null); } var count = SendMessage(handle, TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero).ToInt32(); if (count == 0) { return(null); } GetWindowThreadProcessId(handle, out var pid); var hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid); if (hProcess == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var size = (IntPtr)Marshal.SizeOf <TBBUTTONINFOW>(); var buffer = VirtualAllocEx(hProcess, IntPtr.Zero, size, MEM_COMMIT, PAGE_READWRITE); if (buffer == IntPtr.Zero) { CloseHandle(hProcess); throw new Win32Exception(Marshal.GetLastWin32Error()); } for (int i = 0; i < count; i++) { var btn = new TBBUTTONINFOW(); btn.cbSize = size.ToInt32(); btn.dwMask = TBIF_BYINDEX | TBIF_COMMAND; if (WriteProcessMemory(hProcess, buffer, ref btn, size, out var written)) { // we want the identifier var res = SendMessage(handle, TB_GETBUTTONINFOW, (IntPtr)i, buffer); if (res.ToInt32() >= 0) { if (ReadProcessMemory(hProcess, buffer, ref btn, size, out var read)) { // now get display text using the identifier // first pass we ask for size var textSize = SendMessage(handle, TB_GETBUTTONTEXTW, (IntPtr)btn.idCommand, IntPtr.Zero); if (textSize.ToInt32() != -1) { // we need to allocate for the terminating zero and unicode var utextSize = (IntPtr)((1 + textSize.ToInt32()) * 2); var textBuffer = VirtualAllocEx(hProcess, IntPtr.Zero, utextSize, MEM_COMMIT, PAGE_READWRITE); if (textBuffer != IntPtr.Zero) { res = SendMessage(handle, TB_GETBUTTONTEXTW, (IntPtr)btn.idCommand, textBuffer); if (res == textSize) { var localBuffer = Marshal.AllocHGlobal(utextSize.ToInt32()); if (ReadProcessMemory(hProcess, textBuffer, localBuffer, utextSize, out read)) { var text = Marshal.PtrToStringUni(localBuffer); tooltips.Add(text); } Marshal.FreeHGlobal(localBuffer); } VirtualFreeEx(hProcess, textBuffer, IntPtr.Zero, MEM_RELEASE); } } } } } } VirtualFreeEx(hProcess, buffer, IntPtr.Zero, MEM_RELEASE); CloseHandle(hProcess); return(tooltips); }