Окно цикла сообщений ( WndProc | While (GetMEssage)) в.NET Core
Я пытаюсь подписаться на оконные сообщения, используя.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 ответ
В итоге удалось найти рабочее решение.
В то время как в C++ созданное окно работает в своем собственном потоке автоматически без какого-либо ввода и может обрабатывать свою собственную очередь сообщений. Кроме того, потому что это в первую очередь GUI, это то, как ввод в любом случае.
В.Net вы не можете назначать объекты конкретному потоку. Таким образом, даже если вы запустите GetMessage Loop в новом потоке или задаче, само окно будет заблокировано из-за того, что оно находится в основном потоке. Чтобы преодолеть это, запустите C++ Window и цикл GetMessage в основном потоке и запустите вашу консоль /Gui/APi во втором потоке.