Как Вырезать Файл В Буфер Обмена?

kuzduk

Green Team
21.09.2011
31
10
BIT
70
Нужно вырезать файл в буфер обмена из-под моей программы, да так, чтобы потом можно было этот вырезанный файл вставить в любом файловом менеджере (Ctrl+V): проводник, TotalCommander, DubleCommander... (Ессено вырезаем не содержимое файла в буфер, а ссылку на файл: такой то файл вырезан и ожидает вставки)


Проделать оное можно с помощью процедур:
procedure Clipboard_DataSend(const DataPaths: TStrings; const MoveType: integer); //Вырезаем или копируем
procedure ClipBoard_DataPaste(const Target: string); //Вставляем

скачать модуль kuShell.pas с процедурами можно здесь:
 
S

sinkopa

Нужно вырезать файл в буфер обмена из-под моей программы.
Так, чтобы потом можно было этот вырезанный файл вставить в любом файловом менеджере (Ctrl+V): проводник, TotalCommander, DubleCommander...

Копировать получается, а вырезать как???
Да собственно... сказать сказать буферу что Вы собрались именно вырезать а не копировать... ;)
Код:
procedure Clipboard_DataCopy(ShellStr: string);
var
DropFiles: PDropFiles;
hGlobal: THandle;
iLen: Integer;
ADropEffectFormat: Cardinal;
ADropEffect: PCardinal;
begin
iLen := Length(ShellStr) + 2;
ShellStr := ShellStr + #0#0;
OpenClipboard(0);
hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT, SizeOf(TDropFiles) + iLen);
if (hGlobal = 0) then raise Exception.Create('Could not allocate memory.');
begin
DropFiles := GlobalLock(hGlobal);
DropFiles^.pFiles := SizeOf(TDropFiles);
Move(ShellStr[1], (PChar(DropFiles) + SizeOf(TDropFiles))^, iLen);
SetClipboardData(CF_HDROP, hGlobal);
GlobalUnlock(hGlobal);
end;

ADropEffectFormat := RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT); // CFSTR_PREFERREDDROPEFFECT = 'Preferred DropEffect'
hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT, sizeof(dword));
ADropEffect := GlobalLock(hGlobal);

// говорим буферу что делаем с данными
ADropEffect^ := 2; // 2 если CUT or 5 если COPY

SetClipboardData(ADropEffectFormat, hGlobal);
GlobalUnlock(hGlobal);
CloseClipboard;
end;
 
R

rebux

мда очень интересно..
а файл действительно поместится в буфер?
 
S

sinkopa

мда очень интересно..
а файл действительно поместится в буфер?
Собственно не сам файл, а указатель на структуру TDropFiles.
А, затем, после команды пользователя "Вставить", система найдет по этому указателю файлы и выполнит перемещение в указанный каталог...
Помоему вполне логично...
Представьте что файлы которые Вы собираетесь переместить будут размером гигабайт так на 300... где в буфере взять столько места? :D
Притом... пользователь ведь может и отказаться от намерения что нибудь перемещать... :facepalm:
 

kuzduk

Green Team
21.09.2011
31
10
BIT
70
Собственно не сам файл, а указатель на структуру TDropFiles.
А, затем, после команды пользователя "Вставить", система найдет по этому указателю файлы и выполнит перемещение в указанный каталог.
именно так.


ребята! все вопросы решены. вот как это делается:


Код:
{$REGION '  Clipboard  '}



//============================================================================== Copy
procedure Clipboard_DataCopy(const DataPaths: TStrings);
{
Отправляет файлы/папки в буфер обмена на копирование(будто вы нажали в проводнике Ctrl+C)
чтоб птом можно было вставить(Ctrl+V) эти данные в любом файловом менеджере.

uses ShlObj, ClipBrd;
}
var
DropFiles: PDropFiles;
hGlobal: THandle;
iLen: Integer;
f: Cardinal;
d: PCardinal;
DataSpecialList: string; //список адресов(FullPath) файлов/папок которые надо копировать


