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

Тема в разделе "Delphi - Система", создана пользователем kuzduk, 21 сен 2011.

  1. kuzduk

    kuzduk Member

    Регистрация:
    21 сен 2011
    Сообщения:
    19
    Симпатии:
    0
    Нужно вырезать файл в буфер обмена из-под моей программы, да так, чтобы потом можно было этот вырезанный файл вставить в любом файловом менеджере (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
     
  2. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Да собственно... сказать сказать буферу что Вы собрались именно вырезать а не копировать... ;)
    Код (Delphi):
    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;
     
  3. rebux

    rebux Гость

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

    sinkopa Well-Known Member

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

    kuzduk Member

    Регистрация:
    21 сен 2011
    Сообщения:
    19
    Симпатии:
    0
    именно так.


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


    Код (Delphi):
    {$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}
     
  6. rebux

    rebux Гость

    kuzduk
    Немного шокирован... Что-это???
     
  7. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
  8. Slava9371

    Slava9371 Гость

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

    kuzduk Member

    Регистрация:
    21 сен 2011
    Сообщения:
    19
    Симпатии:
    0
    Всё правильно! Shell_Str и Shell_DataOperations - это мои функции. Совсем забыл их дописать. вот они, с подробным описанием:

    Код (Delphi):
    {$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}
     
  10. Slava9371

    Slava9371 Гость

    Большое спасибо!
     
  11. kuzduk

    kuzduk Member

    Регистрация:
    21 сен 2011
    Сообщения:
    19
    Симпатии:
    0
  12. Slava9371

    Slava9371 Гость

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

    kuzduk Member

    Регистрация:
    21 сен 2011
    Сообщения:
    19
    Симпатии:
    0
    Спасибо на добром слове! Вот спец тема для обсуждения каталогера, если какие-то вопросы есть - пишите сюды: http://codeby.net/forum/threads/45819.html



    всё стандартные



    ну дык учение и труд все перетрут! не желаете присоединиться к открытому проекту? http://kuzduk.narod.ru/emailer/emailer.html
     
  14. kuzduk

    kuzduk Member

    Регистрация:
    21 сен 2011
    Сообщения:
    19
    Симпатии:
    0
    Итак поправил первое ссобщение - сделал ссылку на зело полезный модуль, там окромя функций вырезания и вставляния найдёте много приятного
     
  15. MisterSpock

    MisterSpock Member

    Регистрация:
    19 мар 2014
    Сообщения:
    9
    Симпатии:
    0
    Очень полезный модуль оказался, спасибо большое!
     
  16. kuzduk

    kuzduk Member

    Регистрация:
    21 сен 2011
    Сообщения:
    19
    Симпатии:
    0
    пожалуйста. теперь все полезные плюшки в одном флаконе kuLibrary, ссылка в первом сообщении
     
Загрузка...

Поделиться этой страницей