Как я могу получать уведомления о создании нового окна в Win32?

Есть ли способ с помощью Win32 зарегистрироваться для получения уведомлений при создании нового окна. Я пытаюсь сохранить список текущих открытых окон, но сейчас просто опрашиваю список текущих окон, используя EnumWindows().

Кто-нибудь делал что-то подобное?

Спасибо


Я не уверен, что делаю это правильно, но я не могу запустить метод SetWindowsHookEx.

что-нибудь приходит на ум?

вот мой фрагмент

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(HookType hook, HookProc callback, IntPtr hMod, uint dwThreadId);

[DllImport("user32.dll")]
private static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
const int HSHELL_WINDOWCREATED = 1;

private static HookProc winDelegate = ShellHookProcDelegate;
internal static void RegisterWindowCreatedEvent()
{
    SetWindowsHookEx(HookType.WH_SHELL, winDelegate, IntPtr.Zero, 0);
}

private static int ShellHookProcDelegate(int code, IntPtr wParam, IntPtr lParam)
{
    if (code != HSHELL_WINDOWCREATED)
    {
        return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
    }

    //App specific code here

    return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}

person James Hollister    schedule 21.06.2009    source источник
comment
Так как WH_SHELL является внедренным хуком, ваш хук должен находиться в DLL, и эта DLL должна иметь ту же разрядность, что и приложение, вызывающее событие. А поскольку вы пишете обработчик в управляемом коде, он должен быть нацелен на ту же версию CLR, что и приложение, вызывающее событие. Любой из них помешает вашему крючку работать. Кроме того, ваш хук запускается в контексте приложения, вызывающего событие, поэтому, даже если он запустится, вы не сможете увидеть эффект, поскольку вы находитесь в неправильном процессе. Хук доступности, вероятно, лучший подход, поскольку он позволяет избежать всех этих проблем.   -  person Raymond Chen    schedule 26.11.2011


Ответы (5)


Используйте SetWindowsHookEx для настройки WH_SHELL и найдите событие HSHELL_WINDOWCREATED.

person RichieHindle    schedule 21.06.2009

Конечно, вы можете написать ловушку CBT и следить за HCBT_CREATEWND. См. также SetWindowsHookEx().


Обратите внимание, что это позволит вам получать уведомления о создании всех окон еще до того, как создаваемые окна будут полностью инициализированы. Если все, что вам нужно, это окна верхнего уровня без владельца, предложение RichieHindle может работать лучше...

person Shog9    schedule 21.06.2009

Detours позволит вам прикреплять перехватчики к произвольным функциям Win32. Тем не менее, опрос, вероятно, является более надежным способом решения проблемы: вам не нужно беспокоиться о том, не пропустили ли вы конкретный метод создания окна (сколько их в Win32? Держу пари, что больше одного!), и , конечно, вы не будете переписывать машинный код для функций Windows во время выполнения.

Но, знаешь, твой выбор.

person David Seiler    schedule 21.06.2009
comment
Джеймс должен был внедрить свой код Detours в каждый процесс графического интерфейса, включая новые запущенные. Перехватчики Windows (через SetWindowsHookEx) созданы для того, чтобы делать именно то, что он хочет, и являются официальной частью Windows API. - person RichieHindle; 22.06.2009

Вы можете попробовать библиотеку WinEventHook для autohotkey. Попробуйте изменить пример блокировщика всплывающих окон блокнота следующим образом :

HookProc( hWinEventHook, Event, hWnd, idObject, idChild, dwEventThread, dwmsEventTime ) { if Event ; EVENT_SYSTEM_FOREGROUND = 0x3 {
WinGetTitle, title, ahk_id %hWnd% If (title = "your_window_name" msgbox, your window has been created } }

person Naveen    schedule 28.06.2009

Вот некоторый код, основанный на событиях автоматизации пользовательского интерфейса. Он дает окна, открытые, закрытые и сфокусированные события.

C#

[STAThread]
public static void Main(string[] args)
{
    Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, (sender, e) =>
    {
        var element = (AutomationElement)sender;
        var name = element.Current.Name;
        Console.WriteLine("open: " + name + " hwnd:" + element.Current.NativeWindowHandle);
        Automation.AddAutomationEventHandler(WindowPattern.WindowClosedEvent, element, TreeScope.Element, (s, e2) =>
        {
            Console.WriteLine("close: " + name + " hwnd:" + element.Current.NativeWindowHandle);
        });
    });

    Automation.AddAutomationFocusChangedEventHandler((sender, e) =>
    {
        var element = (AutomationElement)sender;
        var name = element.Current.Name;
        Console.WriteLine("focused: " + name + " hwnd:" + element.Current.NativeWindowHandle);
    });
    Console.ReadLine();
    Automation.RemoveAllEventHandlers();
}

Эквивалент С++:

#include <windows.h>
#include <stdio.h>
#include <uiautomation.h>

// some useful macros
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)

