Насос сообщения в службе Windows.NET

Мне записали службу Windows в C#, который обрабатывает все наше внешнее оборудование ввод-вывод для приложения киоска. Одно из наших новых устройств является USB-устройством, которое идет с API в собственном DLL. У меня есть надлежащий созданный класс обертки P/Invoke. Однако этот API должен быть инициализирован с HWnd к приложению Windows, потому что он использует насос сообщения, чтобы сгенерировать асинхронные события.

Помимо включения запроса к производителю оборудования для предоставления нам API, который не зависит от насоса сообщения Windows, там какой-либо способ вручную инстанцировать насоса сообщения в новом потоке в моей службе Windows, которую я могу передать в этот API? Я должен на самом деле создать полный Класс приложений, или есть ли более низкий уровень класс.NET, который инкапсулирует насос сообщения?

25
задан John Saunders 16 March 2010 в 19:40
поделиться

3 ответа

Спасибо всем за ваши предложения. Richard & overslacked, ссылка, которую вы предоставили в комментариях, была очень полезной. Кроме того, мне не нужно было разрешать службе взаимодействовать с рабочим столом, чтобы вручную запускать перекачку сообщений с помощью 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();
    }
}

Мне пришлось преодолеть несколько препятствий, чтобы заставить это работать. Во-первых, вам необходимо создать форму в том же потоке, в котором вы выполняете Application.Run. Вы также можете получить доступ к свойству Handle только из того же потока, поэтому мне показалось, что проще всего просто инициализировать DLL в этом потоке. Насколько я знаю, он в любом случае ожидает инициализации из потока графического интерфейса.

Кроме того, в моей реализации класс MessagePumpManager является экземпляром Singleton, поэтому для всех экземпляров моего класса устройств работает только один насос сообщений. Убедитесь, что вы действительно лениво инициализируете свой экземпляр singleton, если вы запускаете поток в своем конструкторе. Если вы запускаете поток из статического контекста (такого как частный статический экземпляр MessagePumpManager = new MessagePumpManager ();), среда выполнения никогда не переключает контекст на вновь созданный поток, и вы зайдете в тупик, ожидая запуска насоса сообщений.

39
ответ дан 28 November 2019 в 21:11
поделиться

Вам необходимо создать форму, службы Windows по умолчанию не взаимодействуют с рабочим столом, поэтому вам необходимо настроить службу для взаимодействия с рабочим столом и установить это может быть немного больно. Однако форма не будет видна. Microsoft намеренно усложняет эту задачу из-за проблем с безопасностью.

2
ответ дан 28 November 2019 в 21:11
поделиться

Просто сделайте окно только для сообщений, обозначенное параметром HWND_MESSAGE в вызове CreateWindowEx. Конечно, это код на C, но вы можете легко сделать эти структуры и P/Invoke вызовы в C#.

WNDCLASS w;
HWND handle;
w.hInstance = (HINSTANCE)GetModuleHandle(...); // Associate this module with the window.
w.lpfnWndProc = ... // Your windowproc
w.lpszClassName = ... // Name of your window class

RegisterClass(&w)
handle = CreateWindowEx(0, w.lpszClassName, w.lpszClassName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, wc.hInstance, NULL);
1
ответ дан 28 November 2019 в 21:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: