Системный доступ

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
0
1 682
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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 и целевым процессом.

Другие вопросы по теме