C# 如何在Windows 8.1中获取MessageBox图标

C# 如何在Windows 8.1中获取MessageBox图标,c#,icons,windows-8.1,messagebox,C#,Icons,Windows 8.1,Messagebox,我想获取MessageBox图标,当用户看到一个MessageBox时会显示这些图标。之前我使用SystemIcons来实现这个目的,但现在它返回的图标似乎与消息框中的图标不同 这导致的结论是,在Windows 8.1系统中,图标和MessageBox图标是不同的。我知道图标是使用WinApi MessageBox获取的,但我似乎无法以任何方式获取图标本身 我想询问检索这些图标的方法。更新: 你应该使用这个函数 要在C#中实现这一点,您必须定义一些枚举和结构(有关更多信息,请参阅): 之后,您可

我想获取MessageBox图标,当用户看到一个
MessageBox
时会显示这些图标。之前我使用SystemIcons来实现这个目的,但现在它返回的图标似乎与
消息框中的图标不同

这导致的结论是,在Windows 8.1系统中,图标和MessageBox图标是不同的。我知道图标是使用WinApi MessageBox获取的,但我似乎无法以任何方式获取图标本身


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

更新:

你应该使用这个函数

要在C#中实现这一点,您必须定义一些枚举和结构(有关更多信息,请参阅):

之后,您可以轻松获得所需的图标:

 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();
结果将是这样的:

请:

如果此函数在 SHSTOCKICONINFOpsii指向的结构,您负责 当不再需要图标时,使用销毁图标释放图标


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

原始答案:

非常有趣的是,
系统图标
中显示的图标与
消息框
中显示的图标不同,例如
星号
信息
问题
。对话框上的图标看起来更平坦

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

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

// get icon from SystemIcons
pictureBox1.Image = SystemIcons.Asterisk.ToBitmap();
[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();
如果您再努力一点,使用user32.dll中的
LoadIcon
方法,仍然会得到相同的图标(如上图中所示)

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

为此,我们需要更多的DLL运动:

// 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);
其思想如下:首先我们显示一个
消息框
,然后(当它仍然显示时)我们找到它的句柄,使用该句柄我们将获得另一个句柄,现在是包含图标的静态控件。最后,我们将向该控件发送一条消息(一条
STM_GETICON
消息),该消息将带着图标本身的句柄返回。使用这个句柄,我们可以创建一个
图标
,我们可以在应用程序中的任何地方使用它

代码:

// 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();
    }
}
代码运行后,名为
pictureBox3
PictureBox
将显示与
MessageBox
相同的图像(如图右侧所示)

我真的希望这有帮助


以下是所有代码供参考(这是一个WinForms应用程序,表单有三个
图片框
和一个
计时器
,它们的名称可以从代码中扣除……):


你的决定很好,但对我没有帮助。遮瑕膏错误地纠正了我的问题。我不搜索解决方法(您的messagebox示例)。我用直接搜索的方式获取图标(例如SystemIcons.Asterisk),但你们会看到不同的结果。有没有其他方法可以获取MessageBox图标
// 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();
    }
}
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();
                }
            }
        }
    }
}