【问题标题】:Force SetWinEventHook to be called from main thread强制从主线程调用 SetWinEventHook
【发布时间】:2014-02-27 22:19:50
【问题描述】:

我正在尝试在新创建的进程上注册一些对象级 WinEvents 挂钩,但正如官方 documentation 所说:

对于上下文外事件,事件在调用 SetWinEventHook 的同一线程上传递。

我的问题是我从主线程以外的线程调用 SetWinEventHook,这将导致在主线程中没有收到任何回调。我一直在寻找一种在主线程中触发(从另一个线程)SetWinEventHook 方法调用的方法。知道这是一个控制台应用程序,Invoke 和 BeginInvoke 解决方案不起作用。我还尝试了事件和事件处理程序。

我希望我的问题不会被误解。这是代码和输出。

// storing the callback as a field to make sure the garbage collector do not move it
// while being used in managed code, this is easier than using GCHandle 
static WinEventDelegate procDelegate = new Native.WinEventDelegate(WinEventProc);

static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, 
    int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
    {
        Console.WriteLine("callback, tid = " + Thread.CurrentThread.ManagedThreadId);
    }

ManagementEventWatcher processStartEvent = new ManagementEventWatcher("SELECT * FROM Win32_ProcessStartTrace");

void processStartEvent_EventArrived(object sender, EventArrivedEventArgs e)
{
    string processName = e.NewEvent.Properties["ProcessName"].Value.ToString();
    int processID = Convert.ToInt32(e.NewEvent.Properties["ProcessID"].Value);
    Process process = Process.GetProcessById(processID);
    IntPtr hook = SetWinEventHook(eventId, eventId, IntPtr.Zero, procDelegate, (uint)process.Id, 
            GetWindowThreadProcessId(process.MainWindowHandle, IntPtr.Zero),
            Native.WINEVENT_OUTOFCONTEXT | Native.WINEVENT_SKIPOWNPROCESS | Native.WINEVENT_SKIPOWNTHREAD); 
    if (hook == IntPtr.Zero)  Console.WriteLine("Hooking failed");
    Console.WriteLine("event, tid = " + Thread.CurrentThread.ManagedThreadId);
}

void watchProcess()
{
    processStartEvent.EventArrived += new EventArrivedEventHandler(processStartEvent_EventArrived);
    processStartEvent.Start();
}

static void Main(string[] args)
{
        Console.WriteLine("main, tid = " + Thread.CurrentThread.ManagedThreadId);
        watchProcess(); 
        MessageBox.Show("Message loop");          
}

输出:

主要,tid = 1
event, tid = 4 // 重复创建新进程的次数

【问题讨论】:

  • 不,这永远行不通。您确实需要一种从运行事件处理程序的线程到另一个线程的方法,该线程使 SetWinEventHook and 泵送一个消息循环,以便可以进行回调。这需要 Application.Run(),而不是 MessageBox.Show()。您可以轻松地从 Winforms 或 WPF 应用程序中获得它。或者,如果控制台模式应用程序是硬性要求,您可以使用 this class
  • @HansPassant 是否有另一种方法来检测新的进程/窗口(我需要窗口,所以我正在测试 process.MAIN_WINDOW_HANDLE != IntPtr.Zero)创建不是单独创建/运行线。我知道 EVENT_OBJECT_CREATE 不是一个选项。
  • @HansPassant 如果将其用于后台进程,您有什么建议?
  • @John 当然还有另一种方法。但是在 cmets 中询问是错误的方法。你需要问一个问题。

标签: c# .net windows multithreading pinvoke


【解决方案1】:

遇到了同样的问题。使用任何形式的 Invoke 方法:

            this.Invoke(new MethodInvoker(() => StartEventListener()));

问候

【讨论】:

    猜你喜欢
    • 2020-10-30
    • 1970-01-01
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多