Drag & Drop для виртуальной файловой системы
От: pi  
Дата: 20.04.04 12:21
Оценка:
Есть следующая задача: нужно реализовать Drag & Drop для виртуальной файловой системы.
Проблема возникает только при перетаскивании из нашей программы в Explorer. В настоящий
момент решение имеет следующий вид:
1. Есть реализация интерфеса IDataObject — TDropFileSource.
В методе GetData заполняются список файлов и его содержимое
для форматов CF_FILEGROUPDESCRIPTOR и CF_FILECONTENTS.
2. При заполнении CF_FILECONTENTS необходимо заполнить поле stm структуры TStgMedium (проект в
данный момент реализуется на Delphi).

function TDropFileSource.DoGetData(const FormatEtcIn: TFormatEtc;
         out Medium: TStgMedium):HRESULT;
begin

    if (FormatEtcIn.cfFormat = CF_FILEGROUPDESCRIPTOR) and
      (FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
      (FormatEtcIn.tymed and TYMED_HGLOBAL <> 0) then
    begin
      Medium.hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_ZEROINIT, SizeOf(TFileGroupDescriptor));
      Medium.tymed := TYMED_HGLOBAL;
      fileGroupDescriptor := GlobalLock(Medium.hGlobal);

      try
        // заполняем список файлов из массива ffiles
        // ,,,
      finally
        GlobalUnlock(Medium.hGlobal);
      end;

      result := S_OK;
    end

    else if (FormatEtcIn.cfFormat = CF_FILECONTENTS) and
      (FormatEtcIn.dwAspect = DVASPECT_CONTENT) and
      (FormatEtcIn.tymed and TYMED_ISTREAM <> 0) then
    begin
      // дастаем имя файла
      fileName := ffiles[FormatEtcIn.lindex];

      // делаем темповый фалик для будущего копирования с удаленной файловой системы
      tmp := GetMemory(255);
      GetTempPath(255,tmp);
      tempFile := tmp + fileName;
      srcFile := CurrentDir + fileName;

      // Вызов копирование файла
      RemoteFileSystem.FileCopy(srcFile, tempFile);

      // Тут появляется ПРОБЛЕМА 1: Дело в том что RemoteFileSystem это 
      // интерфес а FileCopy асинхронная функция. Т.е. результат конца копирования м.б.  
      // узнать через RemoteFileSystem_Sink интерфейс. Зацыклить прогу сдесь 
      // нельзя. Пробовали создать поток, но к сажалению тоже не удается 
      // получить нотификацию конца копирования. Но допустим
      // нам удалось сделать поток который ожидает конца копирования:
      
      WaitForRemoteFileCopyFinished;
      
      // А тут появляется ПРОБЛЕМА 2: Прога на время копированя будет подвисать. 
      // Хотелось бы чтобы это все работало асинхронно. Почитывая MSDN можно наткнутся на 
      // IAsyncOperation, как бы там все скудно не описывалось есть проблема и с ним, он
      // рализован начиная с Win ME. А тут есть задача поддержки и Win 98. Так что 
      // IAsyncOperation тоже не подходит.

      // Создаем Stream типа IStream
      OleCheck(CreateStreamOnHGlobal(0, True, Stream)); 
      // Копируем файл в Stream 
      CopyFileToStream(tempFile,Stream);
      // Устанавливаем в начало потока
      OleCheck(Stream.Seek(0, STREAM_SEEK_SET, newPos));

      Medium.tymed := TYMED_ISTREAM;
      Medium.stm := Pointer(Stream);
    end;
end;


Теперь несколько соображений по поводу решения проблемы:
1. Завернуть каким-то образом работу интерфейсов необходимых для Drag & Drop в поток.
Честно говоря не знаю как это все сделать но такая дурацкая идея приходит на ум.
2. Я новичок в COM-е, так что не судите строго о моей терминалогии .
Знаю есть пару способов пересылать данные через IDataObject: через Moniker и
через Marshal Interface. Но я сомневаюсь что со стороны Explorer-а будет адекватная реакция.
Имеется ввиду что Explorer запустит мой интерфейс для того что-бы запустить операцию копирования.
3. Идеальный вариант, опеределить Destination file name. Проблемы бы вообще небыло
4. Сделать наследника от IStream и выделить его в глобальной памяти. К сажалению ничего не
нашел кроме CreateStreamOnHGlobal, которая позваляет создать в Global только IStream и ничего
иного. Таже история и с IStorage но там немного другая функция.

Уф. Вот вроде все если есть вопросы пишите. Но больше жду ответов или предложений
Заранее благодарен.



 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.