How can I be notified when a new window is created on Win32?

前端 未结 5 1575
不思量自难忘°
不思量自难忘° 2020-12-08 11:29

Is there a way using Win32, to register for notifications when a new window is created. I\'m trying to keep a list of current open windows, but am now just polling the list

5条回答
  •  旧巷少年郎
    2020-12-08 12:24

    Here is some code based on UI automation events. It gives window opened, closed, and focused events.

    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();
    }
    

    C++ equivalent:

    #include 
    #include 
    #include 
    
    // 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;
    }
    

提交回复
热议问题