Существует ли Windows API для программного вырезания/копирования/вставки файлов через проводник Windows?

Я знаю, что SHFileOperation можно использовать для выполнения файловых операций. с Проводником Windows, но он выполняет только полные операции с файлами, когда известны и источник, и место назначения.

Существует ли API, который позволяет приложению вырезать, копировать или вставлять в проводнике Windows из приложения?

Чтобы ответить на пару вопросов:

  • Использование Проводника Windows для выполнения операций с файлами/папками значительно упростило бы перемещение нескольких объектов. Это особенно важно для перемещения папок и их содержимого, поскольку MoveFile не поддерживает перемещение папок на другие тома.

  • Использование проводника Windows для выполнения операций с файлами/папками позволит добавить операции в буфер отмены проводника Windows, чтобы их можно было отменить, в противном случае операции, выполненные с консольными приложениями/командной строкой, не могут быть отменены.

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


person Synetech    schedule 23.03.2012    source источник
comment
Быстрый поиск здесь, на SO, показал этот ответ, который может оказаться полезным. Существует API для программного доступа к буферу обмена. Вы используете .NET или нативный код?   -  person Adam Mihalcin    schedule 23.03.2012
comment
@AdamMihalcin, хм, я не подумал взломать его с помощью буфера обмена. Я провел несколько тестов, и похоже, что по крайней мере вырезать/копировать можно таким образом, но я не уверен, как будет реализована вставка. Простая функция API была бы намного лучше.   -  person Synetech    schedule 23.03.2012
comment
Это сработало для меня   -  person Miserable Variable    schedule 22.04.2014


Ответы (3)


Трудно представить, зачем такая функция существует, или что хорошего было бы, если бы она существовала.

Вырезание/копирование и вставка предназначены для удобства пользователя. Это позволяет им перемещать/копировать что-то в другое место позже. Приложение, реализующее функции вырезания/копирования и вставки, может не знать, куда в конечном итоге будут вставлены данные, но это нормально, поскольку пользователь все равно знает.

Но приложение, выполняющее действие вырезания/копирования-вставки, не имеет большого смысла, потому что для того, чтобы часть «вставки» работала, приложение должно знать где элемент будет вставлен. А если он это знает, то может просто вызвать SHFileOperation функцию, о которой вы уже знаете.

Если вы на самом деле просто говорите о том, чтобы предоставить пользователю возможность вырезать/копировать/вставить элемент, тогда вы захотите использовать буфер обмена, как это делает Windows. Когда элемент вырезается или копируется, он помещается в буфер обмена. При вставке элемента извлекается текущее содержимое буфера обмена. Используйте функции Windows API буфера обмена для взаимодействия с буфером обмена. .

person Cody Gray    schedule 23.03.2012
comment
Вот пример: вы за консолью. Вы вводите C:\>cut foobar.txt, а затем C:\Somewhere\Else>paste. Это очень похоже на pushd/popd. - person Synetech; 24.03.2012
comment
@Syn: Да, это что-то помещает в буфер обмена. Для этого нет специального API, вы просто используете функции, связанные с буфером обмена, такие как OpenClipboard и SetClipboardData. - person Cody Gray; 24.03.2012
comment
Да, и я легко понимаю, как таким образом можно выполнить и копирование, и вырезание, но не вижу способа сделать таким образом вставку. Я предполагаю, что он мог прочитать буфер обмена и вручную выполнить операцию с файлом в зависимости от DropEffect CF_HDROP, но это довольно беспорядочно, поэтому я надеялся, что есть какой-то ярлык для подключения к Функции вырезания/копирования/вставки Проводника. - person Synetech; 24.03.2012
comment
@Syn: они не скрывали функцию GetClipboardData. Проводник не использует и не предоставляет для этого специальный API, и я до сих пор не понимаю, почему вы так считаете. - person Cody Gray; 24.03.2012
comment
Смоделируйте падение на папку IDropTarget. - person Raymond Chen; 24.03.2012
comment
› Я до сих пор не понимаю, почему вы так считаете. Доступ к функциям вырезания/копирования/вставки в проводнике (например, hExplorer->Cut(); hExplorer->Paste();) был бы намного проще, чем ввод вручную или обработка данных в буфер обмена. Это не так уж плохо для одного файла, но для нескольких объектов… - person Synetech; 24.03.2012
comment
@RaymondChen, это звучит еще более запутанно. Я собираюсь собрать тестовую программу, используя библиотеку функций буфера обмена, которую я написал некоторое время назад (хотя некоторые из них действительно включают OLE). - person Synetech; 24.03.2012
comment
@Synetech Пример программы. - person Raymond Chen; 24.03.2012
comment
@Раймонд, спасибо; это выглядит многообещающе. Я тоже попробую это. - person Synetech; 24.03.2012
comment
@Down: На какой вопрос я не ответил? В последнем абзаце конкретно объясняется, как использовать API буфера обмена, чтобы делать то, что он просит. - person Cody Gray; 25.03.2012
comment
Вот как я его использую: я провожу большую часть своего времени в emacs или в командной строке. Но я часто люблю прикреплять файлы к электронным письмам. Поэтому я использую File2Clip, чтобы скопировать файл из Emacs и вставить его в свое электронное письмо. Без этого мне пришлось бы либо перейти к папке из всплывающего окна вложений Outlook, либо открыть папку в проводнике, а затем перетащить в Outlook. - person Miserable Variable; 22.04.2014

