是否可以使用Windows图标选择器对话框?

时间:2019-05-05 18:23:50

标签: c# wpf dialog

在我的代码中,我希望我的用户能够从其计算机上的任何位置选择一个图标。该图标可以是独立的.ico,也可以是.exe.dll中的图标-不仅是.exe/dll的默认显示图标,而且以及其中包含的任何其他图标。

在理想的世界中,我希望能够使用此本机Windows图标选择器对话框:

Windows Icon Picker Dialog

但是我不知道如何使用它-可能吗? 该对话框对我来说非常理想,因为它似乎只允许用户浏览图标或标准浏览.exe.dll

如果我的用户只能使用独立的.ico文件,那么我将采用在CommonOpenFileDialog nuget包中为Windows Visa +和{{ 1}}(对于较旧的系统),如下所示:

Microsoft.WindowsAPICodePack-Shell

但是据我所知,这条路线不会允许我的用户从System.Windows.Forms.FolderBrowserDialog中选择图标?

如果无法使用“图标选择器”对话框,是否有另一种方法可以从private string SelectWinXPIcon() { using (WinForms.OpenFileDialog ofd = new WinForms.OpenFileDialog() { Filter = "Icon files (*.ico)|*.ico", }) { WinForms.DialogResult result = ofd.ShowDialog(); switch (result) { case WinForms.DialogResult.OK: case WinForms.DialogResult.Yes: return ofd.FileName; default: return null; } } } private string SelectWinVistaIcon() { using (CommonOpenFileDialog dialog = new CommonOpenFileDialog { DefaultDirectory = @"C:\", AllowNonFileSystemItems = false, EnsurePathExists = true, Multiselect = false, NavigateToShortcut = true }) { dialog.Filters.Add(new CommonFileDialogFilter("Icon Files (*.ico)", ".ico")); CommonFileDialogResult result = dialog.ShowDialog(); switch (result) { case CommonFileDialogResult.Ok: return dialog.FileName; default: return null; } } } 中提取图标,从而还可以选择独立的.exe/dll文件?

1 个答案:

答案 0 :(得分:3)

这是通过shell32 PickIconDlg函数完成的,您可以使用pinvoke site轻松调用该函数以供参考。该函数将返回文件名和索引,然后您可以使用the shell32 ExtractIconEx function提取图标句柄。然后,您可以将图标手柄转换为GDI图标或WPF ImageSource。

例如,在XAML中声明一个图像以显示用户选择的图标:

<Image x:Name="myImage" Stretch="None" />

然后在窗口加载处理程序中使用以下代码来显示对话框,加载该对话框,将其转换为ImageSource并显示它:

[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern int PickIconDlg(IntPtr hwndOwner, System.Text.StringBuilder lpstrFile, int nMaxFile, ref int lpdwIconIndex);

[DllImport("shell32.dll", CharSet = CharSet.Auto)]
private static extern uint ExtractIconEx(string szFileName, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool DestroyIcon(IntPtr handle);

private const int MAX_PATH = 0x00000104;

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    // show the Pick Icon Dialog
    int index = 0;
    int retval;
    var handle = new WindowInteropHelper(this).Handle;
    var iconfile = Environment.GetFolderPath(Environment.SpecialFolder.System) + @"\shell32.dll";
    var sb = new System.Text.StringBuilder(iconfile, MAX_PATH);
    retval = PickIconDlg(handle, sb, sb.MaxCapacity, ref index);

    if (retval != 0)
    {
        // extract the icon
        var largeIcons = new IntPtr[1];
        var smallIcons = new IntPtr[1];
        ExtractIconEx(sb.ToString(), index, largeIcons, smallIcons, 1);

        // convert icon handle to ImageSource
        this.myImage.Source = Imaging.CreateBitmapSourceFromHIcon(largeIcons[0],
            Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());

        // clean up
        DestroyIcon(largeIcons[0]);
        DestroyIcon(smallIcons[0]);
    }
}

它将与DLL / EXE等以及独立的.ICO文件一起使用。