Pic*_*les 25 .net c# service message-pump
我有一个用C#编写的Windows服务,它处理自助服务终端应用程序的所有外部硬件I/O. 我们的新设备之一是USB设备,它在本机DLL中附带API.我创建了一个正确的P/Invoke包装类.但是,必须使用HWnd将此API初始化为Windows应用程序,因为它使用消息泵来引发异步事件.
除了向硬件制造商请求我们提供不依赖于Windows消息泵的API之外,有没有办法在我的Windows服务中的新线程中手动实例化消息泵,我可以将其传递给此API ?我是否真的必须创建一个完整的Application类,或者是否有一个封装消息泵的低级.NET类?
Pic*_*les 39
谢谢大家的建议.Richard&overlacked,您在评论中提供的链接非常有帮助.此外,我不必允许服务与桌面交互,以便使用Application.Run手动启动消息泵.显然,如果您希望Windows自动为您启动消息泵,您只需要允许服务与桌面交互.
对于每个人的启发,以下是我最终为第三方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();
}
}
Run Code Online (Sandbox Code Playgroud)
我必须克服一些障碍才能让它发挥作用.一个是你需要确保在执行Application.Run的同一个线程上创建Form.您也只能从同一个线程访问Handle属性,所以我发现在该线程上简单地初始化DLL也是最简单的.据我所知,无论如何,它都希望从GUI线程初始化.
此外,在我的实现中,MessagePumpManager类是一个Singleton实例,因此只有一个消息泵为我的设备类的所有实例运行.如果在构造函数中启动线程,请确保您真正延迟初始化单例实例.如果从静态上下文(例如私有静态MessagePumpManager instance = new MessagePumpManager();)启动线程,则运行时永远不会将上下文切换到新创建的线程,并且在等待消息泵启动时您将死锁.