begin

Clipboard.Open;

Clipboard.Clear;

//преобразовываем в спец-строку
DataSpecialList := Shell_Str(DataPaths);

iLen := Length(DataSpecialList) * SizeOf(Char);
hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT, SizeOf(TDropFiles) + iLen);

Win32Check(hGlobal <> 0);
DropFiles := GlobalLock(hGlobal);
DropFiles^.pFiles := SizeOf(TDropFiles);

{$IFDEF UNICODE}
DropFiles^.fWide := true;
{$ENDIF}

Move(DataSpecialList[1], (PansiChar(DropFiles) + SizeOf(TDropFiles))^, iLen);
SetClipboardData(CF_HDROP, hGlobal);
GlobalUnlock(hGlobal);


//FOR COPY
begin
f := RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT, sizeof(dword));
d := PCardinal(GlobalLock(hGlobal));
d^ := 5;//DROPEFFECT_MOVE; 2-Cut, 5-Copy
SetClipboardData(f, hGlobal);
GlobalUnlock(hGlobal);
end;

Clipboard.Close;

end;


//============================================================================== Cut
procedure Clipboard_DataCut(const DataPaths: TStrings);
{
Отправляет файлы/папки в буфер обмена на вырезку(будто вы нажали в проводнике Ctrl+X)
чтоб потом можно было вставить(Ctrl+V) эти данные в любом файловом менеджере.

uses ShlObj, ClipBrd;
}

var
DropFiles: PDropFiles;
hGlobal: THandle;
iLen: Integer;
f: Cardinal;
d: PCardinal;
DataSpecialList: string; //список адресов(FullPaths) файлов/папок которые надо вырезать

begin

Clipboard.Open;

Clipboard.Clear;

//преобразовываем в спец-строку
DataSpecialList := Shell_Str(DataPaths);


iLen := Length(DataSpecialList) * SizeOf(char);
hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT, SizeOf(TDropFiles) + iLen);
Win32Check(hGlobal <> 0);
DropFiles := GlobalLock(hGlobal);
DropFiles^.pFiles := SizeOf(TDropFiles);

{$IFDEF UNICODE}
DropFiles^.fWide := true;
{$ENDIF}

Move(DataSpecialList[1], (PansiChar(DropFiles) + SizeOf(TDropFiles))^, iLen);
SetClipboardData(CF_HDROP, hGlobal);
GlobalUnlock(hGlobal);

//FOR CUT
begin
f := RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
hGlobal := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT, sizeof(dword));
d := PCardinal(GlobalLock(hGlobal));
d^ := 2;//DROPEFFECT_MOVE; 2-Cut, 5-Copy
SetClipboardData(f, hGlobal);
GlobalUnlock(hGlobal);
end;

Clipboard.Close;

end;


//============================================================================== Copy or Cut
function Clipboard_OperationType : integer;
{
Определяет тип операции в буфере.
Т.е. если вы вырезали в файловом менеджере, то это один тип, если копировали - другой.
Эта функция создаваласть специально для функции ClipBoard_DataPaste,
чтоб было понятно что делать: копировать или вырезать.

5 - copy
2 - cut

DropEffect_None = 0;
DropEffect_Copy = 1;
DropEffect_Move = 2;
DropEffect_Link = 4;
}
var
ClipFormat,hn: Cardinal;
szBuffer: array[0..511] of Char;
FormatID: string;
pMem: Pointer;

begin

Result := 0;

if not OpenClipboard(Application.Handle) then exit;


try
ClipFormat := EnumClipboardFormats(0);

while (ClipFormat <> 0)
do
begin

GetClipboardFormatName(ClipFormat, szBuffer, SizeOf(szBuffer));
FormatID := string(szBuffer);

if SameText(FormatID,'Preferred DropEffect')
then
begin
hn := GetClipboardData(ClipFormat);
pMem := GlobalLock(hn);
Move(pMem^, Result, 4);// <- теперь в Result тип операции
GlobalUnlock(hn);
Break;
end;

