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

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


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

скачать модуль kuShell.pas с процедурами можно здесь: http://kuzduk.zz.mu/prog/kuLibrary.zip
 

sinkopa

Well-known member
17.06.2009
344
4
#2
Нужно вырезать файл в буфер обмена из-под моей программы.
Так, чтобы потом можно было этот вырезанный файл вставить в любом файловом менеджере (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

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

sinkopa

Well-known member
17.06.2009
344
4
#4
мда очень интересно..
а файл действительно поместится в буфер?
Собственно не сам файл, а указатель на структуру TDropFiles.
А, затем, после команды пользователя "Вставить", система найдет по этому указателю файлы и выполнит перемещение в указанный каталог...
Помоему вполне логично...
Представьте что файлы которые Вы собираетесь переместить будут размером гигабайт так на 300... где в буфере взять столько места? :D
Притом... пользователь ведь может и отказаться от намерения что нибудь перемещать... :facepalm:
 
21.09.2011
23
3
#5
Собственно не сам файл, а указатель на структуру 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

#8
Случайно наткнулся на код, выложенный выше, все здорово!
Вот только Компилятор почему-то ругается на Shell_Str и Shell_DataOperations может в USES чего прописать надо или еще что?
Использую Delphi 2007.
Подскажите пожалуйста уж очень полезный код.
 
21.09.2011
23
3
#9
Вот только Компилятор почему-то ругается на 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}
 
S

Slava9371

#11
Заглянул на сайт, посмотрел программу "Kataloger" на мой взгляд отличная программа, просто и со вкусом, и по ходу все компоненты стандартные, эх научиться бы тоже писать стильные программы кривых без сторонних компонентов.
 
21.09.2011
23
3
#12
Заглянул на сайт, посмотрел программу "Kataloger" на мой взгляд отличная программа, просто и со вкусом
Спасибо на добром слове! Вот спец тема для обсуждения каталогера, если какие-то вопросы есть - пишите сюды: http://codeby.net/forum/threads/45819.html



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



эх научиться бы тоже писать стильные программы кривых без сторонних компонентов.
ну дык учение и труд все перетрут! не желаете присоединиться к открытому проекту? http://kuzduk.narod.ru/emailer/emailer.html
 
21.09.2011
23
3
#13
Итак поправил первое ссобщение - сделал ссылку на зело полезный модуль, там окромя функций вырезания и вставляния найдёте много приятного
 
21.09.2011
23
3
#15
пожалуйста. теперь все полезные плюшки в одном флаконе kuLibrary, ссылка в первом сообщении