Спасибо всем за ваши предложения. 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 в этом потоке. Насколько я знаю, он все равно ожидает инициализации из потока GUI.
Кроме того, в моей реализации класс MessagePumpManager является экземпляром Singleton, поэтому для всех экземпляров моего класса устройств работает только один насос сообщений. Убедитесь, что вы действительно лениво инициализируете свой экземпляр singleton, если запускаете поток в своем конструкторе. Если вы запускаете поток из статического контекста (такого как частный статический экземпляр MessagePumpManager = new MessagePumpManager ();), среда выполнения никогда не переключится в контекст во вновь созданный поток, и вы будете в тупике, ожидая запуска насоса сообщений. *