#define SBTRACE wprintf
#define CHECKHR(expr) {hr=(expr);if(FAILED(hr)){ SBTRACE(L"HR FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }  
#define CHECKWIN32(expr) {if(!(expr)){hr = HRESULT_FROM_WIN32(GetLastError()); SBTRACE(L"WIN32 FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }  
#define CHECKARG(expr) {if(!(expr)){ SBTRACE(L"ARG FAILED line:%u file:%s\n", __LINE__, __WFILE__); hr = E_INVALIDARG; goto cleanup; } }  
#define CHECKMEM(expr) {if(!(expr)){ SBTRACE(L"MEM FAILED line:%u file:%s\n", __LINE__, __WFILE__); hr = E_OUTOFMEMORY; goto cleanup; } } 
#define CORELEASE(expr) {if(expr){ expr->Release(); expr = NULL; } } 
#define HR HRESULT hr=S_OK;

class EventHandler :
  public IUIAutomationEventHandler,
  public IUIAutomationFocusChangedEventHandler
{
private:
  LONG _ref;
  IUIAutomation* _automation;
  HWND _hwnd;
  IUIAutomationElement* _sender;

public:
  EventHandler(IUIAutomation* automation, IUIAutomationElement* sender, HWND hwnd) :
    _ref(1),
    _automation(automation),
    _sender(sender),
    _hwnd(hwnd)
  {
    if (sender)
    {
      sender->AddRef();
    }
  }

  ~EventHandler()
  {
    CORELEASE(_sender);
  }

  // IUnknown
  ULONG STDMETHODCALLTYPE AddRef() { ULONG ret = InterlockedIncrement(&_ref); return ret; }
  ULONG STDMETHODCALLTYPE Release() { ULONG ret = InterlockedDecrement(&_ref); if (!ret) { delete this; return 0; } return ret; }
  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface)
  {
    if (riid == __uuidof(IUnknown))
    {
      *ppInterface = (IUIAutomationEventHandler*)this;
    }
    else if (riid == __uuidof(IUIAutomationEventHandler))
    {
      *ppInterface = (IUIAutomationEventHandler*)this;
    }
    else if (riid == __uuidof(IUIAutomationFocusChangedEventHandler))
    {
      *ppInterface = (IUIAutomationFocusChangedEventHandler*)this;
    }
    else
    {
      *ppInterface = NULL;
      return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
  }

  // IUIAutomationFocusChangedEventHandler
  HRESULT STDMETHODCALLTYPE HandleFocusChangedEvent(IUIAutomationElement* sender)
  {
    HWND hwnd = NULL;
    sender->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
    wprintf(L"Window focused hwnd:%p'\n", hwnd);
    return S_OK;
  }

  // IUIAutomationEventHandler
  HRESULT STDMETHODCALLTYPE HandleAutomationEvent(IUIAutomationElement* sender, EVENTID eventID)
  {
    HR;
    HWND hwnd = NULL;
    EventHandler* windowHandler;

    switch (eventID)
    {
    case UIA_Window_WindowOpenedEventId:
      sender->get_CurrentNativeWindowHandle((UIA_HWND*)&hwnd);
      wprintf(L"Window opened hwnd:%p\n", hwnd);

      // register for close on this window
      // we build a new handler, this is the only way to remember the hwnd (the close event doesn't have anything)
      windowHandler = new EventHandler(_automation, sender, hwnd); // implicit addref
      CHECKMEM(windowHandler);
      CHECKHR(_automation->AddAutomationEventHandler(UIA_Window_WindowClosedEventId, sender, TreeScope_Element, NULL, windowHandler));
      break;

    case UIA_Window_WindowClosedEventId:
      wprintf(L"Window closed hwnd:%p\n", _hwnd);
      CHECKHR(_automation->RemoveAutomationEventHandler(UIA_Window_WindowClosedEventId, _sender, this));
      Release(); // we release our own reference, 'this' we be deleted sometime when all COM references are gone. don't do 'delete this'!
      break;
    }

  cleanup:
    return hr;
  }
};

int main()
{
  HR;
  IUIAutomationElement* root = NULL;
  EventHandler* handler = NULL;
  IUIAutomation* automation = NULL;

  CoInitializeEx(NULL, COINIT_MULTITHREADED);
  CHECKHR(CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&automation));

  CHECKHR(automation->GetRootElement(&root));

  handler = new EventHandler(automation, NULL, NULL);
  CHECKMEM(handler);

  CHECKHR(automation->AddAutomationEventHandler(UIA_Window_WindowOpenedEventId, root, TreeScope_Subtree, NULL, handler));
  CHECKHR(automation->AddFocusChangedEventHandler(NULL, handler));

  wprintf(L"Press any key to stop listening for events.\n");
  getchar();

cleanup:
  if (automation != NULL)
  {
    automation->RemoveAllEventHandlers();
    CORELEASE(automation);
  }

  CORELEASE(handler);
  CORELEASE(root);
  CoUninitialize();
  return hr;
}
person Simon Mourier    schedule 06.08.2020