ご提案いただきありがとうございます。リチャードと怠け者、コメントで提供したリンクは非常に役に立ちました。また、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();
}
}
これを機能させるには、いくつかのハードルを克服する必要がありました。1 つは、Application.Run を実行するのと同じスレッドでフォームを作成する必要があることです。また、Handle プロパティには同じスレッドからしかアクセスできないため、そのスレッドでも DLL を単純に初期化するのが最も簡単であることがわかりました。とにかく、GUIスレッドから初期化されることを期待しています。
また、私の実装では、MessagePumpManager クラスは Singleton インスタンスであるため、デバイス クラスのすべてのインスタンスに対して 1 つのメッセージ ポンプのみが実行されます。コンストラクターでスレッドを開始する場合は、必ずシングルトン インスタンスを遅延初期化してください。静的コンテキスト (private static MessagePumpManager instance = new MessagePumpManager(); など) からスレッドを開始すると、ランタイムは新しく作成されたスレッドにコンテキストを切り替えることはなく、メッセージ ポンプの開始を待機している間にデッドロックが発生します。