4

我正在尝试在 winforms 应用程序中创建一个仅消息窗口来接收来自 MFC 库类的窗口消息。

我尝试过 subclassing NativeWindow,并在构造函数中请求这样的窗口句柄:

CreateParams cp = new CreateParams();
cp.Parent = (IntPtr)HWND_MESSAGE;
this.CreateHandle(cp);

但我得到一个 Win32Exception 抛出消息“错误创建窗口句柄”。如何从 Windows 窗体创建仅消息窗口?是否使用NativeWindow了正确的方法?

4

4 回答 4

3

我知道这是 7.5 岁,但以防万一有人发现这个,我想我会回应。我使用了 Microsoft 的TimerNativeWindow 代码并删除了计时器功能。我最终使用了这种方法:

    public class MyNativeWindow : NativeWindow
    {
        private readonly string _caption;
        private const int WmClose = 0x0010;

        [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
        private static readonly HandleRef HwndMessage = new HandleRef(null, new IntPtr(-3));

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        [ResourceExposure(ResourceScope.None)]
        private static extern IntPtr PostMessage(HandleRef hwnd, int msg, int wparam, int lparam);

        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        [ResourceExposure(ResourceScope.Process)]
        private static extern int GetWindowThreadProcessId(HandleRef hWnd, out int lpdwProcessId);

        [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        [ResourceExposure(ResourceScope.Process)]
        private static extern int GetCurrentThreadId();

        public MyNativeWindow(string caption)
        {
            _caption = caption;
        }

        public bool CreateWindow()
        {
            if (Handle == IntPtr.Zero)
            {
                CreateHandle(new CreateParams
                {
                    Style = 0,
                    ExStyle = 0,
                    ClassStyle = 0,
                    Caption = _caption,
                    Parent = (IntPtr)HwndMessage
                });
            }
            return Handle != IntPtr.Zero;
        }


        public void DestroyWindow()
        {
            DestroyWindow(true, IntPtr.Zero);
        }

        private bool GetInvokeRequired(IntPtr hWnd)
        {
            if (hWnd == IntPtr.Zero) return false;
            int pid;
            var hwndThread = GetWindowThreadProcessId(new HandleRef(this, hWnd), out pid);
            var currentThread = GetCurrentThreadId();
            return (hwndThread != currentThread);
        }

        private void DestroyWindow(bool destroyHwnd, IntPtr hWnd)
        {
            if (hWnd == IntPtr.Zero)
            {
                hWnd = Handle;
            }

            if (GetInvokeRequired(hWnd))
            {
                PostMessage(new HandleRef(this, hWnd), WmClose, 0, 0);
                return;
            }

            lock (this)
            {
                if (destroyHwnd)
                {
                    base.DestroyHandle();
                }
            }
        }

        public override void DestroyHandle()
        {
            DestroyWindow(false, IntPtr.Zero);
            base.DestroyHandle();
        }
    }
于 2016-12-15T20:43:14.293 回答
2

试试看:

[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

static IntPtr HWND_MESSAGE = new IntPtr(-3);

protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);
    SetParent(this.Handle, HWND_MESSAGE);
}
于 2009-06-01T20:19:23.430 回答
0

我担心您必须从 a 派生Form,并强制窗口不可见。

另一种方法(在类库可修改的情况下)是在没有窗口的情况下运行消息泵(请参阅Application.RunApplication.AddMessageFilter ,或者如果您更喜欢使用PeekMessage & Co的 pinvokes )。

在这种情况下,您可以使用PostThreadMessage发送消息,方法是让线程 id 运行 Application.Run,​​但实际上您无法与应用程序消息泵线程同步,因为它不等待消息确认。

于 2010-08-02T10:35:15.820 回答
0

我相信您还需要指定一个窗口类。

于 2009-06-01T16:40:47.737 回答