Как создать «Shell IDList Array» для поддержки перетаскивания виртуальных файлов из C # в Windows Explorer? - PullRequest
6 голосов
/ 30 мая 2010

Я начал пытаться реализовать перетаскивание виртуальных файлов (из приложения C # 4 / WPF) с помощью этого учебного курса по коду проекта . Потратив некоторое время , пытаясь выяснить ошибку DV_E_FORMATETC , я понял, что мне нужно поддерживать формат данных «Shell IDList Array». Но, похоже, почти нет документации о том, что на самом деле делает этот формат.

После некоторого поиска я нашел эту страницу о расширенной передаче данных , в которой говорилось, что массив IDList-массивов Shell был указателем на структуру CIDA . Эта структура CIDA содержит количество PIDL и список смещений для них. Так что, черт возьми, PIDL? После дополнительного поиска, эта страница предполагает, что это указатель на ITEMIDLIST , который сам содержит один элемент, который является списком SHITEMID s.

Я еще кое-что прочитал, я до сих пор не могу сказать, для чего нужны несколько PIDL, но для каждого «уровня» в пути есть один SHITEMID. По крайней мере, это одна загадка разгадана.

Моей следующей идеей было попытаться перетащить файл из другого приложения с виртуальными файлами (WinSCP). Я только что вернул MemoryStream для этого формата. По крайней мере, я знаю, какой класс предоставить для этой вещи, но это совсем не помогает объяснить, что в нее вставить. Я попытался изучить этот MemoryStream на основе форматов, указанных в ссылках выше, но у меня ничего не получилось. Я только что получил данные об мусоре, и одно из полей 'cb' сообщило мне, что длина всего 18000 байт, когда весь поток составляет всего 539 байт.

Кроме того, при дальнейшем чтении эта страница , по-видимому, подразумевает, что данные, содержащиеся в PIDL, в действительности оказываются путями, а проверка содержимого упомянутой MemoryStream в шестнадцатеричном редакторе дает путь внутри мой локальный каталог Temp (в любом случае разбитый на части).

Кажется, что WinSCP просто использует расширение оболочки для обработки сбрасывания в проводнике, к чему я действительно не хочу прибегать. Однако у него есть альтернативный режим, в котором он прерывает перетаскивание до тех пор, пока он не перейдет во временную папку - это приемлемо для меня, но я не имею ни малейшего представления, как это сделать.

Мои вопросы сейчас:

  1. Что такое действительный член abID для SHITEMID? Эти виртуальные файлы существуют только в моей программе; Будет ли та вещь, которую они перетаскивают, передать позже «abID», когда он выполняет GetData? Должны ли они быть уникальными для системы?
  2. Как я могу управлять перетаскиванием и отменой позже, что делает WinSCP?
  3. Если бы мне пришлось реализовать расширение оболочки для этого, как бы я вообще это сделал? Я уверен, что могу легко найти объяснения теории расширения оболочки, но как бы я поддержал пользовательские PIDL или что-то еще?

Буду очень признателен за любую помощь или даже ссылки, которые объясняют, что я должен делать.

Редактировать: Итак, вот как я на самом деле это сделал в итоге:

Я удалил большую часть кода из учебника CodeProject выше, сохранив функции для создания FileGroupDescriptor. Затем я переопределил интерфейс .Net IDataObject (и на самом деле мне вообще не пришлось использовать интерфейс COM IDataObject). Затем я вынужден синхронно загрузить файл в фоновом режиме и передать MemoryStream обратно из GetData (). Удобно, что фактическое копирование находится в фоновом режиме, но в ожидании данных находится на переднем плане. Спасибо, исследователь. Любые достаточно большие файлы работают медленно, но сейчас они «работают», что больше, чем я могу сказать за последние несколько недель.

Я попытался передать класс PipeStream , который я использую для переводов внутри, но проводник не доволен этим:

  • Он пытается искать, несмотря на то, что класс CanSeek имеет значение false.
  • Он игнорирует размер, который я посылаю в FileGroupDescriptor, и просто загружает все, что находится в потоке прямо сейчас .

Итак, я не уверен, что идеальный случай действительно возможен. Тем не менее, спасибо за вашу помощь. Я даю награду JPW, потому что его ответы в конечном итоге ставят меня на правильный путь.

Ответы [ 3 ]

3 голосов
/ 03 июня 2010

Я думаю, C # Браузер файлов на http://www.codeproject.com/KB/miscctrl/FileBrowser.aspx - это то, что вам сейчас больше всего поможет.

Эти статьи бесценны.

Edanmo.ShellExtensions абсолютно необходимо. http://www.mvps.org/emorcillo/en/code/shell/shellextensions.shtml

Обратите внимание, что некоторые из этих интерфейсов COM уже определены в .NET 2.0. (Я не проверял 4.0, но сомневаюсь, что Microsoft добавила какую-либо дополнительную поддержку для интерфейсов Shell / COM.)

Extra Stuff

НАЙДЕНО!

Полное идиотское руководство по написанию расширений пространства имен - часть I в http://www.codeproject.com/kb/shell/namespcextguide1.aspx. Это то, что вы ищете?

2 голосов
/ 01 июня 2010

Отказ от ответственности : я не являюсь экспертом ни в программировании Windows Shell, ни в программировании COM, особенно в программировании COM с использованием .NET.

Отказ от ответственности 2 : программирование оболочки является довольно сложным и Windows Explorer, вероятно, завершится сбоем. (Обязательно прочитайте информацию на MSDN об отладке расширений оболочки.)

Вот что я могу дать, чтобы ответить на ваши вопросы:

  1. Значение abID SHITEMID определяется папкой, в которой содержится соответствующий элемент. Поэтому нет никакой действительной или недействительной информации, так как эти данные только для папки. Проводник Windows передаст эти данные, чтобы идентифицировать конкретный элемент. abID не должен быть уникальным для системы, но он, вероятно, будет уникальным в своей папке (хотя это не гарантируется). При определенных обстоятельствах SHITEMID может сохраняться, поэтому в некоторых случаях он должен быть действительным после перезагрузки (из-за этого следует избегать ссылок на память в abID).
  2. Насколько я понимаю, IDataObject :: GetData будет вызываться только в том случае, если требуются фактические данные (и я могу ошибаться в этом). Так что все будет в порядке, если вы извлекаете данные во временный файл в GetData и возвращаете PIDL в этот файл (см. http://support.microsoft.com/kb/132750/en-us,, хотя я помню, что для этого был предложен удобный метод, но я не могу вспомнить его имя). К сожалению, я не вижу хорошего способа удалить временный файл (в качестве крайней меры вы можете сделать это, когда IDataObject будет уничтожен, но это может привести к временным файлам, которые больше не нужны).
  3. Возможно, вам потребуется поддержка пользовательских PIDL (включая собственный менеджер PIDL) и реализация пользовательского IShellFolder. Однако большая часть документации по расширениям оболочки предназначена для C ++, и многие функции не очень хорошо документированы или вообще не документированы. Для получения дополнительной информации о PIDL я бы порекомендовал прочитать http://msdn.microsoft.com/en-us/library/cc144090.aspx. Кроме того, вам следует поискать «Расширение пространства имен оболочки» в Интернете, так как может быть некоторая информация по теме. Также ознакомьтесь с примерами, предоставленными Windows SDK на эту тему.

Надеюсь, некоторая информация будет вам полезна.

Редактировать : Вы также можете соответствующим образом реализовать QueryGetData и EnumerableFormatEtc, чтобы указать, что ваш объект не поддерживает рассматриваемый формат. Возможно, Проводник Windows использует другой формат.

Редактировать 2 : Хотя вы уже остановились на решении, вот еще некоторая информация о том, как выполнять перетаскивание асинхронно (для больших файлов), возможно, вы (или, по крайней мере, кто-то ищет) ответ на симуляционную проблему, кто это читает) найдет его полезным: http://msdn.microsoft.com/en-us/library/bb776904(VS.85).aspx#async

0 голосов
/ 03 июня 2010

Вы видели эту статью? Как перетащить виртуальный файл из приложения в Проводник Windows Исходный код на языке c ++, но он должен помочь вам понять, как все это работает.

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