【问题标题】:How can I get MessageBox icons in Windows 8.1如何在 Windows 8.1 中获取 MessageBox 图标
【发布时间】:2014-08-07 02:14:48
【问题描述】:

我想获取 MessageBoxIcons,当用户看到 MessageBox 时会显示它。早些时候我为此目的使用了 SystemIcons,但现在它返回的图标似乎与 MessageBox 上的图标不同。

由此得出结论,在 Windows 8.1 中 SystemIcons 和 MessageBoxIcons 是不同的。我知道图标是使用 WinApi MessageBox 获取的,但我似乎无法以任何方式获取图标本身。

我想询问一种检索这些图标的方法。

【问题讨论】:

    标签: c# icons windows-8.1 messagebox


    【解决方案1】:

    更新:

    您应该使用SHGetStockIconInfo 函数。

    要在 C# 中做到这一点,您必须定义一些枚举和结构(请咨询 this excellent page 了解更多信息):

    public enum SHSTOCKICONID : uint
    {
        //...
        SIID_INFO = 79,
        //...
    }
    
    [Flags]
    public enum SHGSI : uint
    {
        SHGSI_ICONLOCATION = 0,
        SHGSI_ICON = 0x000000100,
        SHGSI_SYSICONINDEX = 0x000004000,
        SHGSI_LINKOVERLAY = 0x000008000,
        SHGSI_SELECTED = 0x000010000,
        SHGSI_LARGEICON = 0x000000000,
        SHGSI_SMALLICON = 0x000000001,
        SHGSI_SHELLICONSIZE = 0x000000004
    }
    
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct SHSTOCKICONINFO
    {
        public UInt32 cbSize;
        public IntPtr hIcon;
        public Int32 iSysIconIndex;
        public Int32 iIcon;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260/*MAX_PATH*/)]
        public string szPath;
    }
    
    [DllImport("Shell32.dll", SetLastError = false)]
    public static extern Int32 SHGetStockIconInfo(SHSTOCKICONID siid, SHGSI uFlags, ref SHSTOCKICONINFO psii);
    

    之后就可以轻松获取所需的图标了:

     SHSTOCKICONINFO sii = new SHSTOCKICONINFO();
     sii.cbSize = (UInt32)Marshal.SizeOf(typeof(SHSTOCKICONINFO));
    
     Marshal.ThrowExceptionForHR(SHGetStockIconInfo(SHSTOCKICONID.SIID_INFO,
             SHGSI.SHGSI_ICON ,
             ref sii));
     pictureBox1.Image = Icon.FromHandle(sii.hIcon).ToBitmap();
    

    结果如下所示:

    note

    如果此函数在 hIcon 成员中返回一个图标句柄 psii指向的SHSTOCKICONINFO结构,你负责 当您不再需要该图标时,使用 DestroyIcon 释放它。


    我不会删除我原来的答案,因为 - 我认为 - 它包含有关此问题的有用信息,以及检索此图标的另一种方式(或解决方法)。

    原答案:

    AsteriskInformationQuestion 的情况下,SystemIcons 中显示的图标与MessageBoxes 上显示的图标非常有趣。对话框上的图标看起来更扁平

    在所有其他情况下,它们看起来完全相同,例如:Error

    当您尝试使用SystemIcons 获取图标时,您会得到上图中左侧的图标。

    // get icon from SystemIcons
    pictureBox1.Image = SystemIcons.Asterisk.ToBitmap();
    

    如果你再努力一点,使用 user32.dll 中的LoadIcon 方法,你仍然会得到相同的图标(如上图的中心所示)。

    [DllImport("user32.dll")]
    static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);
    
    ...
    
    public enum SystemIconIds
    {
        ...
        IDI_ASTERISK = 32516,
        ...
    }
    
    ...
    
    // load icon by ID
    IntPtr iconHandle = LoadIcon(IntPtr.Zero, new IntPtr((int)SystemIconIds.IDI_ASTERISK));
    pictureBox2.Image = Icon.FromHandle(iconHandle).ToBitmap();
    

    但是当您显示一个 MessagBox 时,您会得到一个不同的消息框(如图片上的 MessageBox 所示)。一个人别无选择,只能从MessageBox 获得那个图标。

    为此,我们需要更多的 DllImport:

    // To be able to find the dialog window
    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
    // To be able to get the icon window handle
    [DllImport("user32.dll")]
    static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
    
    // To be able to get a handle to the actual icon
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
    

    想法如下:首先我们显示一个MessageBox,然后(当它仍然显示时)我们找到它的句柄,使用那个句柄我们会得到另一个句柄,现在到包含图标的静态控件.最后,我们将向该控件发送一条消息(STM_GETICON 消息),该消息将返回图标本身的句柄。使用该句柄,我们可以创建一个Icon,我们可以在应用程序的任何地方使用它。

    在代码中:

    // show a `MessageBox`
    MessageBox.Show("test", "test caption", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
    
    ...
    
    var hwnd = FindWindow(null, "test caption");
    if (hwnd != IntPtr.Zero)
    {
        // we got the messagebox, get the icon from it
        IntPtr hIconWnd = GetDlgItem(hwnd, 20);
        if (hIconWnd != IntPtr.Zero)
        {
            var iconHandle = SendMessage(hIconWnd, 369/*STM_GETICON*/, IntPtr.Zero, IntPtr.Zero);
    
            pictureBox3.Image = Icon.FromHandle(iconHandle).ToBitmap();
        }
    }
    

    代码运行后,名为pictureBox3PictureBox 将显示与MessageBox 相同的图像(如图像右侧所示)。

    我真的希望这会有所帮助。


    这里是所有代码供参考(它是一个WinForms应用程序,Form有三个PicturBoxes和一个Timer,它们的名字可以从代码中扣除......):

    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            [DllImport("user32.dll")]
            static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);
    
            [DllImport("user32.dll", SetLastError = true)]
            static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [DllImport("user32.dll")]
            static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
    
            public enum SystemIconIds
            {
                IDI_APPLICATION = 32512,
                IDI_HAND = 32513,
                IDI_QUESTION = 32514,
                IDI_EXCLAMATION = 32515,
                IDI_ASTERISK = 32516,
                IDI_WINLOGO = 32517,
                IDI_WARNING = IDI_EXCLAMATION,
                IDI_ERROR = IDI_HAND,
                IDI_INFORMATION = IDI_ASTERISK,
            }
    
            public Form1()
            {
                InitializeComponent();
                // Information, Question and Asterix differ from the icons displayed on MessageBox
    
                // get icon from SystemIcons
                pictureBox1.Image = SystemIcons.Asterisk.ToBitmap();
                // load icon by ID
                IntPtr iconHandle = LoadIcon(IntPtr.Zero, new IntPtr((int)SystemIconIds.IDI_ASTERISK));
                pictureBox2.Image = Icon.FromHandle(iconHandle).ToBitmap();
            }
    
            private void pictureBox1_Click(object sender, EventArgs e)
            {
                MessageBox.Show("test", "test caption", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
            }
    
    
            private void timer1_Tick(object sender, EventArgs e)
            {
                var hwnd = FindWindow(null, "test caption");
                if (hwnd != IntPtr.Zero)
                {
                    // we got the messagebox, get the icon from it
                    IntPtr hIconWnd = GetDlgItem(hwnd, 20);
                    if (hIconWnd != IntPtr.Zero)
                    {
                        var iconHandle = SendMessage(hIconWnd, 369/*STM_GETICON*/, IntPtr.Zero, IntPtr.Zero);
                        pictureBox3.Image = Icon.FromHandle(iconHandle).ToBitmap();
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 你的决定是好的,但对我没有帮助。遮瑕膏错误地纠正了我的问题。我不搜索解决方法(您的消息框示例)。我搜索直接获取图标的方法(例如 SystemIcons.Asterisk),但你会看到不同的。有没有其他方法可以获取 MessageBoxIcons
    猜你喜欢
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-24
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    相关资源
    最近更新 更多