SauronKing

写随笔只是为了记录自己的曾经,如果能给您带来些许方便,那是我莫大的荣幸!

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

首先,介绍一下MessageBox.Show()参数:

//提示框显示的按钮
public enum MessageBoxButtons
 {
        OK = 0x00000000,

        OKCancel = 0x00000001,

        AbortRetryIgnore = 0x00000002,

        YesNoCancel  = 0x00000003,

        YesNo  = 0x00000004,

        RetryCancel  = 0x00000005
 }
提示框提示的图标
public enum MessageBoxIcon 
{
        None         = 0,

        Hand         = 0x00000010,

        Question     = 0x00000020,

        Exclamation  = 0x00000030,

        Asterisk     = 0x00000040,

        Stop         = Hand,

        Error        = Hand,

        Warning      = Exclamation,

        Information  = Asterisk, 
}
提示框默认焦点在第几个按钮上
public enum MessageBoxDefaultButton 
{
        Button1       = 0x00000000,
      
        Button2       = 0x00000100,

        Button3       = 0x00000200,
 
}
//按钮的显示方式
public enum MessageBoxOptions 
{
        ServiceNotification = 0x00200000,

        DefaultDesktopOnly = 0x00020000,
 
        RightAlign         = 0x00080000,

        RtlReading         = 0x00100000,
}
以上这几个枚举是MessageBox最终呈现的效果的设置项,这只是.NET平台提供的设置项,实际上MessageBox显示的样式设置有更多,具体的可以参考windowsAPI MessageBox方法。
具体每个枚举值的意义,在VS中都有说明,这里不在赘述。
 
接下来,我们要介绍MessageBox这个类里边所有的静态方法:
        public static DialogResult Show(string text);

        public static DialogResult Show(IWin32Window owner, string text);
      
        public static DialogResult Show(string text, string caption);
      
        public static DialogResult Show(IWin32Window owner, string text, string caption);
      
        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons);
        
        public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons);  
      
        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon);
       
        public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon);
      
        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton);
    
        public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton);
 
        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options);
       
        public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options);
  
        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, bool displayHelpButton);
 
        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath);
       
        public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath);
        
        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator);
       
        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, string keyword);
       
        public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator);
       
        public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, string keyword);
       
        public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator, object param);
       
        public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator, object param);

虽然MessageBox的静态方法有20个之多,但是其实每个方法在内部调用的都是ShowCore方法:

private static DialogResult ShowCore(IWin32Window owner, string text, string caption,   
                                             MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton,
                                             MessageBoxOptions options, bool showHelp) {

也就是说,其实这个方法是实现消息框的关键,为了更好的理解.NET实现的原理,我把这个方法基本用C#的格式重新写了一遍,代码如下:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    class MessageBoxTest
    {
        [DllImport("user32.dll")]
        public static extern IntPtr GetActiveWindow();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr GetModuleHandle(string modName);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr LoadLibrary(string libname);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);

        private const int HELP_BUTTON = 0x00004000;
        private const int WM_SETFOCUS = 0x0007;
internal static DialogResult MessageBoxShow(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, bool showHelp)
        {
            if (buttons < MessageBoxButtons.OK || buttons > MessageBoxButtons.RetryCancel)
            {
                throw new InvalidEnumArgumentException("buttons", (int)buttons, typeof(MessageBoxButtons));
            }
            if (icon < 0 || icon > MessageBoxIcon.Asterisk)
            {
                throw new InvalidEnumArgumentException("icon", (int)icon, typeof(MessageBoxIcon));
            }
            if (defaultButton < 0 || defaultButton > MessageBoxDefaultButton.Button3)
            {
                throw new InvalidEnumArgumentException("defaultButton", (int)defaultButton, typeof(MessageBoxDefaultButton));
            }
            //options即不包含MessageBoxOptions.ServiceNotification也不包含MessageBoxOptions.DefaultDesktopOnly
            //或者当前进程在用户交互模式中运行
            if ((options & (MessageBoxOptions.ServiceNotification | MessageBoxOptions.DefaultDesktopOnly)) == 0 && !SystemInformation.UserInteractive)
            {
                throw new InvalidOperationException();
            }
            //options包含MessageBoxOptions.ServiceNotification或者包含MessageBoxOptions.DefaultDesktopOnly
            //但是owner不为空
            if (owner != null && (options & (MessageBoxOptions.ServiceNotification | MessageBoxOptions.DefaultDesktopOnly)) != 0)
            {
                throw new ArgumentException("options");
            }
            //options包含MessageBoxOptions.ServiceNotification或者包含MessageBoxOptions.DefaultDesktopOnly
            //但是showHelp位true
            if (showHelp && (options & (MessageBoxOptions.ServiceNotification | MessageBoxOptions.DefaultDesktopOnly)) != 0)
            {
                throw new ArgumentException("options");
            }
            //options包含MessageBoxOptions.ServiceNotification或者包含MessageBoxOptions.DefaultDesktopOnly
            if ((options & ~(MessageBoxOptions.RightAlign | MessageBoxOptions.RtlReading)) != 0)
            {
                CodeAccessPermission permission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
                permission.Demand();
            }
            CodeAccessPermission safePermission = new UIPermission(UIPermissionWindow.SafeSubWindows);
            safePermission.Demand();

            
uint style = (showHelp) ? (uint)HELP_BUTTON : 0; style |= (uint)buttons | (uint)icon | (uint)defaultButton | (uint
)options;
            IntPtr handle = IntPtr.Zero;
            
if (owner == null) { handle = GetActiveWindow(); } else

            {
                Control control 
= owner as Control; handle = control != null ?
 control.Handle : owner.Handle;
            }
            IntPtr userCookie = IntPtr.Zero;
            if (GetModuleHandle("shell32.dll") == IntPtr.Zero && LoadLibrary("shell32.dll") == IntPtr.Zero)
            {
                int lastWin32Error = Marshal.GetLastWin32Error();
                throw new Win32Exception(lastWin32Error, "获取动态链接库shell32.dll失败");
            }
            DialogResult result;
            try
            {
                result 
=
 Win32ToDialogResult(MessageBox(handle, text, caption, style));
            }
            finally
            {
                SendMessage(new HandleRef(owner, handle), WM_SETFOCUS, 0, 0);
            }
            return result;
        }


        private const int IDOK = 1;
        private const int IDCANCEL = 2;
        private const int IDABORT = 3;
        private const int IDRETRY = 4;
        private const int IDIGNORE = 5;
        private const int IDYES = 6;
        private const int IDNO = 7;

        private static DialogResult Win32ToDialogResult(int value)
        {
            switch (value)
            {
                case IDOK:
                    return DialogResult.OK;
                case IDCANCEL:
                    return DialogResult.Cancel;
                case IDABORT:
                    return DialogResult.Abort;
                case IDRETRY:
                    return DialogResult.Retry;
                case IDIGNORE:
                    return DialogResult.Ignore;
                case IDYES:
                    return DialogResult.Yes;
                case IDNO:
                    return DialogResult.No;
                default:
                    return DialogResult.No;
            }
        }
    }
}

上面这些代码复制粘贴到一个类里边是可以直接编译通过的,我们现在在看上面的方法就简单多了,其实出去微软进行的判断,我们用到有用的就上面我用黄色标记的代码。

尤其是GetActiveWindow(); 这一步,很多人在自己模拟重写MessageBox窗体的时候(自己新建一个窗体,然后添加show重载方法)经常会漏掉这一步(我第一次写的时候就漏掉了).

posted on 2016-09-27 14:35  SauronKing  阅读(1027)  评论(0编辑  收藏  举报