Есть следующая задача: нужно реализовать 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 но там немного другая функция.
Уф. Вот вроде все если есть вопросы пишите. Но больше жду ответов или предложений
Заранее благодарен.