Как создать окно только для сообщений из форм Windows? - PullRequest
2 голосов
/ 01 июня 2009

Я пытаюсь создать окно только для сообщений для получения оконных сообщений из класса библиотеки MFC в приложении winforms.

Я пытался создать подкласс NativeWindow, и в конструкторе запрашиваю дескриптор окна, например:

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

но я получаю Win32Exception с сообщением "Ошибка создания дескриптора окна". Как создать окно только для сообщений из форм Windows? Является ли использование NativeWindow правильным подходом?

Ответы [ 4 ]

3 голосов
/ 15 декабря 2016

Я знаю, что это 7,5 лет, но на случай, если кто-нибудь найдет это, я подумал, что отвечу. Я использовал Microsoft TimerNativeWindow code и удалил функцию таймера. Я закончил тем, что использовал этот подход:

    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();
        }
    }
1 голос
/ 02 июня 2009

Попробуйте это:

[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);
}
0 голосов
/ 02 августа 2010

Боюсь, что вы должны получить от Form и заставить окно невидимым.

Другой подход (в случае, если библиотека классов является изменяемой) - запускать насос сообщений без окна (см. Application.Run и Application.AddMessageFilter , или, если вы предпочитаете пинвоки с использованием PeekMessage & Co).

В этом случае вы можете отправлять сообщения, используя PostThreadMessage , имея идентификатор потока, который запускается Application.Run, но на самом деле вы не можете синхронизироваться с потоком сообщения приложения, поскольку он не ожидает подтверждения сообщения.

0 голосов
/ 01 июня 2009

Полагаю, вам также нужно указать класс окна.

...