2017-04-12 107 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用这种形式来引起消息泵送。