Window .NET Core 中的消息循环(WndProc | While (GetMEssage))线程
Window message loop ( WndProc | While (GetMEssage)) thread in .NET Core
我正在尝试使用 .Net Core
订阅 window 消息
我能够接收初始消息以创建 window(通过 pinvoke)和销毁消息。但在那之后我创建的 windows 被阻止并且没有收到任何其他消息。
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;
}
Class 创建自定义 window CustomWndProc 接收消息。我还没有在那里执行任何逻辑,只是想让事情正常进行。
我想弄清楚如何从一个单独的线程执行此操作,以继续收听消息,同时又不阻塞主 api/gui/console 接口
我可以在单独的线程中创建这个 class 并且仍然使用依赖注入并可以随心所欲地访问它的 data/messages/events 吗?我知道在 .net 中有很多方法可以做到这一点,但这是 .net Core。
反对票怎么了,实际上没有资源如何在 Net Core 中实现它,我无法访问任何简化此操作的 .Net forms/controls,我还提供了完整的工作 class, 如果我的 post 中缺少详细信息,请发表评论。不要在没有充分理由的情况下随机投票给人们。如果有另一个线程解释了如何做到这一点,link 它然后对这个线程投反对票。
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 循环,我的 window 现在接收所有消息并且没有被阻塞,但它现在阻塞了主线程。我会看看我是否可以在单独的线程上创建 window 并在该线程上创建 运行 消息循环。
最终找到了可行的解决方案。
而在 C++ 中,created window 在其自己的线程中自动工作,无需任何输入,并且能够处理自己的消息队列。也因为它主要是 GUI,所以无论如何都是这样接收输入的。
在 .Net 中,您不能将对象分配给特定线程。因此,即使您在新线程或任务中启动 GetMessage Loop,window 本身也会被阻塞,因为它在主线程中。
为了克服这个问题,运行 C++ Window 和 GetMessage 在主线程中循环,运行 你的 console/Gui/APi 在第二个线程中循环。
我正在尝试使用 .Net Core
订阅 window 消息我能够接收初始消息以创建 window(通过 pinvoke)和销毁消息。但在那之后我创建的 windows 被阻止并且没有收到任何其他消息。
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;
}
Class 创建自定义 window CustomWndProc 接收消息。我还没有在那里执行任何逻辑,只是想让事情正常进行。
我想弄清楚如何从一个单独的线程执行此操作,以继续收听消息,同时又不阻塞主 api/gui/console 接口
我可以在单独的线程中创建这个 class 并且仍然使用依赖注入并可以随心所欲地访问它的 data/messages/events 吗?我知道在 .net 中有很多方法可以做到这一点,但这是 .net Core。
反对票怎么了,实际上没有资源如何在 Net Core 中实现它,我无法访问任何简化此操作的 .Net forms/controls,我还提供了完整的工作 class, 如果我的 post 中缺少详细信息,请发表评论。不要在没有充分理由的情况下随机投票给人们。如果有另一个线程解释了如何做到这一点,link 它然后对这个线程投反对票。
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 循环,我的 window 现在接收所有消息并且没有被阻塞,但它现在阻塞了主线程。我会看看我是否可以在单独的线程上创建 window 并在该线程上创建 运行 消息循环。
最终找到了可行的解决方案。
而在 C++ 中,created window 在其自己的线程中自动工作,无需任何输入,并且能够处理自己的消息队列。也因为它主要是 GUI,所以无论如何都是这样接收输入的。
在 .Net 中,您不能将对象分配给特定线程。因此,即使您在新线程或任务中启动 GetMessage Loop,window 本身也会被阻塞,因为它在主线程中。 为了克服这个问题,运行 C++ Window 和 GetMessage 在主线程中循环,运行 你的 console/Gui/APi 在第二个线程中循环。