.Net Core 2.0中PostThreadMessage调用失败如何解决?
解决.NET Core 2.0中PostThreadMessage调用失败的问题
我来帮你分析下问题所在,以及如何修复:
核心问题
你的代码在.NET Framework中正常,但在.NET Core里失败,主要有两个关键原因:
- 线程ID不匹配:
AppDomain.GetCurrentThreadId()在.NET Framework中返回的是原生Win32线程ID,但在.NET Core中,它返回的是托管线程ID——这个ID和系统层面的线程ID不是一回事,PostThreadMessage找不到对应的目标线程,自然返回false。 - 错误码获取不正确:直接调用
GetLastError()在.NET Core中不可靠,因为CLR在P/Invoke调用后可能会执行一些内部操作,覆盖了Win32的错误状态。应该使用Marshal.GetLastWin32Error()来获取准确的错误码。
修复步骤
1. 获取正确的原生线程ID
导入Kernel32.dll的GetCurrentThreadId()函数,它会返回当前线程的原生Win32 ID:
[DllImport("Kernel32.dll")] public static extern uint GetCurrentThreadId();
然后在MyThread方法中用这个函数替换AppDomain.GetCurrentThreadId():
private static void MyThread(object obj) { threadId = GetCurrentThreadId(); // 改用原生线程ID MSG Msg = new MSG(); var RetVal = GetMessage(out Msg, IntPtr.Zero, 0, 0); Console.WriteLine(RetVal); }
2. 正确获取Win32错误码
把GetLastError()调用替换为Marshal.GetLastWin32Error(),并且确保在PostThreadMessage调用后立即获取,避免CLR操作覆盖错误状态:
bool status = PostThreadMessage(threadId, 0, UIntPtr.Zero, IntPtr.Zero); Int32 err = Marshal.GetLastWin32Error(); // 替换为这个方法
3. (可选)更可靠的线程同步
你当前用Thread.Sleep(100)来确保线程已经进入消息循环,但这种方式不够可靠。可以用ManualResetEvent来实现精确同步:
private static ManualResetEvent _threadReady = new ManualResetEvent(false); static void Main(string[] args) { var mMsgThread = new Thread(MyThread); mMsgThread.Priority = ThreadPriority.Highest; mMsgThread.Start(); _threadReady.WaitOne(); // 等待线程准备好接收消息 bool status = PostThreadMessage(threadId, 0, UIntPtr.Zero, IntPtr.Zero); Int32 err = Marshal.GetLastWin32Error(); } private static void MyThread(object obj) { threadId = GetCurrentThreadId(); MSG Msg = new MSG(); _threadReady.Set(); // 通知主线程已准备好 var RetVal = GetMessage(out Msg, IntPtr.Zero, 0, 0); Console.WriteLine(RetVal); }
完整修改后的代码
using System; using System.Runtime.InteropServices; using System.Threading; namespace ConsoleApp2 { class Program { [DllImport("user32.dll")] public static extern int GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool PostThreadMessage(uint threadId, uint msg, UIntPtr wParam, IntPtr lParam); [DllImport("Kernel32.dll")] public static extern uint GetCurrentThreadId(); [StructLayout(LayoutKind.Sequential)] public struct MSG { public IntPtr hwnd; public uint message; public IntPtr wParam; public IntPtr lParam; public uint time; } private static uint threadId = 0; private static ManualResetEvent _threadReady = new ManualResetEvent(false); static void Main(string[] args) { var mMsgThread = new Thread(MyThread); mMsgThread.Priority = ThreadPriority.Highest; mMsgThread.Start(); _threadReady.WaitOne(); bool status = PostThreadMessage(threadId, 0, UIntPtr.Zero, IntPtr.Zero); Int32 err = Marshal.GetLastWin32Error(); Console.WriteLine($"Post status: {status}, Error code: {err}"); } private static void MyThread(object obj) { threadId = GetCurrentThreadId(); MSG Msg = new MSG(); _threadReady.Set(); var RetVal = GetMessage(out Msg, IntPtr.Zero, 0, 0); Console.WriteLine($"GetMessage returned: {RetVal}"); } } }
这样修改后,你的代码应该就能在.NET Core 2.0中正常运行了,PostThreadMessage会成功将消息发送到目标线程的消息队列,GetMessage也能接收到消息返回。
内容的提问来源于stack exchange,提问作者giraffe_head
相关产品推荐
相关产品推荐

