TDragDropInfo CreateHDrop преобразует информацию
о перетаскиваемых файлах
function TDragDropInfo.CreateHDrop : HGlobal;
var RequiredSize : Integer; i : Integer; hGlobalDropInfo : HGlobal; DropFiles : PDropFiles; c : PChar; begin { Построим структуру TDropFiles в памяти, выделенной через GlobalAlloc. Область памяти сделаем глобальной и совместной, поскольку она, вероятно, будет передаваться другому процессу. } { Определяем необходимый размер структуры } RequiredSize := sizeof (TDropFiles);
for i := 0 to Self.Files.Count-1 do begin { Длина каждой строки, плюс 1 байт для терминатора } RequiredSize := RequiredSize + Length (Self.Files[i]) + 1; end; { 1 байт для завершающего терминатора } inc (RequiredSize);
hGlobalDropInfo := GlobalAlloc ((GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT), RequiredSize);
if (hGlobalDropInfo <>
0) then begin { Заблокируем область памяти, чтобы к ней можно было обратиться } DropFiles := GlobalLock (hGlobalDropInfo);
{ Заполним поля структуры DropFiles } { pFiles -- смещение от начала структуры до первого байта массива с именами файлов. } DropFiles.pFiles := sizeof (TDropFiles);
DropFiles.pt := Self.FDropPoint; DropFiles.fNC := Self.InClientArea; DropFiles.fWide := False; { Копируем каждое имя файла в буфер. Буфер начинается со смещения DropFiles + DropFiles.pFiles, то есть после последнего поля структуры. } c := PChar (DropFiles);
c := c + DropFiles.pFiles; for i := 0 to Self.Files.Count-1 do begin StrCopy (c, PChar (Self.Files[i]));
c := c + Length (Self.Files[i]);
end; { Снимаем блокировку } GlobalUnlock (hGlobalDropInfo);
end; Result := hGlobalDropInfo; end;
Данная функция вычисляет требуемый размер данных (он равен размеру записи TDropFiles, определенной в модуле ShlObj, плюс общая длина всех имен файлов), выделяет область памяти и заполняет структуру. Память выделяет ся из глобального пула (global heap) Windows с атрибутом «общая» (GMEM_SHARE), чтобы ее можно было передавать другим приложениям. Обращения к выделенной памяти осуществляются через логический номер типа HGlobal. Имен
но его мы возвращаем вызывающей стороне, которая обязана освободить данные (функцией API GlobalFree) после завершения работы с ними.
Интерфейсы IDropSource и IDataObject реализуются в файле DRAGDROP.PAS (листинг 4.5) объектами TFileDropSource и THDropDataObject соответственно. Объект TFileDropSource выглядит очень просто. Его конструктор просто вызывает конструктор TInterfacedObject, а затем задает начальное значение счетчика ссылок функцией _AddRef. Функция GiveFeedback просто приказывает DoDragDrop использовать стандартные варианты курсора, а QueryContinueDrag проверяет флаг клавиши Escape и состояние кнопок мыши, определяя по ним, следует ли завершить, продолжить или отменить операцию перетаскивания. В общем, ничего необычного.
THDropDataObject выглядит посложнее. Конструктор создает объект TDragDrop Info, который представляет собой пустой список файлов. Затем вызывающая сторона заносит файлы в список методом Add. Деструктор объекта освобожда ет объект TDragDropInfo, если он существует. Из всех методов интерфейса IData Object реализованы только GetData, QueryGetData и EnumFormatEtc. Другие методы возвращают коды, показывающие, что они (методы) не поддерживаются объектом.
QueryGetData просматривает переданную запись TFormatEtc и проверяет, поддерживается ли формат запрашиваемых данных. Если формат поддержи вается, код возврата показывает, что GetData, вероятно, сможет воспроизвес ти данные. EnumFormatEtc создает и возвращает объект IEnumFormatEtc по статическому массиву структур TFormatEtc. Функция GetData проверяет, допустим ли запрашиваемый формат (для чего снова вызывает QueryGetData), убеждается в наличии данных для воспроизведения и затем вызывает TDragDropInfo.Create HDrop. Последний метод создает глобальную область памяти, которая возвращается вызывающей стороне через передаваемую запись TStgMedium. За освобождение данных отвечает вызывающая сторона (то есть клиент перетаски вания).