c# - .NET Windows 服务中的消息泵

标签 c# .net service message-pump

我有一个用 C# 编写的 Windows 服务,用于处理信息亭应用程序的所有外部硬件 I/O。我们的新设备之一是 USB 设备,它在 native DLL 中带有 API。我创建了一个适当的 P/Invoke 包装器类。但是,此 API 必须使用 Windows 应用程序的 HWnd 进行初始化,因为它使用消息泵来引发异步事件。

除了请求硬件制造商为我们提供不依赖于 Windows 消息泵的 API 之外,还有什么方法可以在我可以传递的 Windows 服务的新线程中手动实例化消息泵进入这个API?我真的必须创建一个完整的应用程序类,还是有一个封装消息泵的较低级别的 .NET 类?

最佳答案

感谢大家的建议。 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 类是一个单例实例,因此只有一个消息泵为我的设备类的所有实例运行。如果您在构造函数中启动线程,请确保您真正延迟初始化了您的单例实例。如果您从静态上下文(例如 private static MessagePumpManager instance = new MessagePumpManager();)启动线程,运行时将永远不会将上下文切换到新创建的线程,并且您将在等待消息泵启动时死锁。

关于c# - .NET Windows 服务中的消息泵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2443867/

相关文章:

c# - JavaScriptSerializer C# 和泛型(我认为是新手犯的错误!)

c# - 从不受信任的域生成 GPO 报告

.net - DataGridView 排序和例如.NET 中的 BindingList<T>

android - 从服务运行中收集加速度计数据

c# - Windows 服务无法启动 'Error 1053: The service did not respond to the start or control request in timely fashion'

c# - 为什么 EF Core 更新无法更新已修改的列

c# - 在不解析堆栈的情况下将异常位置获取到 Logger 方法中?

c# - 使用扩展方法将字符串转换为十进制

c# - .net core 是否支持代码契约?

javascript - 报告服务出现奇怪的 IE 渲染问题