Программно выбрать несколько файлов в проводнике Windows - PullRequest
18 голосов
/ 13 августа 2008

Я могу отобразить и выбрать один файл в проводнике Windows следующим образом:

explorer.exe /select, "c:\path\to\file.txt"

Однако я не могу понять, как выбрать более одного файла. Ни одна из перестановок избранных я не пробовал работать.

Примечание: я просмотрел эти страницы для документов, но не помог.

https://support.microsoft.com/kb/314853
http://www.infocellar.com/Win98/explorer-switches.htm

Ответы [ 7 ]

17 голосов
/ 10 июня 2010

Это должно быть возможно с помощью функции оболочки SHOpenFolderAndSelectItems

EDIT

Вот пример кода, показывающего, как использовать функцию в C / C ++ без проверки ошибок:

//Directory to open
ITEMIDLIST *dir = ILCreateFromPath(_T("C:\\"));

//Items in directory to select
ITEMIDLIST *item1 = ILCreateFromPath(_T("C:\\Program Files\\"));
ITEMIDLIST *item2 = ILCreateFromPath(_T("C:\\Windows\\"));
const ITEMIDLIST* selection[] = {item1,item2};
UINT count = sizeof(selection) / sizeof(ITEMIDLIST);

//Perform selection
SHOpenFolderAndSelectItems(dir, count, selection, 0);

//Free resources
ILFree(dir);
ILFree(item1);
ILFree(item2);
5 голосов
/ 26 августа 2010

Истинный способ выбора нескольких файлов в Проводнике - следующий

Неуправляемый код выглядит следующим образом (скомпилировано из публикаций кода в Китае с исправлением ошибок)

static class NativeMethods
{
    [DllImport("shell32.dll", ExactSpelling = true)]
    public static extern int SHOpenFolderAndSelectItems(
        IntPtr pidlFolder,
        uint cidl,
        [In, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
        uint dwFlags);

    [DllImport("shell32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr ILCreateFromPath([MarshalAs(UnmanagedType.LPTStr)] string pszPath);

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("000214F9-0000-0000-C000-000000000046")]
    public interface IShellLinkW
    {
        [PreserveSig]
        int GetPath(StringBuilder pszFile, int cch, [In, Out] ref WIN32_FIND_DATAW pfd, uint fFlags);

        [PreserveSig]
        int GetIDList([Out] out IntPtr ppidl);

        [PreserveSig]
        int SetIDList([In] ref IntPtr pidl);

        [PreserveSig]
        int GetDescription(StringBuilder pszName, int cch);

        [PreserveSig]
        int SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);

        [PreserveSig]
        int GetWorkingDirectory(StringBuilder pszDir, int cch);

        [PreserveSig]
        int SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);

        [PreserveSig]
        int GetArguments(StringBuilder pszArgs, int cch);

        [PreserveSig]
        int SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);

        [PreserveSig]
        int GetHotkey([Out] out ushort pwHotkey);

        [PreserveSig]
        int SetHotkey(ushort wHotkey);

        [PreserveSig]
        int GetShowCmd([Out] out int piShowCmd);

        [PreserveSig]
        int SetShowCmd(int iShowCmd);

        [PreserveSig]
        int GetIconLocation(StringBuilder pszIconPath, int cch, [Out] out int piIcon);

        [PreserveSig]
        int SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);

        [PreserveSig]
        int SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);

        [PreserveSig]
        int Resolve(IntPtr hwnd, uint fFlags);

        [PreserveSig]
        int SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
    }

    [Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode), BestFitMapping(false)]
    public struct WIN32_FIND_DATAW
    {
        public uint dwFileAttributes;
        public FILETIME ftCreationTime;
        public FILETIME ftLastAccessTime;
        public FILETIME ftLastWriteTime;
        public uint nFileSizeHigh;
        public uint nFileSizeLow;
        public uint dwReserved0;
        public uint dwReserved1;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        public string cFileName;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
        public string cAlternateFileName;
    }

    public static void OpenFolderAndSelectFiles(string folder, params string[] filesToSelect)
    {
        IntPtr dir = ILCreateFromPath(folder);

        var filesToSelectIntPtrs = new IntPtr[filesToSelect.Length];
        for (int i = 0; i < filesToSelect.Length; i++)
        {
            filesToSelectIntPtrs[i] = ILCreateFromPath(filesToSelect[i]);
        }

        SHOpenFolderAndSelectItems(dir, (uint) filesToSelect.Length, filesToSelectIntPtrs, 0);
        ReleaseComObject(dir);
        ReleaseComObject(filesToSelectIntPtrs);
    }

    private static void ReleaseComObject(params object[] comObjs)
    {
        foreach (object obj in comObjs)
        {
            if (obj != null && Marshal.IsComObject(obj))
                Marshal.ReleaseComObject(obj);
        }
    }
}
2 голосов
/ 13 августа 2008

это нельзя сделать через explorer.exe

1 голос
/ 18 августа 2008

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

Чтобы добавить больше контекста - Наша компания разрабатывает клиентское приложение на C #, которое позволяет пользователям загружать файлы и делать с ними что-то вроде того, как iTunes управляет вашими файлами MP3, не показывая вам фактический файл на диске.

Полезно выбрать файл в приложении и выполнить команду «Показать мне этот файл в проводнике Windows» - это то, чего я пытаюсь добиться, и я сделал это для отдельных файлов.

У нас есть ListView, который позволяет пользователям выбирать несколько файлов в приложении и перемещать / удалять / и т.д. их. Было бы неплохо, чтобы команда «покажи мне этот файл в windows» работала для нескольких выбранных файлов - по крайней мере, если все исходные файлы находятся в одном каталоге, но если это невозможно, то это не является основной функцией.

1 голос
/ 13 августа 2008

В зависимости от того, чего вы на самом деле хотите достичь, вы можете сделать это с помощью AutoHotKey . Это удивительный бесплатный инструмент для автоматизации вещей, которые вы обычно не можете сделать. Это должно прийти с Windows. Этот скрипт выберет ваш файл и выделит следующие два файла под ним, когда вы нажмете F12.

F12:: 
 run explorer.exe /select`, "c:\path\to\file.txt"
 SendInput {Shift Down}{Down}{Down}{Shift Up}
return

Также можно просто поместить эти две средние строки в текстовый файл, а затем передать его в файл autohotkey.exe. У них также есть возможность скомпилировать скрипт, что сделает его автономным exe-файлом, который вы можете вызвать. Прекрасно работает с отличным файлом справки.

@ Orion, можно использовать autohotkey из C #. Вы можете превратить скрипт autohotkey в автономный исполняемый файл (около 400 КБ), который может быть запущен вашим приложением C # (именно так, как вы запускаете проводник). Вы также можете передать ему параметры командной строки. У него нет требований времени выполнения.

0 голосов
/ 04 декабря 2008

Grr, я бы тоже хотел это сделать. Media Player делает это, когда вы выбираете 2+ файла, щелкаете правой кнопкой мыши и делаете «открыть местоположение файла», но не совсем уверены, как (и при этом я не испытываю желания тратить время на / procmon, чтобы это выяснить).

0 голосов
/ 24 октября 2008

Полагаю, вы можете использовать FindWindowEx, чтобы получить SysListView32 в Windows Explorer, а затем использовать SendMessage с LVM_SETITEMSTATE для выбора элементов. Сложность в том, чтобы узнать расположение предметов ... Возможно, для этого можно использовать LVM_FINDITEM.

...