您的位置:首页 > 编程语言 > C#

C#:Win32 Hooks(一)让下一个弹出子窗体自动显示在父窗体中心

2012-05-08 09:42 609 查看
/* ----------------------------------------------------------
文件名称:FormHelper.cs

作者:秦建辉

MSN:splashcn@msn.com
QQ:36748897

博客:http://blog.csdn.net/jhqin

开发环境:
Visual Studio V2010
.NET Framework 4 Client Profile

版本历史:
V1.0	2012年05月07日
优化参考代码

参考资料: http://www.jasoncarr.com/technology/centering-a-message-box-on-the-active-window-in-csharp http://stackoverflow.com/questions/1732443/center-messagebox-in-parent-form
------------------------------------------------------------ */
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();
}
}
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c# user class 扩展 hook struct