2017-04-12 6 views
0

(これはC#.NET 4.5です)WndProcオーバーロード+アンマネージDLLラッパー:良い方法ですか?

私はいくつかのハードウェアと会話するいくつかのアンマネージドDLLを持っています。私はコードの束をラップし、WinFormで作成できるクラスオブジェクトとして単純なものを手に入れます。

private AvaSpec AS = new AvaSpec(); 

    public AvaSpec_Form() 
    { 
     InitializeComponent(); 

     AS.SpectrumMeasuredEvent += (se, ev) => { SpectrumMeasured(ev); }; 

     AS.Init(this.Handle); 
     AS.Activate(); 

     // configure as desired 
     // AS.l_PrepareMeasData.m_IntegrationDelay = 0; 

     if (AS.DeviceList.Count > 0) 
     { 
      AS.Start(); 
     } 
    } 

ただし、DLLはWndProcを介してメッセージを受信することに依存しています。私はこれを行うために見つけ出すことができる最高の方法は、フォーム上のWndProcメソッドをオーバーロードすることです:

protected override void WndProc(ref Message m) 
    { 
     // catch WndProc messages that AvaSpec defines as its own 
     if (m.Msg == AvaSpec.WM_MEAS_READY || 
       m.Msg == AvaSpec.WM_APP || 
       m.Msg == AvaSpec.WM_DBG_INFOAs || 
       m.Msg == AvaSpec.WM_DEVICE_RESET) 
     { 
      AS.WndProcMessageReceived(ref m); 
     } 

     // else pass message on to default message handler 
     base.WndProc(ref m); 
    } 

オーバーロードメソッドが追加する必要がないように、私は、クラス定義で何とかこのオーバーロードを非表示にすることができますどのようにフォーム自体? IMessageFilterインターフェイスに関する話がありますが、フォームにフィルタを追加するコードが必要になります。どのようにこれをよりエレガントにするためのアイデア?

+0

非表示にすることは何もありません。元のForm.WndProc()としてオーバーライドされたものとして検出されます。 –

+0

私はフォームを移動するまで、IMessageFilterインターフェイスを試してみましたが、何らかの理由でメッセージがオブジェクトに流れなくなりました...? –

答えて

0

私はそれをColin Smithのヒントに基づいて理解しました。

あなたはNativeWindowのからクラスを派生:

https://msdn.microsoft.com/en-us/library/system.windows.forms.nativewindow(v=vs.110).aspx

その後、NativeWindowのクラスオブジェクトに提供して処理するために(あなたには、いくつかの初期化によって渡すこと)、親(フォーム)がハンドルを割り当てます。次に、WndProcメソッドを直接オブジェクトにオーバーロードすることができます。

// object definition 

public class AvaSpec : NativeWindow 
{ 
    protected override void WndProc(ref Message m) 
    { 
     // catch WndProc messages that AvaSpec defines as its own 
     if (m.Msg == AvaSpec.WM_MEAS_READY || 
      m.Msg == AvaSpec.WM_APP || 
      m.Msg == AvaSpec.WM_DBG_INFOAs || 
      m.Msg == AvaSpec.WM_DEVICE_RESET) 
     { 
      WndProcMessageReceived(ref m); 
     } 

     // Call base WndProc for default handling 
     base.WndProc(ref m); 
    } 

...(中略)

public void Init(IntPtr parentHandle) 
    { 
     this.AssignHandle(parentHandle); 

...(中略)

などのように(いくつかのinitを経由して、ポインタを扱う渡す)、それを使用します。

// WinForm definition 

public partial class AvaSpec_X : Form 
{ 
    private AvaSpec AS = new AvaSpec(); 

    public AvaSpec_X() 
    { 
     InitializeComponent(); 

     AS.SpectrumMeasuredEvent += (se, ev) => { SpectrumMeasured(ev); }; 

     AS.Init(this.Handle); 
     AS.Activate(); 

     // configure as desired 
     //AS.l_PrepareMeasData.m_IntegrationDelay = 0; 

     if (AS.DeviceList.Count > 0) 
     { 
      AS.Start(); 
     } 
    } 

...(スナップ)

1

非表示のモードレスの「フォーム」/ウィンドウを作成し、の呼び出しでその.Handleを使用できます。

メインアプリケーションウィンドウにピギーバックするのではなく、別の「ウィンドウ」を使用することで、より優れたカプセル化が提供されます。

たとえば、将来複数のデバイスの処理を同時にサポートする必要がある場合、「別々の」ウィンドウを使用すると、異なるデバイスのメッセージを適切に分離できます。

ハードウェア/デバイスの処理コードでは、「デバイスID」を識別するためにwParamまたはlParamが使用される可能性がありますが、他のものに使用している可能性が高く、識別器として「ウィンドウ宛先」に依存します。

次に、メインアプリのUIスレッドメッセージポンプ...を使って、作成したウィンドウにメッセージを自動的に送り込ませます。

その "ウィンドウ"のメッセージ処理コードでは、WM_DBG_INFOAsなどの特別に登録されたメッセージを含むメッセージを処理し、次にWndProcMessageReceived経由でAvaSpecに転送します。

そのAvaSpecクラスがこれらのメッセージをタイムリーに処理している場合は、複数のUIスレッドの作成を調べる必要があります。あなたのメインアプリのUIスレッドが過負荷状態、またはサイズ変更するときに、他のメッセージなどを処理する「忙しい」だった、ウィンドウを動かしなっていた場合、これは必要になることがあります

など

メッセージをポンプされた別個のUIスレッドを持つことにより、あなたの隠された "デバイス"ウィンドウのために、それはあなたの "デバイス"のためのより良い応答を提供するかもしれません。

注:複数のUIスレッドは高度なトピックであり、いくつかの問題がありますが、基本的にはスレッドを作成し、STA(シングルスレッドアパートメント)を使用するように指示し、ウィンドウフォームを作成してから通常使用しますメッセージポンピングを引き起こすそのフォームのApplication.Run

関連する問題