2017-04-12 50 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

好的,我根據科林史密斯的提示計算出來的。

您從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); 
    } 

...(SNIP)

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

...(SNIP)

,並用它(通過處理通過一些初始化指針),像這樣:

// 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

您可以創建一個隱藏的非模態「窗體」/窗口,然後在調用'AS.Init'時使用其.Handle

通過使用單獨的「窗口」而不是捎帶到主應用程序窗口上,它提供了更好的封裝。

例如,如果將來您需要同時支持多個設備的處理......那麼「獨立」窗口將使不同設備的消息能夠良好分離。

您的硬件/設備處理代碼可能使用wParam或lParam來標識「設備ID」......但它更有可能將它們用於別的東西,並依靠「窗口目標」作爲標識符。

然後讓主應用程序UI線程消息泵...自動將消息發送到您創建的窗口。

在消息處理代碼爲「窗口」,你會處理的消息,其中包括特殊私下注冊信息,如WM_DBG_INFOAs,等...然後您可以通過WndProcMessageReceived向前回AvaSpec

如果該AvaSpec類依賴於您及時處理這些消息,那麼您可能需要探索創建多個UI線程。

這可能需要如果你的主應用程序UI線程被擠破頭,或者是「忙」處理其他消息,例如調整大小時,移動窗口,等等

通過具有即抽消息的單獨UI線程對於隱藏的「設備」窗口,則可能會爲您的「設備」提供更好的響應。

注意:多個UI線程是一個高級主題,並且有一些疑難問題,但基本上它涉及到創建線程,告訴它使用STA(單線程單元),創建窗口窗體,然後通常使用Application.Run用這種形式來引起消息泵送。