Как я могу получить значки MessageBox в Windows 8.1

#c# #icons #windows-8.1 #messagebox

#c# #Значки #windows-8.1 #messagebox

Вопрос:

Я хочу получить значки MessageBoxIcons, которые отображаются, когда пользователю предоставляется a MessageBox . Ранее я использовал SystemIcons для этой цели, но теперь кажется, что он возвращает значки, отличные от тех, что на MessageBox .

Это приводит к выводу, что в Windows 8.1 SystemIcons и MessageBoxIcons разные. Я знаю, что значки берутся с помощью WinAPI MessageBox, но, похоже, я никак не могу получить сами значки.

Я хотел бы попросить способ получения этих значков.

Ответ №1:

Обновить:

Вы должны использовать SHGetStockIconInfo функцию.

Чтобы сделать это на C #, вам нужно будет определить несколько перечислений и структур (обратитесь к этой превосходной странице для получения дополнительной информации):

 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();
  

Вот как будет выглядеть результат: Извлеченный значок

Пожалуйста, обратите внимание:

Если эта функция возвращает дескриптор значка в элементе hIcon структуры SHSTOCKICONINFO, на который указывает psii, вы несете ответственность за освобождение значка с помощью DestroyIcon, когда он вам больше не нужен.


я не буду удалять свой первоначальный ответ, поскольку — я думаю — он содержит полезную информацию об этой проблеме и другой способ (или обходной путь) получения этого значка.

Оригинальный ответ:

Довольно интересно, что значки, присутствующие в SystemIcons , отличаются от тех, которые отображаются MessageBoxes в случае Asterisk , Information и Question . Значки в диалоговом окне выглядят намного более плоскими.

Значки для звездочки и информации
Значки для вопроса

Во всех остальных случаях они выглядят точно так же, например: в случае Error :

Значок ошибки

Когда вы пытаетесь получить значок, используя значок SystemIcons , вы получаете тот, который слева на приведенных выше изображениях.

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

Если вы попробуете немного сложнее, используя LoadIcon метод из user32.dll , вы по-прежнему получаете тот же значок (как это видно в центре приведенных выше изображений).

 [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 .

Для этого нам понадобится еще несколько DllImports:

 // 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);
  

Идея заключается в следующем: сначала мы отображаем a 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();
    }
}
  

После выполнения кода PictureBox вызываемый pictureBox3 будет отображать то же изображение MessageBox , что и (как видно справа на изображении).

Я действительно надеюсь, что это поможет.


Для справки вот весь код (это приложение WinForms, форма имеет три 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();
                }
            }
        }
    }
}
  

Комментарии:

1. Ваше решение хорошее, но мне не помогает. Корректор неправильно исправил мой вопрос. Я не ищу обходной путь (ваш пример messagebox). Я ищу прямой способ получения значков (SystemIcons. Например, звездочка), но, как вы увидите, разные. Есть ли другой способ получить MessageBoxIcons