2010-03-14 2 views
24

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

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

+4

Отметьте эту тему, это может оказаться полезным: http://connect.microsoft.com/VisualStudio/feedback/details/241133/detecting-a-wm-timechange-event-in-a-net-windows-service – overslacked

+0

@overslacked, это действительно так. Он точно говорит, как это сделать. –

+0

@overslacked Я знаю, что это старый вопрос, поэтому неудивительно, что ссылка MS Connect больше не работает. Но поскольку содержание этой ссылки, по-видимому, имеет решающее значение для обсуждения здесь, мне было интересно, есть ли новая связь. Извините, что вы вызываете хлопот! – Sabuncu

ответ

38

Спасибо всем за ваши предложения. Ричард & переполнен, ссылка, которую вы предоставили в комментариях, была очень полезна. Кроме того, мне не нужно было позволять службе взаимодействовать с рабочим столом, чтобы вручную запустить насос сообщений с помощью 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 в этом потоке. Насколько я знаю, он все равно будет инициализирован из потока графического интерфейса.

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

+3

Спасибо, что нашли время, чтобы опубликовать решение вашей проблемы - вы просто спасли мне часы работы. – Basic

+0

Спасибо ... кажется, работает, однако в моем случае, поскольку моя 3-я DLL публикует события .net, и эти события поднимаются в другом потоке, все работает не так, как ожидалось ... – JobaDiniz

1

Просто создайте окно только для сообщений, обозначенное параметром 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

Но разве это работает с Сервисом? –

+0

Конечно, не нужно использовать вызовы P/Invoke для создания окна. –

+0

Я не думаю, что вы можете сделать окно HWND_MESSAGE без вызова CreateWindowEx. – jaws

2

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

+0

Интересное предложение. Однако разрешение на взаимодействие с рабочим столом не является вариантом. Я, конечно, не хочу, чтобы окна были видны. Сам API не имеет визуальных компонентов, просто они решили использовать насос сообщений для уведомления абонентов о асинхронных событиях. Требование, чтобы службе разрешалось взаимодействовать с рабочим столом для запуска насоса сообщений? – Pickles

+0

Окно не будет видно. Да, это требование. –

+0

См. Https://connect.microsoft.com/VisualStudio/feedback/details/241133/detecting-a-wm-timechange-event-in-a-net-windows-service?wa=wsignin1.0, который имеет шаг за шагом инструкции. –