15

有没有办法使用 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);
}
4

5 回答 5

14

用于SetWindowsHookEx设置WH_SHELL挂钩并查找HSHELL_WINDOWCREATED事件。

于 2009-06-21T21:14:07.947 回答
2

当然-您可以编写一个 CBT 钩子并监视HCBT_CREATEWND. 另请参阅SetWindowsHookEx()


请注意,这将允许您在创建的窗口甚至完全初始化之前收到所有窗口创建的通知。如果您只需要无主的顶级窗口,RichieHindle 的建议可能会更好......

于 2009-06-21T21:14:54.140 回答
1

这是一些基于UI 自动化事件的代码。它提供窗口打开、关闭和聚焦事件。

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++ 等价物:

#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 MYTRACE wprintf
#define CHECKHR(expr) {hr=(expr);if(FAILED(hr)){ MYTRACE(L"HR FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }  
#define CHECKWIN32(expr) {if(!(expr)){hr = HRESULT_FROM_WIN32(GetLastError()); MYTRACE(L"WIN32 FAILED line:%u file:%s\n", __LINE__, __WFILE__); goto cleanup; } }  
#define CHECKARG(expr) {if(!(expr)){ MYTRACE(L"ARG FAILED line:%u file:%s\n", __LINE__, __WFILE__); hr = E_INVALIDARG; goto cleanup; } }  
#define CHECKMEM(expr) {if(!(expr)){ MYTRACE(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;
}
于 2020-08-06T22:08:26.577 回答
0

Detours将允许您将挂钩附加到任意 Win32 函数。但是,轮询可能是解决问题的一种更可靠的方法:您不必担心是否错过了特定的窗口创建方法(Win32 中有多少种方法?我敢打赌不止一个!),并且,当然,您不会在运行时重写 Windows 函数的机器代码

但是,你知道,你的电话。

于 2009-06-21T21:15:11.987 回答
0

您可以尝试自动热键的WinEventHook库。尝试使用以下内容修改记事本弹出窗口阻止程序示例

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 } }

于 2009-06-28T01:13:25.333 回答