Я реализовал это в своем файловом менеджере, вот ссылка на источник GitHub для функции копирования. Паста рядом.

Он работает, создавая невидимое контекстное меню проводника для интересующих элементов файловой системы, а затем вызывая команду «Вырезать», «Копировать» или «Вставить» из этого меню. Это на C++ (потому что COM), но я уверен, что вы можете каким-то образом использовать COM и из других языков.

bool copyObjectsToClipboard(std::vector<std::wstring> objects, void * parentWindow)
{
    ComInitializer comInitializer;

    IContextMenu * imenu = 0;
    HMENU hMenu = NULL;
    if (!prepareContextMenuForObjects(objects, parentWindow, hMenu, imenu) || !hMenu || !imenu)
        return false;

    CComInterfaceReleaser menuReleaser(imenu);

    const char command[] = "Copy";

    CMINVOKECOMMANDINFO info = { 0 };
    info.cbSize = sizeof(info);
    info.hwnd = (HWND)parentWindow;
    info.lpVerb = command;
    info.nShow = SW_SHOWNORMAL;
    const auto result = imenu->InvokeCommand((LPCMINVOKECOMMANDINFO)&info);

    DestroyMenu(hMenu);

    return SUCCEEDED(result);
}
person Violet Giraffe    schedule 27.12.2015
comment
Число 26 не является договорным. Команда 26 может означать шифрование в зависимости от того, какие другие расширения оболочки установлены. Просто поместите объект данных в буфер обмена самостоятельно - person Raymond Chen; 28.12.2015
comment
@RaymondChen: я запускаю это программное обеспечение на многих компьютерах с Windows, и еще не видел ни одного, на котором оно не работает. Я понятия не имею, как поместить его туда самостоятельно - с API буфера обмена, упомянутым в другом ответе? Будет ли он совместим с Explorer? В любом случае, спасибо за подсказку. Являются ли другие два числа договорными? - person Violet Giraffe; 28.12.2015
comment
Ну хотя бы вызывать по каноническому имени, которое стабильно. Идентификаторы меню не являются договорными. - person Raymond Chen; 28.12.2015
comment
@RaymondChen: я думал об именах, но разве имена, которые я могу получить программно переводимыми именами, зависят от языка пользовательского интерфейса? - person Violet Giraffe; 28.12.2015
comment
Программные имена не переводятся. - person Raymond Chen; 28.12.2015
comment
@RaymondChen: спасибо. Я исправил проблему и обновил код — это оказалось проще, чем я ожидал! - person Violet Giraffe; 28.12.2015

