C# - 等待WinForms消息循环

Jon*_*s W 5 .net c# multithreading message-loop winforms

我必须编写一个C#API来注册全局热键.要接收WM_HOTKEY消息,我使用a System.Windows.Forms.NativeWindow并运行自己的消息循环System.Windows.Forms.Application.Run(ApplicationContext).当用户想要注册一个热键时,他必须运行一个叫RegisterHotkey()停止消息循环的方法System.Windows.Forms.ApplicationContext.ExitThread(),将热键注册到RegisterHotKey()(P/Invoke)函数并再次启动消息循环.这是必需的,因为RegisterHotKey()必须在创建窗口的同一个线程中调用,该窗口必须在运行消息循环的同一个线程中实例化.

问题是,如果用户RegisterHotkey()在启动正在运行消息循环的线程后不久调用该方法,则会在ApplicationContext.ExitThread()之前调用Application.Run(ApplicationContext),因此应用程序将无限期地阻塞.有人知道等待消息循环启动的方法吗?

提前致谢!

Bri*_*eon 5

因此RegisterHotKey需要从创建窗口的同一线程调用并启动消息循环.为什么不将执行注入RegisterHotKey到自定义消息循环线程中?这样您就不需要停止并重新启动消息循环.您可以重复使用您开始使用的第一个并同时避免奇怪的竞争条件.

您可以将委托注入另一个线程,使用ISynchronizeInvoke.Invoke该线程将该委托编组到托管该ISynchronizeInvoke实例的线程上.这是如何做到的.

void Main()
{
  var f = new Form();

  // Start your custom message loop here.
  new Thread(
    () =>
    {
      var nw = NativeWindow.FromHandle(f.Handle);
      Application.Run(new ApplicationContext(f));
    }

  // This can be called from any thread.
  f.Invoke(
    (Action)(() =>
    {
      RegisterHotKey(/*...*/);
    }), null);
}
Run Code Online (Sandbox Code Playgroud)

我不知道......也许你会UnregisterHotKey根据你所追求的行为来打电话.我对这些API并不熟悉,因此我无法评论它们的使用方式.

如果您不希望Form创建任意实例,那么您可能可以通过SendMessage等方式向线程提交自定义消息并将其处理NativeWindow.WndProc以获得与ISynchronizeInvoke方法自动提供的效果相同的效果.