Есть ли способ (в C#) получить доступ к панели задач? Я не говорю о создании значка уведомления. Я хочу перебирать элементы в лотке (я бы догадывался по процессам, но я не знаю, как определить, что на самом деле находится в лотке, а что является просто процессом), а также представить элементы с их значками в моем собственном ui.





MadCollection Матиаса Рауэна (для Delphi, а не C#) может отображать Значки в трее.
И есть инструмент командной строки: Утилита сканирования в области уведомлений Windows
Я также написал (не выпущен) свою собственную программу на Delphi (не Delphi.NET), не используя madCollection, которая показывает значки в трее, имена процессов, всплывающие подсказки и другую информацию, но она не идеальна. Есть несколько значков, которые он не может отобразить (хотя в нем перечислена другая информация), и он не может отображать какие-либо значки под Windows 9x. Я вообще не тестировал его под Vista.
Как вы относитесь к взаимодействию Win32? Я нашел Код C / Win32, который может помочь вам. (На самом деле, это похоже на интересную проблему, поэтому я мог бы попытаться решить ее сам, но не сейчас).
Магия, похоже, в том, что он получает дескриптор окна панели задач:
NotifyWnd = FindWindowEx(SysTray, 0, "TrayNotifyWnd", 0);Затем он подключает его к насосу сообщений:
hHook=SetWindowsHookEx(WH_CALLWNDPROC,HOOKPROC(MsgProc),
hInstance,dwExplorerThreadId);Затем во время обратного вызова перегрузки сообщений он получает ссылку на некоторые данные указателя об окне:
TWDataT* twd=(TWDataT*)GetWindowLong(NotifyWnd,0);Загадка - это его петля:
pTWIconDataT p=COMCTL32_332(twd->iconsInfo,i);COMCTL32_332 определяется с помощью GetProcAddress и указывает на порядковый номер 332 в Comctl32.dll - согласно моей проверке с помощью средства просмотра зависимостей, это DPA_GetPtr, который получает данные из массива динамических указателей. Я не знаком с тем, что там происходит за кулисами, но это не совсем исключено.
Я собираюсь немного поиграть с этим сам, но, надеюсь, это хорошее место для начала. :)
В Windows 2000 значки на панели задач находятся в простом элементе управления на панели инструментов (класс окна «ToolbarWindow32»), который является дочерним по отношению к окну «TrayNotifyWnd», поэтому вы можете отправлять ему сообщения панели инструментов, такие как TB_BUTTONCOUNT и TB_GETBUTTON.
Однако вы должны быть осторожны: такие сообщения, как TB_GETBUTTON, которые требуют указателя на буфер, в котором будут храниться результаты, нуждаются в этом буфере на быть в самом процессе SysTray. Для этого требуется, чтобы у вас были соответствующие разрешения и чтобы вы использовали VirtualAllocEx для выделения памяти.
Я не пробовал на XP или Vista. Я ожидаю, что все изменилось.
Это было вполне возможно в Windows 2000 / Xp. К сожалению, в Windows 7 это больше невозможно.
Уловка была проста: нужно найти ручку окна лотка:
static IntPtr GetSystemTrayHandle()
{
IntPtr hWndTray = FindWindow("Shell_TrayWnd", null);
if (hWndTray != IntPtr.Zero)
{
hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "TrayNotifyWnd", null);
if (hWndTray != IntPtr.Zero)
{
hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "SysPager", null);
if (hWndTray != IntPtr.Zero)
{
hWndTray = FindWindowEx(hWndTray, IntPtr.Zero, "ToolbarWindow32", null);
return hWndTray;
}
}
}
return IntPtr.Zero;
}
Поскольку это окно ToolbarWindow32, вам необходимо перечислить все кнопки с помощью WinAPI. Единственная проблема заключается в том, что все используемые для этого структуры должны быть размещены в адресном пространстве целевого процесса, поэтому вы должны использовать что-то вроде этого:
private static unsafe bool GetTBButton(IntPtr hToolbar, int i, ref TBBUTTON tbButton, ref string text, ref IntPtr ipWindowHandle)
{
// One page
const int BUFFER_SIZE = 0x1000;
byte[] localBuffer = new byte[BUFFER_SIZE];
UInt32 processId = 0;
UInt32 threadId = User32.GetWindowThreadProcessId(hToolbar, out processId);
IntPtr hProcess = Kernel32.OpenProcess(ProcessRights.ALL_ACCESS, false, processId);
if (hProcess == IntPtr.Zero) { Debug.Assert(false); return false; }
IntPtr ipRemoteBuffer = Kernel32.VirtualAllocEx(
hProcess,
IntPtr.Zero,
new UIntPtr(BUFFER_SIZE),
MemAllocationType.COMMIT,
MemoryProtection.PAGE_READWRITE);
if (ipRemoteBuffer == IntPtr.Zero) { Debug.Assert(false); return false; }
// TBButton
fixed (TBBUTTON* pTBButton = &tbButton)
{
IntPtr ipTBButton = new IntPtr(pTBButton);
int b = (int)User32.SendMessage(hToolbar, TB.GETBUTTON, (IntPtr)i, ipRemoteBuffer);
if (b == 0) { Debug.Assert(false); return false; }
// this is fixed
Int32 dwBytesRead = 0;
IntPtr ipBytesRead = new IntPtr(&dwBytesRead);
bool b2 = Kernel32.ReadProcessMemory(
hProcess,
ipRemoteBuffer,
ipTBButton,
new UIntPtr((uint)sizeof(TBBUTTON)),
ipBytesRead);
if (!b2) { Debug.Assert(false); return false; }
}
// button text
fixed (byte* pLocalBuffer = localBuffer)
{
IntPtr ipLocalBuffer = new IntPtr(pLocalBuffer);
int chars = (int)User32.SendMessage(hToolbar, TB.GETBUTTONTEXTW, (IntPtr)tbButton.idCommand, ipRemoteBuffer);
if (chars == -1) { Debug.Assert(false); return false; }
// this is fixed
Int32 dwBytesRead = 0;
IntPtr ipBytesRead = new IntPtr(&dwBytesRead);
bool b4 = Kernel32.ReadProcessMemory(
hProcess,
ipRemoteBuffer,
ipLocalBuffer,
new UIntPtr(BUFFER_SIZE),
ipBytesRead);
if (!b4) { Debug.Assert(false); return false; }
text = Marshal.PtrToStringUni(ipLocalBuffer, chars);
if (text == " ") text = String.Empty;
}
К сожалению, в Windows 7 tbButton.dwData равно 0, поэтому вы не можете найти никакой связи между NotifyIcon и целевым процессом.