/* ----------------------------------------------------------
文件名稱:FormHelper.cs
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Splash.Windows.Forms
{
/// <summary>
/// 窗體擴展功能:
/// 1.子窗體自動顯示在父窗體中心位置
/// </summary>
public static class FormHelper
{
/// <summary>
/// 子窗體自動顯示在父窗體中心位置
/// </summary>
/// <param name="owner">要中心化子窗體的窗體</param>
/// <remarks>擴展方法</remarks>
public static void CenterChild(this IWin32Window owner)
{
CenterChildHelper helper = new CenterChildHelper();
helper.Run(owner);
}
/// <summary>
/// 基於Hook實現子窗體自動顯示在父窗體中心位置
/// </summary>
private class CenterChildHelper
{
private const Int32 WH_CBT = 5;
private const Int32 HCBT_ACTIVATE = 5;
private const Int32 GWL_HINSTANCE = -6;
private IntPtr _hhk; // 鉤子句柄
private IntPtr _parent; // 父窗體句柄
private GCHandle _gch;
public void Run(IWin32Window owner)
{
NativeMethods.CBTProc CenterChildHookProc = new NativeMethods.CBTProc(CenterChildCallBack);
// 分配新的GCHandle,保護對象不被垃圾回收
_gch = GCHandle.Alloc(CenterChildHookProc);
_parent = owner.Handle; // 父窗體句柄
// 注意:dwThreadId為System.Threading.Thread.CurrentThread.ManagedThreadId不起作用
_hhk = NativeMethods.SetWindowsHookEx(WH_CBT, CenterChildHookProc, IntPtr.Zero, NativeMethods.GetCurrentThreadId());
}
private IntPtr CenterChildCallBack(Int32 nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode == HCBT_ACTIVATE)
{ // 父窗體
NativeMethods.RECT formRect;
NativeMethods.GetWindowRect(_parent, out formRect);
// 子窗體
NativeMethods.RECT messageBoxRect;
NativeMethods.GetWindowRect(wParam, out messageBoxRect);
Int32 width = messageBoxRect.right - messageBoxRect.left; // 消息窗體寬度
Int32 height = messageBoxRect.bottom - messageBoxRect.top; // 消息窗體高度
Int32 xPos = (formRect.left + formRect.right - width) >> 1; // 消息窗體位於父窗體中心時左上角X坐標
Int32 yPos = (formRect.top + formRect.bottom - height) >> 1; // 消息窗體位於父窗體中心時左上角Y坐標
// 將消息窗體移到父窗體中心
NativeMethods.MoveWindow(wParam, xPos, yPos, width, height, false);
// 卸載鉤子
NativeMethods.UnhookWindowsHookEx(_hhk);
// 釋放已分配的GCHandle
_gch.Free();
}
// 允許操作
return IntPtr.Zero;
}
}
private static class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
/// <summary>
/// CBTProc委托聲明
/// </summary>
/// <param name="nCode">HCBT_ACTIVATE:系統將要激活一個窗口</param>
/// <param name="wParam">要激活的窗口句柄</param>
/// <param name="lParam">指向CBTACTIVATESTRUCT結構</param>
/// <returns>
/// 0:執行這個操作
/// 1:阻止這個操作
/// </returns>
internal delegate IntPtr CBTProc(Int32 nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr SetWindowsHookEx(Int32 idHook, CBTProc lpfn, IntPtr hMod, Int32 dwThreadId);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean MoveWindow(IntPtr hWnd, Int32 X, Int32 Y, Int32 nWidth, Int32 nHeight, [MarshalAs(UnmanagedType.Bool)]Boolean bRepaint);
[DllImport("kernel32.dll")]
internal static extern Int32 GetCurrentThreadId();
}
}
}
摘自 秦建輝的專欄