Обработка сценариев передачи данных оболочки
В документе "Объект данных оболочки" рассматривается общий подход, используемый для передачи данных оболочки с перетаскиванием или буфером обмена. Однако для реализации передачи данных оболочки в приложении необходимо также понять, как применять эти общие принципы и методы к различным способам передачи данных оболочки. В этом документе представлены распространенные сценарии передачи данных оболочки и рассматриваются способы реализации каждого из них в приложении.
- Общие рекомендации
- Копирование имен файлов из буфера обмена в приложение
- Копирование содержимого удаленного файла в приложение
- Обработка оптимизированных операций перемещения
- Обработка операций удаления по вставки
- Передача данных в виртуальные папки и из нее
- Удаление файлов в корзине
- Создание и импорт файлов лома
- Перетаскивание и удаление объектов оболочки асинхронно
Примечание.
Хотя каждый из этих сценариев обсуждает определенную операцию передачи данных, многие из них применяются к различным связанным сценариям. Например, основное различие между большинством буферов обмена и передачей перетаскивания заключается в том, как объект данных поступает в целевой объект. После того как целевой объект имеет указатель на интерфейс IDataObject объекта данных, процедуры извлечения информации в значительной степени одинаковы для обоих типов передачи данных. Однако некоторые сценарии ограничены определенным типом операции. Дополнительные сведения см. в отдельном сценарии.
Общие рекомендации
В каждом из следующих разделов рассматривается отдельный сценарий передачи данных. Однако передача данных часто более сложна и может включать аспекты нескольких сценариев. Обычно вы не знаете, заранее, какой сценарий вам потребуется обработать. Вот несколько общих рекомендаций, которые следует учитывать.
Для источников данных:
- Форматы буфера обмена оболочки , за исключением CF_HDROP, не определены. Каждый формат, который требуется использовать, должен быть зарегистрирован путем вызова RegisterClipboardFormat.
- Форматы объектов данных предоставляются в порядке предпочтения из источника. Перечислите объект данных и выберите первый, который можно использовать.
- Включите столько форматов, сколько можно поддерживать. Как правило, вы не знаете, где будет удален объект данных. Эта практика повышает вероятность того, что объект данных будет содержать формат, который может принять целевой объект удаления.
- Существующие файлы должны предлагаться в формате CF_HDROP .
- Предложение файловых данных с CFSTR_FILECONTENTS форматами CFSTR_FILEDESCRIPTOR/. Такой подход позволяет целевому объекту создавать файл из объекта данных без необходимости знать ничего о базовом хранилище данных. Обычно данные должны отображаться в виде интерфейса IStream . Этот механизм передачи данных является более гибким, чем глобальный объект памяти и использует гораздо меньше памяти.
- При перетаскивании элементов оболочки источники должны предлагать формат CFSTR_SHELLIDLIST . Объекты данных для элементов можно получить с помощью методов IShellFolder::GetUIObjectOf или IShellItem::BindToHandler. Источники данных могут создать стандартную реализацию объекта данных, которая поддерживает формат CFSTR_SHELLIDLIST с помощью SHCreateDataObject.
- Целевые объекты, которые хотят понять, что элементы перетаскиваются с помощью модели программирования элементов оболочки, могут преобразовать IDataObject в IShellItemArray с помощью SHCreateShellItemArrayFromDataObject.
- Используйте стандартные курсоры обратной связи.
- Поддержка перетаскивания влево и вправо.
- Используйте сам объект данных из внедренного объекта. Этот подход позволяет приложению получать любые дополнительные форматы, которые объект данных должен предложить и избежать создания дополнительного слоя хранения. Например, внедренный объект с сервера A перетаскивается из сервера или контейнера B и удаляется на контейнер C. C должен создать внедренный объект сервера A, а не внедренный объект сервера B, содержащий внедренный объект сервера A.
- Помните, что оболочка может использовать оптимизированные операции перемещения или удаления при перемещении файлов. Приложение должно иметь возможность распознавать эти операции и реагировать соответствующим образом.
Для целевых объектов данных:
- Форматы буфера обмена оболочки , за исключением CF_HDROP, не определены. Каждый формат, который требуется использовать, должен быть зарегистрирован путем вызова RegisterClipboardFormat.
- Реализуйте и зарегистрируйте целевой объект удаления OLE. По возможности избегайте использования целевых объектов Windows 3.1 или сообщения WM_DROPFILES.
- Форматы, содержащиеся в объекте данных, зависят от того, откуда поступает объект. Так как обычно заранее не известно, откуда поступает объект данных, не предполагается, что будет присутствовать определенный формат. Объект данных должен перечислять форматы в порядке качества, начиная с лучшего. Таким образом, чтобы получить лучший доступный формат, приложения обычно перечисляют доступные форматы и используют первый формат в перечислении, который они могут поддерживать.
- Поддержка перетаскивания вправо. Контекстное меню перетаскивания можно настроить, создав обработчик перетаскивания.
- Если приложение примет существующие файлы, он должен иметь возможность обрабатывать CF_HDROP формат.
- Как правило, приложения, принимаюющие файлы, также должны обрабатывать форматы CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR. Хотя файлы из файловой системы имеют формат CF_HDROP, файлы из таких поставщиков, как расширения пространства имен, обычно используют CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR. Примерами являются папки Windows CE, папки ПРОТОКОЛА FTP, веб-папки и папки CAB. Источник обычно реализует интерфейс IStream для представления данных из хранилища в виде файла.
- Помните, что оболочка может использовать оптимизированные операции перемещения или удаления при перемещении файлов. Приложение должно иметь возможность распознавать эти операции и реагировать соответствующим образом.
Копирование имен файлов из буфера обмена в приложение
Сценарий. Пользователь выбирает один или несколько файлов в проводнике Windows и копирует их в буфер обмена. Приложение извлекает имена файлов и вставляет их в документ.
Этот сценарий можно использовать, например, чтобы разрешить пользователю создавать HTML-ссылку, вырезав и вставив файл в приложение. Затем приложение может извлечь имя файла из объекта данных и обработать его, чтобы создать тег привязки.
Когда пользователь выбирает файл в проводнике Windows и копирует его в буфер обмена, оболочка создает объект данных. Затем он вызывает OleSetClipboard, чтобы поместить указатель на интерфейс IDataObject объекта данных в буфер обмена.
Когда пользователь выбирает команду "Вставить" в меню или панели инструментов приложения:
- Вызовите OleGetClipboard, чтобы получить интерфейс IDataObject объекта данных.
- Вызовите IDataObject::EnumFormatEtc , чтобы запросить объект перечислителя.
- Используйте интерфейс IEnumFORMATETC объекта перечислителя для перечисления форматов, содержащихся в объекте данных.
Примечание.
Последние два шага в этой процедуре включены для полноты. Обычно они не необходимы для простой передачи файлов. Все объекты данных, используемые для этого типа передачи данных, должны содержать формат CF_HDROP , который можно использовать для определения имен файлов, содержащихся в объекте. Однако для более общих передач данных следует перечислить форматы и выбрать оптимальный формат, который может обрабатывать приложение.
Извлечение имен файлов из объекта данных
Следующим шагом является извлечение одного или нескольких имен файлов из объекта данных и их вставка в приложение. Обратите внимание, что процедура, описанная в этом разделе, для извлечения имени файла из объекта данных применяется одинаково хорошо для передачи перетаскивания.
Самый простой способ получения имен файлов из объекта данных — это формат CF_HDROP :
Вызовите IDataObject::GetData. Задайте для элемента cfFormat структуры FORMATETC значение CF_HDROP и элементу TYMED_HGLOBAL. Для элемента dwAspect обычно задано значение DVASPECT_CONTENT. Однако если вам нужно иметь путь к файлу в коротком формате (8.3), задайте для dwAspect значение DVASPECT_SHORT.
При возвращении IDataObject::GetData элемент hGlobal структуры STGMEDIUM указывает на глобальный объект памяти, содержащий данные.
Создайте переменную HDROP и задайте для него элемент hGlobal структуры STGMEDIUM. Переменная HDROP теперь является дескриптором структуры DROPFILES , за которой следует двойная строка, завершающая значение NULL, содержащая полные пути к файлам, скопированным файлам.
Определите, сколько путей к файлам находятся в списке, вызвав DragQueryFile с параметром iFile, заданным для 0xFFFFFFFF. Функция возвращает количество путей к файлам в списке. Индекс пути к файлу на основе нуля в этом списке используется на следующем шаге для определения определенного пути.
Извлеките пути к файлам из глобального объекта памяти, вызвав DragQueryFile один раз для каждого файла, указав iFile в индекс файла.
Обработайте пути к файлам по мере необходимости и вставьте их в приложение.
Вызовите ReleaseStgMedium и передайте указатель на структуру STGMEDIUM, переданную в IDataObject::GetData на шаге 1. После выпуска структуры значение HDROP, созданное на шаге 2, больше не является допустимым и не должно использоваться.
Копирование содержимого удаленного файла в приложение
Сценарий. Пользователь перетаскивает один или несколько файлов из проводника Windows и удаляет их в окне приложения. Приложение извлекает содержимое файла (s) и вставляет его в приложение.
Этот сценарий использует перетаскивание для передачи файлов из проводника Windows в приложение. Перед операцией приложение должно:
- Вызовите RegisterClipboardFormat , чтобы зарегистрировать все необходимые форматы буфера обмена оболочки.
- Вызовите RegisterDragDrop, чтобы зарегистрировать целевое окно и интерфейс IDropTarget приложения.
После запуска операции пользователь выбирает один или несколько файлов и начинает перетаскивать их:
- Обозреватель Windows создает объект данных и загружает в него поддерживаемые форматы.
- Обозреватель Windows вызывает DoDragDrop , чтобы инициировать цикл перетаскивания.
- Когда изображение перетаскивания достигает целевого окна, система уведомляет вас, вызвав IDropTarget::D ragEnter.
- Чтобы определить, какой объект данных содержит, вызовите метод IDataObject объекта данных::EnumFormatEtc. Используйте объект перечислителя, возвращаемый методом, чтобы перечислить форматы, содержащиеся в объекте данных. Если приложение не хочет принимать ни один из этих форматов, верните DROPEFFECT_NONE. В этом сценарии приложение должно игнорировать любые объекты данных, которые не содержат форматы, используемые для передачи файлов, например CF_HDROP.
- Когда пользователь удаляет данные, система вызывает IDropTarget::D rop.
- Используйте интерфейс IDataObject для извлечения содержимого файлов.
Существует несколько различных способов извлечения содержимого объекта Shell из объекта данных. Как правило, используйте следующий порядок:
- Если файл содержит формат CF_TEXT , данные — это текст ANSI. Вы можете использовать формат CF_TEXT для извлечения данных, а не открытия самого файла.
- Если файл содержит связанный или внедренный объект OLE, объект данных содержит формат CF_EMBEDDEDOBJECT. Используйте стандартные методы OLE для извлечения данных. Файлы лома всегда содержат формат CF_EMBEDDEDOBJECT.
- Если объект Shell находится из файловой системы, объект данных содержит CF_HDROP формат с именами файлов. Извлеките имя файла из CF_HDROP и вызовите OleCreateFromFile, чтобы создать связанный или внедренный объект. Сведения о том, как получить имя файла из формата CF_HDROP, см. в разделе "Копирование имен файлов" из буфера обмена в приложение.
- Если объект данных содержит формат CFSTR_FILEDESCRIPTOR, можно извлечь содержимое файла из CFSTR_FILECONTENTS формата файла. Сведения об этой процедуре см. в разделе "Использование формата CFSTR_FILECONTENTS для извлечения данных из файла".
- До версии 4.71 приложение указало, что он передает тип ярлыка, задав FD_LINKUI в элементе dwFlags структуры FILEDESCRIPTOR. Для более поздних версий оболочки предпочтительный способ указать, что сочетания клавиш передаются, — использовать формат CFSTR_PREFERREDDROPEFFECT для DROPEFFECT_LINK . Этот подход гораздо эффективнее, чем извлечение структуры FILEDESCRIPTOR только для проверки флага.
Если процесс извлечения данных будет длительным, может потребоваться выполнить операцию асинхронно в фоновом потоке. Затем основной поток может продолжаться без ненужных задержек. Сведения об асинхронном извлечении данных см. в разделе "Перетаскивание и удаление объектов оболочки" асинхронно.
Использование формата CFSTR_FILECONTENTS для извлечения данных из файла
Формат CFSTR_FILECONTENTS предоставляет очень гибкий и мощный способ передачи содержимого файла. Для хранения данных в виде одного файла даже не требуется. Все, что необходимо для этого формата, заключается в том, что объект данных представляет данные целевому объекту, как если бы он был файлом. Например, фактические данные могут быть разделом текстового документа или блоком данных, извлеченными из базы данных. Целевой объект может рассматривать данные как файл и не должен знать ничего о базовом механизме хранения.
Расширения пространства имен обычно используют CFSTR_FILECONTENTS для передачи данных, так как этот формат не предполагает какого-либо конкретного механизма хранения. Расширение пространства имен может использовать любой удобный механизм хранения и использовать этот формат, чтобы представить свои объекты приложениям, как будто они были файлами.
Механизм передачи данных для CFSTR_FILECONTENTS обычно TYMED_ISTREAM. Для передачи указателя интерфейса IStream требуется гораздо меньше памяти, чем загрузка данных в глобальный объект памяти, а IStream — это более простой способ представления данных, чем IStorage.
Формат CFSTR_FILECONTENTS всегда сопровождается форматом CFSTR_FILEDESCRIPTOR . Сначала необходимо проверить содержимое этого формата. Если передается несколько файлов, объект данных фактически будет содержать несколько форматов CFSTR_FILECONTENTS , по одному для каждого файла. Формат CFSTR_FILEDESCRIPTOR содержит имя и атрибуты каждого файла и предоставляет значение индекса для каждого файла, необходимого для извлечения CFSTR_FILECONTENTS формата определенного файла.
Чтобы извлечь формат CFSTR_FILECONTENTS :
- Извлеките формат CFSTR_FILEDESCRIPTOR в виде значения TYMED_HGLOBAL.
- Элемент hGlobal возвращаемой структуры STGMEDIUM указывает на глобальный объект памяти. Блокировка этого объекта путем передачи значения hGlobal в GlobalLock.
- Приведение указателя, возвращаемого GlobalLock, в указатель FILEGROUPDESCRIPTOR. Он указывает на структуру FILEGROUPDESCRIPTOR, за которой следует одна или несколько структур FILEDESCRIPTOR. Каждая структура FILEDESCRIPTOR содержит описание файла, содержащегося в одном из сопровождающих CFSTR_FILECONTENTS форматов.
- Проверьте структуры FILEDESCRIPTOR, чтобы определить, какой из них соответствует файлу, который требуется извлечь. Отсчитываемый от нуля индекс этой структуры FILEDESCRIPTOR используется для идентификации CFSTR_FILECONTENTS формата файла. Так как размер глобального блока памяти не является точным, используйте nFileSizeLow и nFileSizeHigh члены структуры, чтобы определить, сколько байтов представляет файл в глобальном объекте памяти.
- Вызовите IDataObject::GetData с элементом cfFormat структуры FORMATETC, заданным значением CFSTR_FILECONTENTS, и элемент lIndex, заданный на предыдущем шаге. Элемент tymed обычно имеет значение TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE. Затем объект данных может выбрать предпочтительный механизм передачи данных.
- Структура STGMEDIUM, возвращаемая IDataObject::GetData, будет содержать указатель на данные файла. Изучите тимый элемент структуры, чтобы определить механизм передачи данных.
- Если задано значение TYMED_ISTREAM или TYMED_ISTORAGE, используйте интерфейс для извлечения данных. Если задано значение TYMED_HGLOBAL, данные содержатся в глобальном объекте памяти. Обсуждение способа извлечения данных из глобального объекта памяти см. в разделе "Извлечение глобального объекта памяти" из раздела "Объект данных оболочки".
- Вызовите GlobalLock , чтобы разблокировать глобальный объект памяти, заблокированный на шаге 2.
Обработка оптимизированных операций перемещения
Сценарий. Файл перемещается из файловой системы в расширение пространства имен с помощью оптимизированного перемещения.
В обычной операции перемещения целевой объект делает копию данных, а источник удаляет исходный объект. Эта процедура может быть неэффективной, так как для нее требуется две копии данных. С большими объектами, такими как базы данных, обычная операция перемещения может даже не быть практической.
При оптимизированном перемещении целевой объект использует свое представление о том, как хранятся данные для обработки всей операции перемещения. Нет второй копии данных, и для удаления исходных данных не требуется. Данные оболочки хорошо подходят для оптимизации перемещения, так как целевой объект может обрабатывать всю операцию с помощью API оболочки. Типичный пример — перемещение файлов. После перемещения целевого объекта можно использовать SHFileOperation для перемещения файла. Для удаления исходного файла не требуется.
Примечание.
Оболочка обычно использует оптимизированное перемещение для перемещения файлов. Чтобы правильно обрабатывать передачу данных оболочки, приложение должно быть способно обнаруживать и обрабатывать оптимизированное перемещение.
Оптимизированные перемещения обрабатываются следующим образом:
Источник вызывает DoDragDrop с параметром dwEffect, равным DROPEFFECT_MOVE, чтобы указать, что исходные объекты можно переместить.
Целевой объект получает значение DROPEFFECT_MOVE через один из его методов IDropTarget , указывающий, что перемещение разрешено.
Целевой объект копирует объект (неоптимизованный перемещение) или перемещает объект (оптимизированное перемещение).
Затем целевой объект сообщает источнику, нужно ли удалить исходные данные.
Оптимизированное перемещение — это операция по умолчанию с данными, удаленными целевым объектом. Чтобы сообщить источнику, что оптимизированное перемещение выполнено:
-
- Целевой объект задает значение pdwEffect, полученное с помощью метода IDropTarget::D rop, в некоторое значение, отличное от DROPEFFECT_MOVE. Обычно для него задано значение DROPEFFECT_NONE или DROPEFFECT_COPY. Значение будет возвращено источнику DoDragDrop.
- Целевой объект также вызывает метод IDataObject::SetData и передает идентификатор формата CFSTR_PERFORMEDDROPEFFECT для DROPEFFECT_NONE. Этот вызов метода необходим, так как некоторые целевые объекты удаления могут неправильно задать параметр pdwEffect DoDragDrop. Формат CFSTR_PERFORMEDDROPEFFECT — это надежный способ указать, что оптимизированное перемещение произошло.
Если целевой объект сделал неоптимизованный перемещение, данные должны быть удалены источником. Чтобы сообщить источнику о том, что неоптимизованный переход был выполнен:
-
- Целевой объект задает значение pdwEffect, полученное с помощью метода IDropTarget::D rop, для DROPEFFECT_MOVE. Значение будет возвращено источнику DoDragDrop.
- Целевой объект также вызывает метод IDataObject::SetData и передает идентификатор формата CFSTR_PERFORMEDDROPEFFECT для DROPEFFECT_MOVE. Этот вызов метода необходим, так как некоторые целевые объекты удаления могут неправильно задать параметр pdwEffect DoDragDrop. Формат CFSTR_PERFORMEDDROPEFFECT — это надежный способ указать, что произошел неоптимизированный шаг.
-
Источник проверяет два значения, которые могут быть возвращены целевым объектом. Если для обоих задано значение DROPEFFECT_MOVE, он завершает неоптимизированное перемещение, удалив исходные данные. В противном случае целевой объект сделал оптимизированное перемещение и исходные данные были удалены.
Обработка операций удаления по вставки
Сценарий. Один или несколько файлов вырезаются из папки в проводнике Windows и вставляются в расширение пространства имен. Обозреватель Windows оставляет файлы выделенными, пока он не получит отзыв о результатах операции вставки.
Традиционно при сокращении данных пользователь сразу же исчезает из представления. Это может быть не эффективным, и это может привести к проблемам с удобством использования, если пользователь становится обеспокоен тем, что произошло с данными. Альтернативный подход — использовать операцию удаления при вставе.
При операции удаления во вставку выбранные данные не сразу удаляются из представления. Вместо этого исходное приложение помечает его как выбранное, возможно, изменив шрифт или цвет фона. После вставки данных целевое приложение уведомляет источник о результатах операции. Если целевой объект выполнил оптимизированное перемещение, источник может просто обновить его отображение. Если целевой объект выполнил обычное перемещение, источник также должен удалить ее копию данных. Если вставка завершается ошибкой, исходное приложение восстанавливает выбранные данные до исходного внешнего вида.
Примечание.
Оболочка обычно использует удаление во время операции выреза и вставки для перемещения файлов. Операции удаления в вставки с объектами Оболочки обычно используют оптимизированное перемещение для перемещения файлов. Чтобы правильно обрабатывать передачу данных оболочки, приложение должно быть способно обнаруживать операции удаления и вставки и обрабатывать их.
Важное требование удаления вставить заключается в том, что целевой объект должен сообщить о результатах операции источнику. Однако стандартные методы буфера обмена нельзя использовать для реализации удаления в вставки, так как они не предоставляют способ взаимодействия целевого объекта с источником. Вместо этого целевое приложение использует метод IDataObject объекта данных ::SetData , чтобы сообщить о результатах объекту данных. Затем объект данных может взаимодействовать с источником через закрытый интерфейс.
Базовая процедура операции удаления вставить выглядит следующим образом:
- Источник помечает отображение выбранных данных на экране.
- Источник создает объект данных. Он указывает операцию вырезания, добавив формат CFSTR_PREFERREDDROPEFFECT со значением данных DROPEFFECT_MOVE.
- Источник помещает объект данных в буфер обмена с помощью OleSetClipboard.
- Целевой объект извлекает объект данных из буфера обмена с помощью OleGetClipboard.
- Целевой объект извлекает данные CFSTR_PREFERREDDROPEFFECT . Если для него задано значение только DROPEFFECT_MOVE, целевой объект может выполнить оптимизированное перемещение или просто скопировать данные.
- Если целевой объект не выполняет оптимизированное перемещение, он вызывает метод IDataObject::SetData с набором форматов CFSTR_PERFORMEDDROPEFFECT значение DROPEFFECT_MOVE.
- По завершении вставки целевой объект вызывает метод IDataObject::SetData с CFSTR_PASTESUCCEEDED форматом, заданным для DROPEFFECT_MOVE.
- Если метод IDataObject источника::SetData вызывается с CFSTR_PASTESUCCEEDED форматом, равным DROPEFFECT_MOVE, он должен проверить, получил ли он также формат CFSTR_PERFORMEDDROPEFFECT, равный DROPEFFECT_MOVE. Если оба формата отправляются целевым объектом, источнику придется удалить данные. Если получен только формат CFSTR_PASTESUCCEEDED , источник может просто удалить данные из его отображения. Если передача завершается ошибкой, источник обновляет отображение до исходного внешнего вида.
Передача данных в виртуальные папки и из нее
Сценарий. Пользователь перетаскивает объект из виртуальной папки или удаляет его из нее.
Виртуальные папки содержат объекты, которые обычно не являются частью файловой системы. Некоторые виртуальные папки, такие как корзина, могут представлять данные, хранящиеся на жестком диске, но не как обычные объекты файловой системы. Некоторые могут представлять хранимые данные, которые хранятся в удаленной системе, например на ручном компьютере или на FTP-сайте. Другие, такие как папка "Принтеры", содержат объекты, которые не представляют хранимые данные вообще. Хотя некоторые виртуальные папки являются частью системы, разработчики также могут создавать и устанавливать пользовательские виртуальные папки, реализуя расширение пространства имен.
Независимо от типа данных или способа его хранения, объекты папок и файлов, содержащихся в виртуальной папке, представлены оболочкой, как если бы они были обычными файлами и папками. Это ответственность за виртуальную папку, чтобы принимать все данные, содержащиеся в ней, и представить его в оболочку соответствующим образом. Это требование означает, что виртуальные папки обычно поддерживают передачу данных перетаскивания и буфера обмена.
Таким образом, существует две группы разработчиков, которые должны быть обеспокоены передачей данных в виртуальные папки и из них:
- Разработчики, приложения которых должны принимать данные, передаваемые из виртуальной папки.
- Разработчики, расширения пространства имен которых должны правильно поддерживать передачу данных.
Прием данных из виртуальной папки
Виртуальные папки могут представлять практически любой тип данных и могут хранить эти данные любым способом. Некоторые виртуальные папки могут содержать обычные файлы файловой системы и папки. Например, другие могут упаковать все объекты в один документ или базу данных.
При передаче объекта файловой системы в приложение объект данных обычно содержит формат CF_HDROP с полным путем объекта. Приложение может извлечь эту строку и использовать обычные функции файловой системы для открытия файла и извлечения его данных. Тем не менее, поскольку виртуальные папки обычно не содержат обычные объекты файловой системы, они обычно не используют CF_HDROP.
Вместо CF_HDROP данные обычно передаются из виртуальных папок с форматами CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS. Формат CFSTR_FILECONTENTS имеет два преимущества по сравнению с CF_HDROP:
- Не предполагается конкретный метод хранения данных.
- Формат более гибкий. Он поддерживает три механизма передачи данных: глобальный объект памяти, интерфейс IStream или интерфейс IStorage.
Глобальные объекты памяти редко используются для передачи данных в виртуальные объекты или из них, так как данные должны быть скопированы в память в целом. Для передачи указателя интерфейса требуется почти нет памяти и гораздо эффективнее. С очень большими файлами указатель интерфейса может быть единственным практическим механизмом передачи данных. Как правило, данные представлены указателем IStream, так как этот интерфейс является несколько более гибким, чем IStorage. Целевой объект извлекает указатель из объекта данных и использует методы интерфейса для извлечения данных.
Дополнительные сведения об обработке форматов CFSTR_FILEDESCRIPTOR CFSTR_FILECONTENTS см. в разделе "Использование формата CFSTR_FILECONTENTS/ для извлечения данных из файла".
Передача данных в расширение пространства имен и из нее
При реализации расширения пространства имен обычно требуется поддерживать возможности перетаскивания. Следуйте рекомендациям по источникам и целевым объектам, описанным в общих рекомендациях. В частности, расширение пространства имен должно:
- Будьте в состоянии обрабатывать форматы CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS. Эти два формата обычно используются для передачи объектов в расширения пространства имен и из них.
- Будьте в состоянии обрабатывать оптимизированные перемещения. Оболочка ожидает, что объекты оболочки будут перемещены с оптимизированным перемещением.
- Будьте в состоянии обрабатывать операцию удаления во вставку . Оболочка использует удаление при перемещении объектов из оболочки с операцией выреза или вставки.
- Возможность обрабатывать передачу данных через интерфейс IStream или IStorage. Передача данных в виртуальную папку или из нее обычно обрабатывается путем передачи одного из этих двух указателей интерфейса, как правило , указателя IStream . Затем целевой объект вызывает методы интерфейса для извлечения данных:
-
- В качестве источника удаления расширение пространства имен должно извлекать данные из хранилища и передавать его через этот интерфейс в целевой объект.
- В качестве целевого объекта удаления расширение пространства имен должно принимать данные из источника через этот интерфейс и правильно хранить его.
-
Удаление файлов в корзине
Сценарий. Пользователь удаляет файл в корзине. Приложение или расширение пространства имен удаляет исходный файл.
Корзина — это виртуальная папка, которая используется в качестве репозитория для файлов, которые больше не нужны. Пока корзина не была очищена, пользователь может позже восстановить файл и вернуть его в файловую систему.
В большинстве случаев передача объектов Оболочки в корзину работает так же, как и любая другая папка. Однако, когда пользователь удаляет файл в корзине, источник должен удалить исходный файл, даже если обратная связь из папки указывает на операцию копирования. Как правило, источник удаления не имеет способа знать, в какой папке был удален объект данных. Однако для систем Windows 2000 и более поздних версий, когда объект данных удаляется в корзине, оболочка вызовет метод IDataObject объекта данных::SetData с CFSTR_TARGETCLSID форматом, заданным для идентификатора класса корзины (CLSID) (CLSID_RecycleBin). Чтобы правильно обрабатывать регистр корзины, объект данных должен иметь возможность распознавать этот формат и передавать информацию источнику через закрытый интерфейс.
Примечание.
При вызове IDataObject::SetData с набором формата CFSTR_TARGETCLSID для CLSID_RecycleBin источник данных должен закрыть все открытые дескрипторы к объектам, передаваемым перед возвратом из метода. В противном случае можно создать нарушения общего доступа.
Создание и импорт файлов лома
Сценарий. Пользователь перетаскивает некоторые данные из файла данных приложения OLE и удаляет его на рабочем столе или в проводнике Windows.
Windows позволяет пользователям перетаскивать объект из файла данных приложения OLE и удалять его на рабочем столе или в папке файловой системы. Эта операция создает файл слома, содержащий данные или ссылку на данные. Имя файла берется из короткого имени, зарегистрированного для CLSID объекта и CF_TEXT данных. Чтобы оболочка создавала ломовый файл, содержащий данные, интерфейс IDataObject приложения должен поддерживать формат буфера обмена CF_EMBEDSOURCE. Чтобы создать файл со ссылкой, IDataObject должен поддерживать формат CF_LINKSOURCE.
Существует также три дополнительных компонента, которые приложение может реализовать для поддержки файлов слома:
- Поддержка круговой поездки
- Форматы кэшированных данных
- Отложенная отрисовка
Поддержка круглого пути
Круговая поездка включает передачу объекта данных другому контейнеру, а затем обратно в исходный документ. Например, пользователь может передать группу ячеек из электронной таблицы на рабочий стол, создав ломовый файл с данными. Если пользователь передает лом обратно в электронную таблицу, данные должны быть интегрированы в документ, как это было до первоначальной передачи.
Когда оболочка создает файл слома, он представляет данные в виде объекта внедрения. При передаче лома в другой контейнер он передается как объект внедрения, даже если он возвращается в исходный документ. Ваше приложение отвечает за определение формата данных, содержащегося в ломе, и при необходимости помещает данные обратно в собственный формат.
Чтобы установить формат внедренного объекта, определите его CLSID, извлекая CF_OBJECTDESCRIPTOR формат объекта. Если CLSID указывает формат данных, принадлежащий приложению, он должен передавать собственные данные вместо вызова OleCreateFromData.
Кэшированные форматы данных
Когда оболочка создает файл слома, он проверяет реестр для списка доступных форматов. По умолчанию доступны два формата: CF_EMBEDSOURCE и CF_LINKSOURCE. Однако существует ряд сценариев, в которых приложениям может потребоваться иметь файлы слома в разных форматах:
- Чтобы разрешить перенос отходов в контейнеры, отличные от OLE, которые не могут принимать внедренные форматы объектов.
- Чтобы разрешить наборы приложений взаимодействовать с частным форматом.
- Чтобы упростить обработку круговых путей.
Приложения могут добавлять форматы в лом, кэширование их в реестре. Существует два типа кэшированных форматов:
- Форматы кэша приоритета. Для этих форматов данные копируются в полном объеме в лом из объекта данных.
- Форматы отложенного отображения. Для этих форматов объект данных не копируется в лом. Вместо этого отрисовка задерживается до тех пор, пока целевой объект не запрашивает данные. Задержка отрисовки подробно рассматривается в следующем разделе.
Чтобы добавить кэш приоритета или формат отрисовки, создайте вложенный ключ DataFormat под ключ CLSID приложения, который является источником данных. В этом подразделе создайте подраздел PriorityCacheFormats или DelayRenderFormats. Для каждого кэша приоритетов или отрисовки отложенного формата создайте нумерованный подраздел, начиная с нуля. Задайте значение этого ключа строке с зарегистрированным именем формата или значением #X, где X представляет номер формата стандартного формата буфера обмена.
В следующем примере показаны кэшированные форматы для двух приложений. Приложение MyProg1 имеет формат форматированного текста в качестве формата кэша приоритета и закрытый формат "Мой формат" в виде отложенного формата. Приложение MyProg2 имеет формат CF_BITMAP (#8) в качестве формата кэша приоритета.
HKEY_CLASSES_ROOT
CLSID
{GUID}
(Default) = MyProg1
DataFormats
PriorityCacheFormats
0
(Default) = Rich Text Format
DelayRenderFormats
0
(Default) = My Format
{GUID}
(Default) = MyProg2
DataFormats
PriorityCacheFormats
0
(Default) = #8
Дополнительные форматы можно добавить, создав дополнительные нумерованные подразделы.
Отложенная отрисовка
Формат отложенной отрисовки позволяет приложению создавать файл слома, но откладывать расходы на отрисовку данных до тех пор, пока не будет запрошен целевой объект. Интерфейс IDataObject для лома будет предлагать форматы отложенной отрисовки целевому объекту вместе с собственными и кэшируемыми данными. Если целевой объект запрашивает отложенный формат отрисовки, оболочка запустит приложение и предоставит данные целевому объекту из активного объекта.
Примечание.
Так как отложенная отрисовка является несколько рискованным, его следует использовать с осторожностью. Он не будет работать, если сервер недоступен или в приложениях, которые не включены OLE.
Перетаскивание и удаление объектов оболочки асинхронно
Сценарий. Пользователь передает большой блок данных из источника в целевой объект. Чтобы избежать блокировки обоих приложений в течение значительного времени, целевой объект извлекает данные асинхронно.
Как правило, перетаскивание — это синхронная операция. Краткое описание
- Источник удаления вызывает DoDragDrop и блокирует его основной поток до тех пор, пока функция не возвращается. Блокировка основного потока обычно блокирует обработку пользовательского интерфейса.
- После вызова метода IDropTarget::D rop целевой объект извлекает данные из объекта данных в основном потоке. Обычно эта процедура блокирует обработку пользовательского интерфейса целевого объекта в течение процесса извлечения.
- После извлечения данных целевой объект возвращает вызов IDropTarget::D rop, система возвращает DoDragDrop, и оба потока могут продолжаться.
Короче говоря, синхронная передача данных может блокировать основные потоки обоих приложений в течение значительного времени. В частности, оба потока должны ждать, пока целевой объект извлекает данные. Для небольших объемов данных время, необходимое для извлечения данных, работает очень хорошо и синхронно. Однако синхронно извлечение больших объемов данных может привести к длительным задержкам и препятствовать пользовательскому интерфейсу как целевого, так и исходного.
Интерфейс IAsyncOperation/IDataObjectAsyncCapability является необязательным интерфейсом, который можно реализовать объектом данных. Он предоставляет целевой объект удаления возможность асинхронно извлекать данные из объекта данных в фоновом потоке. После передачи извлечения данных фоновому потоку первичные потоки обоих приложений могут продолжаться.
Использование IASyncOperation/IDataObjectAsyncCapability
Примечание.
Интерфейс первоначально был назван IAsyncOperation, но позже он был изменен на IDataObjectAsyncCapability. В противном случае два интерфейса идентичны.
Цель IAsyncOperation/IDataObjectAsyncCapability заключается в том, чтобы разрешить источнику удаления и удалить целевой объект для согласования возможности извлечения данных асинхронно. В следующей процедуре описывается, как источник удаления использует интерфейс:
- Создайте объект данных, предоставляющий IAsyncOperation/IDataObjectAsyncCapability.
- Вызов SetAsyncMode с параметром fDoOpAsync , равным VARIANT_TRUE , чтобы указать, что поддерживается асинхронная операция.
- После возврата DoDragDrop вызовите InOperation:
- Если InOperation завершается сбоем или возвращает VARIANT_FALSE, происходит обычная синхронная передача данных и процесс извлечения данных завершен. Источник должен выполнить любую необходимую очистку и продолжить.
- Если InOperation возвращает VARIANT_TRUE, данные извлекаются асинхронно. Операции очистки должны обрабатываться EndOperation.
- Отпустите объект данных.
- После завершения асинхронной передачи данных объект данных обычно уведомляет источник через закрытый интерфейс.
В следующей процедуре описывается, как целевой объект удаления использует интерфейс IAsyncOperation/IDataObjectAsyncCapability для асинхронного извлечения данных:
- Когда система вызывает IDropTarget::D rop, вызовите IDataObject::QueryInterface и запросите интерфейс IAsyncOperation/IDataObjectAsyncCapability (IID_IAsyncOperation/IID_IDataObjectAsyncCapability) из объекта данных.
- Вызов GetAsyncMode. Если метод возвращает VARIANT_TRUE, объект данных поддерживает асинхронное извлечение данных.
- Создайте отдельный поток для обработки извлечения данных и вызова StartOperation.
- Верните вызов IDropTarget::D rop, как и для обычной операции передачи данных. DoDragDrop возвращает и разблокирует источник удаления. Не вызывайте IDataObject::SetData , чтобы указать результат оптимизированной операции перемещения или удаления при вставке. Дождитесь завершения операции.
- Извлеките данные в фоновом потоке. Основной поток целевого объекта разблокирован и свободен для продолжения.
- Если передача данных была оптимизированной операцией перемещения или удаления при вставке , вызовите IDataObject::SetData , чтобы указать результат.
- Уведомите объект данных о завершении извлечения путем вызова EndOperation.