WndProc重载+非托管DLL包装器:更好的方法?

时间:2017-04-12 15:40:55

标签: c# dll filter unmanaged wndproc

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

我有一些与某些硬件对话的非托管DLL。我将一堆代码包装成一个简单的东西,作为一个类对象,我可以在WinForm中创建。

.el-1 {
top: 6%;
left: 5%;
motion-path: path('M0.1,0.5c0,0,115.7,24.9,133,122.6');
offset-path: path('M0.1,0.5c0,0,115.7,24.9,133,122.6');
/*motion-offset: 0%;*/
animation: pathy 1.2s 1 ease-in;
animation-delay: 1.60s;
height: 20vh;
width: 20vw; // or auto, or %
}

但是,DLL依赖于通过WndProc接收消息。我能想到的最好的方法是在窗体上重载WndProc方法:

    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();
        }
    }

如何在类定义中以某种方式隐藏此重载,以便不需要将重载方法添加到Form本身?有一些关于IMessageFilter接口的讨论,但它仍然需要表单中的一些代码来添加过滤器。关于如何使这更优雅的任何想法?

2 个答案:

答案 0 :(得分:1)

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

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

例如,如果将来您需要同时支持多个设备的处理......那么“单独”窗口可以很好地分离不同设备的消息。

您的硬件/设备处理代码可能使用wParam或lParam来识别“设备ID”...但它更可能将其用于其他内容,并依赖“窗口目标”作为区分器。

然后让主应用程序UI线程消息泵...自动将消息发送到您创建的窗口。

在你的“窗口”的消息处理代码中,你将处理消息,其中包括特殊的私人注册消息,例如WM_DBG_INFOAs等......然后你通过{{转发回AvaSpec 1}}。

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

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

通过为您隐藏的“设备”窗口提供单独的UI线程,可以为您的“设备”提供更好的响应。

注意:多个UI线程是一个高级主题,并且有一些问题,但基本上它涉及创建一个线程,告诉它使用STA(单线程单元),创建窗口表单,然后通常使用{ {1}}使用该表单引起消息传递。

答案 1 :(得分: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);
    }

...(剪断)

    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();
        }
    }

...(剪断)