tag remarks generate example c# .net service message-pump

c# - remarks - Bomba de mensajes en el servicio.NET de Windows



remarks c# (3)

Tengo un servicio de Windows escrito en C # que maneja todas nuestras E / S de hardware externo para una aplicación de kiosco. Uno de nuestros nuevos dispositivos es un dispositivo USB que viene con una API en una DLL nativa. Tengo una clase de envoltorio P / Invoke adecuada creada. Sin embargo, esta API debe inicializarse con un HWnd a una aplicación de Windows porque utiliza el bombeo de mensajes para generar eventos asíncronos.

Además de presentar una solicitud al fabricante del hardware para que nos proporcione una API que no dependa de una bomba de mensajes de Windows, ¿hay alguna manera de crear una instancia manual de una bomba de mensajes en un nuevo hilo en mi Servicio de Windows que pueda pasar a esta API? ? ¿Realmente tengo que crear una clase de aplicación completa, o hay una clase de .NET de nivel inferior que encapsula una bomba de mensajes?


Debe crear un Formulario, los servicios de Windows no interactúan con el escritorio de manera predeterminada, por lo que debe configurar el servicio para que interactúe con el escritorio y su instalación puede ser un poco molesto. El formulario no será visible sin embargo. Microsoft ha estado haciendo esto cada vez más difícil debido a problemas de seguridad.


Gracias a todos por sus sugerencias. Richard y rezagado, el enlace que proporcionó en los comentarios fue muy útil. Además, no tuve que permitir que el servicio interactúe con el escritorio para iniciar manualmente un bombeo de mensajes con Application.Run. Aparentemente, solo necesita permitir que el servicio interactúe con el escritorio si desea que Windows inicie un bombeo de mensajes automáticamente para usted.

Para la edificación de todos, esto es lo que terminé haciendo para iniciar manualmente un bombeo de mensajes para esta API de terceros:

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(); } }

Tuve que superar algunos obstáculos para que esto funcionara. Una es que debe asegurarse de crear el Formulario en el mismo hilo que ejecuta Application.Run. También puede acceder a la propiedad Handle desde ese mismo hilo, por lo que me resultó más fácil simplemente inicializar la DLL en ese hilo. Por lo que sé, está esperando que se inicialice desde un hilo GUI de todos modos.

Además, en mi implementación, la clase MessagePumpManager es una instancia de Singleton, por lo que solo se ejecuta un bombeo de mensajes para todas las instancias de mi clase de dispositivo. Asegúrese de que realmente inicie su instancia de singleton de manera perezosa si inicia el subproceso en su constructor. Si inicia el subproceso desde un contexto estático (como, por ejemplo, una instancia privada de MessagePumpManager estática = new MessagePumpManager ();), el tiempo de ejecución nunca cambiará de contexto al subproceso recién creado, y quedará bloqueado mientras espera que se inicie el bombeo del mensaje.


Solo cree una ventana de solo mensaje, indicada por el parámetro HWND_MESSAGE en la llamada a CreateWindowEx. Por supuesto, este es el código C, pero puede hacer fácilmente estas estructuras y llamadas P/Invoke en 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);