gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-30 00:40:52 25 4
gpt4 key购买 nike

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

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

我想寻求一种检索这些图标的方法。

最佳答案

更新:

你应该使用 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();

结果如下所示:The retrieved icon

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.


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

原答案:

非常有趣的是,在 Asterisk 的情况下,SystemIcons 中的图标与 MessageBoxes 中显示的图标不同,Information 问题。对话框上的图标看起来更扁平

Icons for Asterix and Information Icons for Question

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

Icon for 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 中获取那个图标。

为此我们需要更多的 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);

想法如下:首先我们显示一个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();
}
}
}
}
}

关于c# - 如何在 Windows 8.1 中获取 MessageBox 图标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24257506/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com