Ошибки в работе буфера обмена в Delphi: почему Windows Explorer отказывается вставлять скопированные файлы
Работа с буфером обмена в Delphi может быть непростой задачей, и одной из распространенных проблем является невозможность вставки файлов обратно в ту же папку, откуда они были скопированы, с помощью Windows Explorer. В данном случае, проблема заключается в использовании формата CF_HDROP для копирования списка файлов в буфер обмена. Этот формат используется для представления списка файлов, которые можно перетащить (drag-and-drop), и обычно работает корректно для вставки файлов в другие папки, но не в исходную.
Проблема
Пользователь столкнулся с ситуацией, когда после копирования файлов в буфер обмена с помощью Delphi, он не может вставить их обратно в исходную папку, используя Windows Explorer. Код для копирования файлов в буфер обмена выглядит следующим образом:
procedure TfMain.CopyFilesToClipboard(FileList: string);
...
begin
...
if FileList <> '' then
Move(FileList[1], (PByte(DropFiles) + SizeOf(TDropFiles))^,
iLen * SizeOf(Char));
...
Clipboard.SetAsHandle(CF_HDROP, hGlobal);
...
end;
Этот код использует глобальный блок памяти для хранения структуры DROPFILES, которая содержит список файлов для перетаскивания.
Подтвержденный ответ
Проблема заключается в том, что Windows Explorer не поддерживает вставку файлов из буфера обмена в ту же папку, если используется формат CF_HDROP. Вместо этого, рекомендуется использовать IDataObject для представления файлов в буфере обмена. Для файлов из одной папки можно получить IShellFolder исходной папки, запросить PIDL для каждого файла, и затем получить IDataObject, который можно поместить в буфер обмена.
Пример кода для копирования файлов в буфер обмена с использованием IDataObject:
uses
System.Classes, Winapi.Windows, Winapi.ActiveX, Winapi.Shlobj, Winapi.ShellAPI, System.Win.ComObj;
...
procedure CopyFilesToClipboard(const Folder: string; FileNames: TStrings);
...
begin
...
for I := 0 to FileNames.Count-1 do
begin
...
SF.ParseDisplayName(0, nil, PChar(FileNames[i]), Eaten, PidlChildren[i], Attrs);
...
end;
SF.GetUIObjectOf(0, FileNames.Count, PIdlChildren[0], IDataObject, nil, obj);
OleSetClipboard(obj);
OleFlushClipboard;
...
end;
Если файлы находятся в разных папках, можно использовать формат CFSTR_SHELLIDLIST, который также позволяет представить список файлов для перетаскивания.
Альтернативный ответ
Для файлов из разных папок можно использовать следующий код:
uses
System.Classes, System.SysUtils, Winapi.Windows, Winapi.ActiveX, Winapi.Shlobj, Winapi.ShellAPI, System.Win.ComObj, Vcl.Clipbrd;
...
function HIDA_GetPIDLFolder(pida: PIDA): LPITEMIDLIST;
...
procedure CopyFilesToClipboard(FileNames: TStrings);
...
begin
...
for I := 0 to FileNames.Count-1 do
begin
...
SHParseDisplayName(PChar(FileNames[I]), nil, PidlInfo[I].Pidl, 0, Attrs);
...
end;
...
Clipboard.SetAsHandle(CF_SHELLIDLIST, gmem);
...
end;
...
initialization
CF_SHELLIDLIST := RegisterClipboardFormat(CFSTR_SHELLIDLIST);
Или, используя функцию CIDLData_CreateFromIDArray:
procedure CopyFilesToClipboard(FileNames: TStrings);
...
begin
...
for I := 0 to FileNames.Count-1 do
begin
...
SHParseDisplayName(PChar(FileNames[I]), nil, Pidls[I], 0, Attrs);
...
end;
CIDLData_CreateFromIDArray(nil, FileNames.Count, PItemIDList(Pidls), obj);
...
end;
Вывод
Для корректной работы с буфером обмена в Delphi и возможности вставки файлов в исходную папку с помощью Windows Explorer, следует использовать IDataObject или формат CFSTR_SHELLIDLIST. Эти подходы позволяют корректно представить список файлов для перетаскивания и обеспечивают совместимость с Windows Explorer.
Проблема, описанная в запросе, связана с ограничениями Windows Explorer, который не позволяет вставлять файлы обратно в ту же папку, откуда они были скопированы, если для этого используется формат `CF_HDROP` буфера обмена в Delphi.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.