ClipFormat := EnumClipboardFormats(ClipFormat);

end;

finally
CloseClipboard;
end;


end;


//============================================================================== Paste
procedure ClipBoard_DataPaste(const Target: string);
{
Эта функция вставит из буфера обмена файлы/папки,
которые копировали/вырезали(Ctrl+C / Ctrl+X) в буфер в каком-либо фаловом менеджере(Проводник, ТоталКоммандер)

Target - папка в которую будет вставлены данные
Clipboard_OperationType - подфункция которая определяет что надо сделать: Копировать или Вырезать
}

var
h : THandle;
Sourse, sr : string;

begin

//Если то, что находиться в буфере
//НЕ является файлами/папками, которые копированы/вырезаны, то выходим
//CF_HDROP - дескриптор который идентифицирует список файлов.
//Прикладная программа может извлечь информацию о файлах, передавая дескриптор функции DragQueryFile.
if not Clipboard.HasFormat(CF_HDROP) then exit;


Clipboard.Open;

try

h := Clipboard.GetAsHandle(CF_HDROP);

if h <> 0
then
begin

Sourse := Shell_Str( ClipBoard_GetDataList_FromHandle(h) );

sr := Copy( Sourse, 0, Pos(#0, Sourse)-1 ); //Path №1
sr := ExtractFilePath(sr);		  //Родительская папка Data


if IncludeTrailingBackslash(sr) = IncludeTrailingBackslash(Target)

then//Делаем копию фала: откуда copy туда и paste
begin
case Clipboard_OperationType
of
5: Shell_DataOperations(sourse, target, FO_COPY, FOF_SIMPLEPROGRESS or FOF_RENAMEONCOLLISION );
2: Shell_DataOperations(sourse, target, FO_MOVE, FOF_SIMPLEPROGRESS );
end;
end

else
begin
case Clipboard_OperationType
of
5: Shell_DataOperations(sourse, target, FO_COPY, FOF_SIMPLEPROGRESS );
2: Shell_DataOperations(sourse, target, FO_MOVE, FOF_SIMPLEPROGRESS );
end;
end;

end;

finally
Clipboard.Close;
end;




end;


//============================================================================== Data List
function ClipBoard_GetDataList_FromHandle(h: THandle) : TStrings;
{
Функция возвращает список файлов/папок из буфера обмена по хэндлу для спец-операций:
Копирования/Вырезания
Дропа(Drag&Drop)
}

var
FilePath: array [0..MAX_PATH] of Char;
i, FileCount: Integer;

begin

Result := nil;

if h = 0 then exit;

Result := TStringList.Create;


FileCount := DragQueryFile(h, $FFFFFFFF, nil, 0);

for i := 0 to FileCount - 1
do
begin
DragQueryFile(h, i, FilePath, SizeOf(FilePath));
Result.Add(FilePath);
end;



end;



{$ENDREGION}
 
S

Slava9371

Случайно наткнулся на код, выложенный выше, все здорово!
Вот только Компилятор почему-то ругается на Shell_Str и Shell_DataOperations может в USES чего прописать надо или еще что?
Использую Delphi 2007.
Подскажите пожалуйста уж очень полезный код.
 

kuzduk

Green Team
21.09.2011
31
10
BIT
70
Вот только Компилятор почему-то ругается на Shell_Str и Shell_DataOperations может в USES чего прописать надо или еще что?
Всё правильно! Shell_Str и Shell_DataOperations - это мои функции. Совсем забыл их дописать. вот они, с подробным описанием:

Код:
{$REGION						  '  Shell  '}


//****************************************************************************** Special Shell Str
function Shell_Str(Strs: TStrings) : string;
{
Функция преобразует TStirngs в спец-строку для Shell
это спец-строка для буфера обмена, где строки разделены знаком #0
и вся спец-строка строка заканчивается #0#0
}
var
//i: Integer;
s: string;

begin
//Y_('into Shell_Str --- Count of Strs', inttostr(Strs.Count) );

s := StringReplace(Strs.Text, #13#10, #0, [rfReplaceAll]);
s := trim(s) + #0#0;
Result := s;


//for i := 0 to Strs.Count - 1
//do Result := Result + Strs.Strings[i] + #0;
//
//Result := Result + #0;

//Y_('into Shell_Str', Result );

end;


//****************************************************************************** Shell File Operation
function Shell_DataOperations (const source, target: string; operacia, flags: Integer): Boolean;
{
Функция для копирования/вырезания/перименования/удаления данныx средсвами API

uses ShellAPI

source - Special Shell Str of Data

operacia:
FO_COPY
FO_MOVE
FO_RENAME
FO_DELETE

flags:
FOF_ALLOWUNDO		 - Если возможно, сохраняет информацию для возможности UnDo. Если вы хотите не просто удалить файлы, а переместить их в корзину, должен быть установлен флаг/
FOF_CONFIRMMOUSE	 - Не реализовано.
FOF_FILESONLY		 - Если в поле pFrom установлено *.*, то операция будет производиться только с файлами.
FOF_MULTIDESTFILES	- Указывает, что для каждого исходного файла в поле pFrom указана своя директория - адресат.
FOF_NOCONFIRMATION	- Отвечает "yes to all" на все запросы в ходе опеации.
FOF_NOCONFIRMMKDIR	- Не подтверждает создание нового каталога, если операция требует, чтобы он был создан.
FOF_RENAMEONCOLLISION - В случае, если уже существует файл с данным именем, создается файл с именем "Copy #N of..."
FOF_SILENT			- Не показывать диалог с индикатором прогресса.
FOF_SIMPLEPROGRESS	- Показывать диалог с индикатором прогресса, но не показывать имен файлов.
FOF_WANTMAPPINGHANDLE - Вносит hNameMappings элемент. Дескриптор должен быть освобожден функцией SHFreeNameMappings
}

var SHOS: TSHFileOpStruct;

begin

FillChar (SHOS, SizeOf(SHOS), #0);

SHOS.Wnd	:= 0;
SHOS.wFunc := operacia;
SHOS.pFrom := PCHAR(source);
SHOS.pTo	:= PCHAR(target);
SHOS.fFlags := flags;

Result := (SHFileOperation(SHOS) = 0) and (not SHOS.fAnyOperationsAborted);


end;


{$ENDREGION}
 

kuzduk

Green Team
21.09.2011
31
10
BIT
70
Дополняю тему файлом: там все функции для копирования/вырезки/вставки через буфер обмена:




а вот, кстати, и моя великая программа:
 
S

Slava9371

Заглянул на сайт, посмотрел программу "Kataloger" на мой взгляд отличная программа, просто и со вкусом, и по ходу все компоненты стандартные, эх научиться бы тоже писать стильные программы кривых без сторонних компонентов.
 

kuzduk

Green Team
21.09.2011
31
10
BIT
70
Заглянул на сайт, посмотрел программу "Kataloger" на мой взгляд отличная программа, просто и со вкусом
Спасибо на добром слове! Вот спец тема для обсуждения каталогера, если какие-то вопросы есть - пишите сюды: https://codeby.net/threads/45819.html



и по ходу все компоненты стандартные
всё стандартные



эх научиться бы тоже писать стильные программы кривых без сторонних компонентов.
ну дык учение и труд все перетрут! не желаете присоединиться к открытому проекту?
 

kuzduk

Green Team
21.09.2011
31
10
BIT
70
Итак поправил первое ссобщение - сделал ссылку на зело полезный модуль, там окромя функций вырезания и вставляния найдёте много приятного
 
M

MisterSpock

Очень полезный модуль оказался, спасибо большое!
 

kuzduk

Green Team
21.09.2011
31
10
BIT
70
пожалуйста. теперь все полезные плюшки в одном флаконе kuLibrary, ссылка в первом сообщении
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!