You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6中MessageBox.Show()居中父窗体失败问题求助

.NET 6 下 MessageBox 居中父窗体的适配方案

问题根源

你的代码在.NET Framework 4.8正常运行,但在.NET 6中调用SetWindowsHookEx返回0、错误码87(参数无效),核心原因有两个:

  1. 线程ID获取错误:.NET 6中AppDomain.GetCurrentThreadId()返回的是托管线程ID,而SetWindowsHookEx需要的是Windows原生线程ID,两者不再一一对应。
  2. 钩子句柄类型不兼容:原代码中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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 14:15:40