Поток сообщений окна (WndProc | While (GetMEssage)) в .NET Core - PullRequest
0 голосов
/ 03 мая 2018

Я пытаюсь подписаться на оконные сообщения, используя .Net Core

Я могу получать исходные сообщения для создания окна (через pinvoke) и уничтожения сообщений. Но после этого мои созданные окна блокируются и не получают никаких других сообщений.

 public class CustomWindow : IDisposable
{
    delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

    [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Unicode)]
    struct WNDCLASS
    {
        public uint style;
        public IntPtr lpfnWndProc;
        public int cbClsExtra;
        public int cbWndExtra;
        public IntPtr hInstance;
        public IntPtr hIcon;
        public IntPtr hCursor;
        public IntPtr hbrBackground;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string lpszMenuName;
        [MarshalAs(UnmanagedType.LPWStr)]
        public string lpszClassName;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct MSG
    {
        public IntPtr hwnd;
        public uint message;
        public IntPtr wParam;
        public IntPtr lParam;
        public uint time;
    }

    [DllImport("user32.dll", SetLastError = true)]
    static extern UInt16 RegisterClassW([In] ref WNDCLASS lpWndClass);

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr CreateWindowExW(
       UInt32 dwExStyle,
       [MarshalAs(UnmanagedType.LPWStr)]string lpClassName,
       [MarshalAs(UnmanagedType.LPWStr)]string lpWindowName,
       UInt32 dwStyle,
       Int32 x,
       Int32 y,
       Int32 nWidth,
       Int32 nHeight,
       IntPtr hWndParent,
       IntPtr hMenu,
       IntPtr hInstance,
       IntPtr lpParam
    );

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr DefWindowProcW(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool DestroyWindow(IntPtr hWnd);

    private const int ERROR_CLASS_ALREADY_EXISTS = 1410;

    private bool _mDisposed;
    public IntPtr Hwnd;

    public List<uint> Messages { get; set; }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if (!_mDisposed)
        {
            if (disposing)
            {
                // Dispose managed resources
            }

            // Dispose unmanaged resources
            if (Hwnd != IntPtr.Zero)
            {
                DestroyWindow(Hwnd);
                Hwnd = IntPtr.Zero;
            }
        }
    }

    public CustomWindow()
    {
        Messages = new List<uint>();
        var className = "InvisibleWindow";

        _mWndProcDelegate = CustomWndProc;

        // Create WNDCLASS
        WNDCLASS windClass = new WNDCLASS
        {
            lpszClassName = className,
            lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_mWndProcDelegate)
        };

        UInt16 classAtom = RegisterClassW(ref windClass);

        int lastError = Marshal.GetLastWin32Error();

        if (classAtom == 0 && lastError != ERROR_CLASS_ALREADY_EXISTS)
        {
            throw new Exception("Could not register window class");
        }

        const UInt32 WS_OVERLAPPEDWINDOW = 0xcf0000;
        const UInt32 WS_VISIBLE = 0x10000000;


        // Create window
        Hwnd = CreateWindowExW(
            0,
            className,
            "My WIndow",
            WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 300, 400,
            IntPtr.Zero,
            IntPtr.Zero,
            IntPtr.Zero,
            IntPtr.Zero
        );

        Importer.ShowWindow(Hwnd, 1);
        Importer.UpdateWindow(Hwnd);
    }

    private  IntPtr CustomWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
    {
        Messages.Add(msg);
        return DefWindowProcW(hWnd, msg, wParam, lParam);
    }

    private WndProc _mWndProcDelegate;
}

Класс для создания пользовательского окна CustomWndProc получает сообщения. Я пока не выполняю никакой логики, просто пытаюсь заставить вещи работать.

Я пытаюсь выяснить, как я могу сделать это из отдельного потока, чтобы продолжать слушать сообщения, не блокируя при этом основной интерфейс API / GUI / консоли

Могу ли я создать этот класс в отдельном потоке и по-прежнему использовать внедрение зависимостей и иметь доступ к его данным / сообщениям / событиям по своей прихоти. Я знаю, что есть много способов сделать это в .net, но это .net Core.

Что случилось с отрицательными голосами, буквально нет ресурсов, как реализовать это в Net Core, у меня нет доступа к любой из форм / элементов управления .Net, которые упрощают это, я также предоставил полный рабочий класс, если есть Отсутствие подробностей в моем посте, оставьте комментарий. Не голосуйте случайно, без веской причины. Если есть другая ветка, которая объясняет, как это сделать, свяжите ее, а затем уменьшите эту.

 private void GetMessage()
    {
       IntPtr hwnd = _customWindow.Hwnd;
        int bRet;
        while ((bRet = Importer.GetMessage(out var msg, _customWindow.GetHandle, 0, 0)) !=0 )
        {
            if (bRet == -1)
            {
                Console.WriteLine("Error");
            }
            else
            {
                Importer.TranslateMessage(ref msg);
                Importer.DispatchMessage(ref msg);
                Console.WriteLine(_customWindow.Messages.LastOrDefault());
            }
        }
    }

Реализован цикл GetMessage, мое окно теперь получает все сообщения и не блокируется, но теперь блокирует основной поток. Я посмотрю, смогу ли я создать окно в отдельном потоке и запустить цикл сообщений в этом потоке.

1 Ответ

0 голосов
/ 10 мая 2018

В конце концов удалось найти рабочее решение.

В то время как в C ++ созданное окно работает в своем собственном потоке автоматически без какого-либо ввода и может обрабатывать свою собственную очередь сообщений. Кроме того, поскольку в основном это графический интерфейс, именно так и поступают входные данные.

В .Net вы не можете назначать объекты определенному потоку. Таким образом, даже если вы запустите GetMessage Loop в новом потоке или задаче, само окно будет заблокировано из-за того, что оно в основном потоке. Чтобы преодолеть это, запустите C ++ Window и цикл GetMessage в основном потоке и запустите вашу консоль / Gui / APi во втором потоке.

...