// https://docs.microsoft.com/ja-jp/windows/desktop/dataxchg/standard-clipboard-formats
const char* wichStandardClipboardFormatsIsAvailable()
{
    // Standard Clipboard Formats
    // CF_BITMAP            : 2
    // CF_DIB               : 8
    // CF_DIBV5             :17
    // CF_DIF               : 5
    // CF_DSPBITMAP         :0x0082
    // CF_DSPENHMETAFILE    :0x008E
    // CF_DSPMETAFILEPICT   :0x0082
    // CF_DSPTEXT           :0x0081
    // CF_ENHMETAFILE       :14
    // CF_GDIOBJFIRST       :0x0300
    // CF_GDIOBJLAST        :0x03FF
    // CF_HDROP             :15
    // CF_LOCALE            :16
    // CF_METAFILEPICT      :3
    // CF_OEMTEXT           :7
    // CF_OWNERDISPLAY      :0x0080
    // CF_PALETTE           :9
    // CF_PENDATA           :10
    // CF_PRIVATEFIRST      :0x0200
    // CF_PRIVATELAST       :0x02FF
    // CF_RIFF              :11
    // CF_SYLK              :4
    // CF_TEXT              :1
    // CF_TIFF              :6
    // CF_UNICODETEXT       :13
    // CF_PRIVATELAST       :0x02FF
    // CF_WAVE              :12

    if ( IsClipboardFormatAvailable(CF_BITMAP) ) {
        return "CF_BITMAP";
    }
    if ( IsClipboardFormatAvailable(CF_DIB) ) {
        return "CF_DIB";
    }
    if ( IsClipboardFormatAvailable(CF_DIBV5) ) {
        return "CF_DIBV5";
    }
    if ( IsClipboardFormatAvailable(CF_DIF) ) {
        return "CF_DIF";
    }
    if ( IsClipboardFormatAvailable(CF_DSPBITMAP) ) {
        return "CF_DSPBITMAP";
    }
    if ( IsClipboardFormatAvailable(CF_DSPENHMETAFILE) ) {
        return "CF_DSPENHMETAFILE";
    }
    if ( IsClipboardFormatAvailable(CF_DSPMETAFILEPICT) ) {
        return "CF_DSPMETAFILEPICT";
    }
    if ( IsClipboardFormatAvailable(CF_HDROP) ) {
        return "CF_HDROP";
    }
    if ( IsClipboardFormatAvailable(CF_GDIOBJFIRST) ) {
        return "CF_GDIOBJFIRST";
    }
    if ( IsClipboardFormatAvailable(CF_GDIOBJLAST) ) {
        return "CF_GDIOBJLAST";
    }
    if ( IsClipboardFormatAvailable(CF_HDROP) ) {
        return "CF_HDROP";
    }
    if ( IsClipboardFormatAvailable(CF_LOCALE) ) {
        return "CF_LOCALE";
    }
    if ( IsClipboardFormatAvailable(CF_METAFILEPICT) ) {
        return "CF_METAFILEPICT";
    }
    if ( IsClipboardFormatAvailable(CF_OEMTEXT) ) {
        return "CF_OEMTEXT";
    }
    if ( IsClipboardFormatAvailable(CF_OWNERDISPLAY) ) {
        return "CF_OWNERDISPLAY";
    }
    if ( IsClipboardFormatAvailable(CF_PALETTE) ) {
        return "CF_PALETTE";
    }
    if ( IsClipboardFormatAvailable(CF_RIFF) ) {
        return "CF_RIFF";
    }
    if ( IsClipboardFormatAvailable(CF_BITMAP) ) {
        return "CF_SYLK";
    }
    if ( IsClipboardFormatAvailable(CF_BITMAP) ) {
        return "CF_TEXT";
    }
    if ( IsClipboardFormatAvailable(CF_BITMAP) ) {
        return "CF_UNICODETEXT";
    }
    if ( IsClipboardFormatAvailable(CF_BITMAP) ) {
        return "CF_PRIVATELAST";
    }
    if ( IsClipboardFormatAvailable(CF_BITMAP) ) {
        return "CF_WAVE";
    }

    return "CF_NOT_STANDARD";
}

https://github.com/WaitrudWeber/source_zip/blob/master/winmain-20190111.zip

  1. выполнить winmain_001.exe.
  2. скопируйте файл в проводник.
  3. нажмите ctl, а затем v
  4. вы могли видеть CF_HDROP

вы видите функцию: wichStandardClipboardFormatsIsAvailable в winmain_001.cpp и https://docs.microsoft.com/ja-jp/windows/desktop/dataxchg/standard-clipboard-formats

однажды я ввел вас в заблуждение, и мне очень жаль всех.

person Waitrud_Weber    schedule 11.01.2019