.NET 6中MessageBox.Show()居中父窗体失败问题求助
.NET 6 下 MessageBox 居中父窗体的适配方案
问题根源
你的代码在.NET Framework 4.8正常运行,但在.NET 6中调用SetWindowsHookEx返回0、错误码87(参数无效),核心原因有两个:
- 线程ID获取错误:.NET 6中
AppDomain.GetCurrentThreadId()返回的是托管线程ID,而SetWindowsHookEx需要的是Windows原生线程ID,两者不再一一对应。 - 钩子句柄类型不兼容:原代码中
SetWindowsHookEx返回值定义为int,在64位系统下会截断句柄(64位指针无法存入32位int),导致参数无效。
具体修改步骤
1. 修正Win32 API的P/Invoke定义
更新SetWindowsHookEx、CallNextHookEx并新增GetCurrentThreadId的定义:
public class Win32 { public const int WH_CBT = 5; public const int HCBT_ACTIVATE = 5; // 修正返回值为IntPtr,适配64位系统 [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern IntPtr SetWindowsHookEx(int idHook, WindowsHookProc lpfn, IntPtr hInstance, uint threadId); // 修正hHook参数为IntPtr [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] public static extern int CallNextHookEx(IntPtr hHook, int code, IntPtr wParam, IntPtr lParam); // 添加获取原生线程ID的API [DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId(); // 保留已有API(GetClassName、GetWindowText、GetDlgItemText等) public delegate int WindowsHookProc(int code, IntPtr wParam, IntPtr lParam); }
2. 修改钩子句柄变量类型
将全局的_hHook从int改为IntPtr:
private static IntPtr _hHook = IntPtr.Zero; private static Win32.WindowsHookProc _hookProcDelegate; private static string _msg; private static string _title;
3. 替换线程ID的获取方式
去掉AppDomain.GetCurrentThreadId(),改用Win32.GetCurrentThreadId()获取原生线程ID:
public static DialogResult Show(string msg, string title, MessageBoxButtons btns, MessageBoxIcon icon) { _hookProcDelegate = new Win32.WindowsHookProc(HookCallback); _msg = msg; _title = title; // 使用原生线程ID替代托管线程ID _hHook = Win32.SetWindowsHookEx(Win32.WH_CBT, _hookProcDelegate, IntPtr.Zero, Win32.GetCurrentThreadId()); DialogResult rslt = MessageBox.Show(msg, title, btns, icon); Unhook(); return rslt; }
4. 修正Unhook函数(若存在)
确保Unhook函数中调用的UnhookWindowsHookEx参数为IntPtr类型:
private static void Unhook() { if (_hHook != IntPtr.Zero) { Win32.UnhookWindowsHookEx(_hHook); _hHook = IntPtr.Zero; } } // 补充UnhookWindowsHookEx的P/Invoke定义 [DllImport("user32.dll", SetLastError = true)] public static extern bool UnhookWindowsHookEx(IntPtr hhk);
验证说明
修改后,SetWindowsHookEx将能正确创建钩子,HookCallback会被触发,从而实现MessageBox居中父窗体的逻辑。该方案适配.NET 6及以上的WinForms项目,同时兼容64位系统。
内容的提问来源于stack exchange,提问作者Unis
相关产品推荐
相关产品推荐

