谢谢大家的建议。Richard & overslacked,您在评论中提供的链接非常有帮助。此外,我不必允许服务与桌面交互以使用 Application.Run 手动启动消息泵。显然,如果您希望 Windows 自动为您启动消息泵,您只需要允许服务与桌面交互。
为了大家的启迪,这是我最终为这个第 3 方 API 手动启动消息泵的操作:
internal class MessageHandler : NativeWindow
{
public event EventHandler<MessageData> MessageReceived;
public MessageHandler ()
{
CreateHandle(new CreateParams());
}
protected override void WndProc(ref Message msg)
{
// filter messages here for your purposes
EventHandler<MessageData> handler = MessageReceived;
if (handler != null) handler(ref msg);
base.WndProc(ref msg);
}
}
public class MessagePumpManager
{
private readonly Thread messagePump;
private AutoResetEvent messagePumpRunning = new AutoResetEvent(false);
public StartMessagePump()
{
// start message pump in its own thread
messagePump = new Thread(RunMessagePump) {Name = "ManualMessagePump"};
messagePump.Start();
messagePumpRunning.WaitOne();
}
// Message Pump Thread
private void RunMessagePump()
{
// Create control to handle windows messages
MessageHandler messageHandler = new MessageHandler();
// Initialize 3rd party dll
DLL.Init(messageHandler.Handle);
Console.WriteLine("Message Pump Thread Started");
messagePumpRunning.Set();
Application.Run();
}
}
我必须克服一些障碍才能让它发挥作用。一是您需要确保在执行 Application.Run 的同一线程上创建表单。您也只能从同一个线程访问 Handle 属性,因此我发现在该线程上简单地初始化 DLL 也是最简单的。据我所知,无论如何它都希望从 GUI 线程初始化。
此外,在我的实现中,MessagePumpManager 类是一个 Singleton 实例,因此只有一个消息泵针对我的设备类的所有实例运行。如果您在构造函数中启动线程,请确保您真正延迟初始化单例实例。如果您从静态上下文(例如私有静态 MessagePumpManager 实例 = new MessagePumpManager();)启动线程,则运行时将永远不会上下文切换到新创建的线程,并且在等待消息泵启动时您将死锁。