Ответ 1
Спасибо всем за ваши предложения. Ричард и переполненный, ссылка, которую вы предоставили в комментариях, была очень полезна. Кроме того, мне не нужно было позволять службе взаимодействовать с рабочим столом, чтобы вручную запустить насос сообщений с помощью 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, если вы начинаете поток в своем конструкторе. Если вы запускаете поток из статического контекста (например, private static MessagePumpManager instance = new MessagePumpManager();), среда выполнения никогда не переключит контекст во вновь созданный поток, и вы будете заторможены в ожидании запуска насоса сообщений.