C# WndProc过载+;非托管DLL包装器:更好的方法?

C# WndProc过载+;非托管DLL包装器:更好的方法?,c#,dll,filter,unmanaged,wndproc,C#,Dll,Filter,Unmanaged,Wndproc,(顺便说一句,这里是C#NET 4.5) 我有一些非托管DLL,可以与一些硬件进行通信。我包装了一堆代码,得到了一些简单的东西,比如类对象,我可以在WinForm中创建它 private AvaSpec AS = new AvaSpec(); public AvaSpec_Form() { InitializeComponent(); AS.SpectrumMeasuredEvent += (se, ev) => { Spectr

(顺便说一句,这里是C#NET 4.5)

我有一些非托管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接口的讨论,但它仍然需要一些表单中的代码来添加过滤器。关于如何使其更加优雅,您有什么想法吗?

您可以创建一个隐藏的无模式“表单”/窗口,然后在调用
'AS.Init'
时使用其
.Handle

通过使用一个单独的“窗口”而不是背驮到主应用程序窗口上,它提供了更好的封装

例如,如果将来您需要支持同时处理多个设备……那么“分离”窗口将能够很好地分离不同设备的消息

您的硬件/设备处理代码可能使用wParam或lParam来标识“设备id”……但更可能是将它们用于其他用途,并依赖“窗口目标”作为区分器

然后让主应用程序UI线程消息泵…自动向您创建的窗口发送消息

在该“窗口”的消息处理代码中,您将处理消息,其中包括特殊的私人注册消息,如WM_DBG_INFOAs等,然后通过
WndProcMessageReceived
转发回
AvaSpec

如果AvaSpec类依赖于您及时处理这些消息,那么您可能需要探索创建多个UI线程

如果您的主应用程序UI线程过载,或者正在“忙于”处理其他消息(例如,调整大小、移动窗口等),则可能需要这样做

通过使用一个单独的UI线程为隐藏的“设备”窗口发送消息,它可能会为“设备”提供更好的响应


注意:多UI线程是一个高级主题,存在一些问题,但基本上它包括创建一个线程,告诉它使用STA(单线程单元),创建窗口窗体,然后通常使用
应用程序。使用该表单运行
以引起消息泵送。

好的,我根据科林·史密斯的提示找到了它

从NativeWindow派生类:

然后将父(表单)句柄(通过一些初始化传递)分配给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);
    }
…(剪报)

…(剪报)

并使用它(通过某个init传递句柄指针),如下所示:


…(snip)

没有什么可隐藏的,它与您覆盖的原始表单一样可见和受保护。WndProc()我尝试了IMessageFilter接口,它可以工作,直到我移动表单,并且由于某种原因消息停止流向对象。。。?
    public void Init(IntPtr parentHandle)
    {
        this.AssignHandle(parentHandle);
// 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();
        }
    }