Можно ли использовать диалоговое окно выбора значков Windows? - PullRequest
2 голосов
/ 05 мая 2019

В своем коде я бы хотел, чтобы мой пользователь мог выбрать значок в любом месте на своем компьютере. Значок может быть автономным .ico или значком из .exe или .dll, как, например, не только отображаемый по умолчанию значок .exe/dll, но также любой другой значок, содержащийся в нем.

В идеальном мире я бы хотел использовать диалоговое окно выбора значков Windows:

Windows Icon Picker Dialog

Но я не знаю, как его использовать - возможно ли это? Этот диалог был бы идеален для меня, потому что, кажется, он позволяет пользователям просматривать либо значки, либо .exe s и .dll s в качестве стандарта.

Если бы мои пользователи могли использовать только автономные .ico файлы, я бы выбрал класс CommonOpenFileDialog, находящийся в пакете Microsoft.WindowsAPICodePack-Shell nuget для Windows Visa + и 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?

Если нет способа использовать диалог выбора значков, есть ли альтернативный способ извлечения значков из .exe/dll с, который также позволил бы выбирать автономные .ico файлы для выбора?

1 Ответ

3 голосов
/ 06 мая 2019

Это делается с помощью функции shell32 PickIconDlg, которую вы легко можете вызвать с помощью pinvoke site для справки. Функция вернет имя файла и индекс, затем вы можете извлечь дескриптор значка с помощью , функции shell32 ExtractIconEx . Затем вы можете преобразовать дескриптор значка в значок 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...