51

How do i get an System.Drawing.Image for the various System.Windows.MessageBoxImage(s) and/or System.Windows.Forms.MessageBoxIcon(s)

Simon
  • 33,714
  • 21
  • 133
  • 202

5 Answers5

64

SystemIcons is what I was looking for:

SystemIcons.Warning.ToBitmap();
Sebastian Brosch
  • 42,106
  • 15
  • 72
  • 87
Simon
  • 33,714
  • 21
  • 133
  • 202
40

You can also include SystemIcons in your XAML as follows:

Include a converter (see code below) as a Resource, and an Image control in your XAML. This Image sample here shows the information icon.

     <Window.Resources>
        <Converters:SystemIconConverter x:Key="iconConverter"/>
     </Window.Resources>

     <Image Visibility="Visible"  
            Margin="10,10,0,1"
            Stretch="Uniform"
            MaxHeight="25"
            VerticalAlignment="Top"
            HorizontalAlignment="Left"
            Source="{Binding Converter={StaticResource iconConverter}, ConverterParameter=Information}"/>

Here is the implementation for the converter:

using System;
using System.Drawing;
using System.Globalization;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Interop;
using System.Windows.Media.Imaging;

namespace Converters
{
   [ValueConversion(typeof(string), typeof(BitmapSource))]
   public class SystemIconConverter : IValueConverter
   {
      public object Convert(object value, Type type, object parameter, CultureInfo culture)
      {
         Icon icon = (Icon)typeof(SystemIcons).GetProperty(parameter.ToString(), BindingFlags.Public | BindingFlags.Static).GetValue(null, null);
         BitmapSource bs = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
         return bs;
      }

      public object ConvertBack(object value, Type type, object parameter, CultureInfo culture)
      {
         throw new NotSupportedException();
      }
   }
}
Zamboni
  • 7,897
  • 5
  • 43
  • 52
  • Thanks so much! This works great! However, I noticed that StackOverflow operates under the Creative Commons licence. Thus I technically can't use/adapt your code in my commercial application (which I don't want to be under the Creative Commons licence) without your permission. Are you willing to give me permission? I can still credit your work. – skybluecodeflier Sep 07 '11 at 16:10
  • @skybluecodeflier, any code posted to StackOverflow is creative commons: http://meta.stackexchange.com/questions/12527/do-i-have-to-worry-about-copyright-issues-for-code-posted-on-stack-overflow – Ed Bayiates May 01 '14 at 20:06
  • @Zamboni Is there any particular reason your converter ignores the `value` and performs the conversion using only the `parameter`? That seems atypical of converters. – Disillusioned Oct 17 '16 at 11:59
20

As others have stated SystemIcons is the class that should contain those icons, but on Windows 8.1 (and possibly on earlier versions too) the icons present in the SystemIcons differ from the ones displayed on the MessageBoxes in the case of Asterisk, Information and Question. The icons on the dialog look much flatter. See - for example - the Question icon:

Question icon

The icon in the dialog is the native dialog icon, and the leftmost icon on the form in the background is the icon retrieved from the SystemIcons class.

For various methods and details on how to get the icon from the MessageBox see this answer, but I include here a quick summary, just for the sake of completeness:

You should use the SHGetStockIconInfo function:

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

Please note:

If this function returns an icon handle in the hIcon member of the SHSTOCKICONINFO structure pointed to by psii, you are responsible for freeing the icon with DestroyIcon when you no longer need it.

Of course for this to work you will have to define a few enums and structs:

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);
Community
  • 1
  • 1
qqbenq
  • 10,220
  • 4
  • 40
  • 45
0

Extend the Icon Class:

    [DllImport("gdi32.dll", SetLastError = true)]
    private static extern bool DeleteObject(IntPtr hObject);

    public static ImageSource ToImageSource(this Icon icon)
    {
        Bitmap bitmap = icon.ToBitmap();
        IntPtr hBitmap = bitmap.GetHbitmap();

        ImageSource wpfBitmap = Imaging.CreateBitmapSourceFromHBitmap(
            hBitmap,
            IntPtr.Zero,
            Int32Rect.Empty,
            BitmapSizeOptions.FromEmptyOptions());

        if (!DeleteObject(hBitmap))
        {
            throw new Win32Exception();
        }

        return wpfBitmap;
    }

Extend the MessageBoxImage Enum:

    public static ImageSource ToImageSource(this MessageBoxImage enumValue)
    {
        switch (enumValue)
        {
            case MessageBoxImage.Error:
                return SystemIcons.Error.ToImageSource();
            case MessageBoxImage.Question:
                return SystemIcons.Question.ToImageSource();
            case MessageBoxImage.Warning:
                return SystemIcons.Warning.ToImageSource();
            case MessageBoxImage.Information:
                return SystemIcons.Information.ToImageSource();
        }

        return null;
    }

Profit:

(Not gonna post the whole WPF Window code here, but "Icon" and "Image" are Properties of Type "ImageSource", linked to Image controls through Data Binding)

    public ConfirmationWindow(Icon icon, MessageBoxImage image, string title, string content, bool defaultIsYes = true)
    {
        InitializeComponent();            

        Icon = icon.ToImageSource();
        Image = image.ToImageSource();
        Title = title;
        Content = content;
        DefaultIsYes = defaultIsYes;
    }
-3
MessageBox.Show(
  "Hello, world!",
  "My App",
  MessageBoxButton.OK, MessageBoxImage.Information);

As simple as that.

jschoi
  • 1,884
  • 1
  • 12
  • 26
  • Thanks for the answer. but i actually want an instance of the bitmap used, not "how to show the message box". And welcome to stackoverflow – Simon Jul 24 '19 at 21:03