C# 强制从主线程调用SetWinEventHook

C# 强制从主线程调用SetWinEventHook,c#,.net,windows,multithreading,pinvoke,C#,.net,Windows,Multithreading,Pinvoke,我试图在新创建的进程上注册一些对象级的WinEvents挂钩,但正如这位官员所说: 对于上下文外事件,该事件在调用SetWinEventHook的同一线程上传递 我的问题是,我从主线程以外的线程调用SetWinEventHook,这将导致主线程中没有收到任何回调。我一直在寻找在主线程中触发(从另一个线程)SetWinEventHook方法调用的方法。知道它是一个控制台应用程序,Invoke和BeginInvoke解决方案不起作用。我还尝试了Events和EventHandler 我希望我的问题不

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

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

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

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

// 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");          
}
输出:

main,tid=1
事件,tid=4//重复次数与创建新进程的次数相同


我也有同样的问题。从任何形式使用Invoke方法:

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

关于

这会有帮助吗:?不,这永远不会起作用。您确实需要一种从事件处理程序运行的线程到另一个线程的方法,该线程生成SetWinEventHook并泵送一个消息循环,以便进行回调。这需要Application.Run(),而不是MessageBox.Show()。您可以从Winforms或WPF应用程序中轻松获得这些信息。或者,如果控制台模式应用程序是一个硬要求,您也可以使用。@HansPassant是否有其他方法来检测不在单独线程中创建/运行的新进程/窗口(我需要该窗口,所以我正在测试process.MAIN_window_HANDLE!=IntPtr.Zero)。我知道EVENT\u OBJECT\u CREATE不是一个选项。@HansPassant如果在后台进程中使用它,你有什么建议吗?@John当然还有另一种方法。但征求意见是错误的做法。你需要问一个问题。