简体   繁体   English

C# WPF - 将远程文件拖放到 Windows Explorer

[英]C# WPF - DragDrop a remote file to Windows Explorer

I am working on a WPF application which shows a list of files stored on a remote server (just like dropbox).我正在开发一个 WPF 应用程序,该应用程序显示存储在远程服务器上的文件列表(就像保管箱一样)。 I want users to drag and drop them onto desktop or any folder.我希望用户将它们拖放到桌面或任何文件夹上。 There are many questions posted related to this but none of them really give a complete solution.发布了许多与此相关的问题,但没有一个真正给出完整的解决方案。

Here is the complete code I am using https://github.com/dotriz/VirtualDragDrop/这是我使用的完整代码https://github.com/dotriz/VirtualDragDrop/

截屏

This is a very simple task if file is stored on local system, but here file is on a remote server and need to be downloaded first.如果文件存储在本地系统上,这是一个非常简单的任务,但这里的文件在远程服务器上,需要先下载。

The only article related to this, is 13 years old posted here https://dlaa.me/blog/post/9923072 .与此相关的唯一一篇文章是 13 岁发布在这里https://dlaa.me/blog/post/9923072 It has few issues too, like它也有一些问题,比如

  • When we drag it on Windows explorer it gives error in DEBUG mode but works fine when we run exe directly.当我们将它拖到 Windows 资源管理器上时,它在调试模式下会出错,但当我们直接运行 exe 时工作正常。 What could be issue?可能是什么问题?

Invalid FORMATETC structure (Exception from HRESULT: 0x80040064 (DV_E_FORMATETC) FORMATETC 结构无效(HRESULT 异常:0x80040064 (DV_E_FORMATETC)

  • If we drag the file to an application like Slack, it hangs while file is downloading.如果我们将文件拖到 Slack 之类的应用程序中,它会在文件下载时挂起。 But works fine (if we run exe directly) when file is dropped on to Windows Explorer.但是当文件被放到 Windows Explorer 时工作正常(如果我们直接运行 exe)。

Here is the code used on MouseDown event of a label.这是用于 label 的 MouseDown 事件的代码。 It uses VirtualFileDataObject class from the link given above它使用上面给出的链接中的VirtualFileDataObject class

private void VirtualFile2_MouseButtonDown(object sender, MouseButtonEventArgs e)
{
    var virtualFileDataObject = new VirtualFileDataObject();

    virtualFileDataObject.SetData(new VirtualFileDataObject.FileDescriptor[]
    {
        new VirtualFileDataObject.FileDescriptor
        {
            Name = "test.zip",
            ChangeTimeUtc = DateTime.Now.AddDays(-1),
            StreamContents = stream =>
                {
                    using(var webClient = new WebClient())
                    {
                        var data = webClient.DownloadData("https://somesite.com/test.zip");
                        stream.Write(data, 0, data.Length);
                    }

                }
        },
    });

    DoDragDropOrClipboardSetDataObject(e.ChangedButton, VirtualFile2, virtualFileDataObject, DragDropEffects.Copy);
}

private static void DoDragDropOrClipboardSetDataObject(MouseButton button, DependencyObject dragSource, VirtualFileDataObject virtualFileDataObject, DragDropEffects allowedEffects)
{
    try
    {
        VirtualFileDataObject.DoDragDrop(dragSource, virtualFileDataObject, allowedEffects);
    }
    catch (COMException)
    {
        // Failure; no way to recover
    }
}

I can successfully use the provided reproduction program.我可以成功使用提供的复制程序。 It works at least on Windows 10, 11, x86 x64 in Release and Debug configuration, when ran without debugging it .它至少适用于 Windows 10、11、x86 x64 在发布和调试配置中,在没有调试的情况下运行。

DV_E_FORMATETC (0x80040064 ) is just a standard error code that means the data object doesn't support the clipboard format that's requested. DV_E_FORMATETC (0x80040064) 只是一个标准错误代码,表示数据 object 不支持所请求的剪贴板格式。 This error is common in copy/paste, drag&drop and clipboard operations.此错误在复制/粘贴、拖放和剪贴板操作中很常见。

What doesn't work at all is:根本不起作用的是:

  • Putting a breakpoint in the Drag & Drop handling code, for example in void System.Runtime.InteropServices.ComTypes.IDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium) while running in Debug mode.在调试模式下运行时,在拖放处理代码中放置断点,例如在void System.Runtime.InteropServices.ComTypes.IDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium)中。
  • Raising an exception in the Drag & Drop handling code when running in Debug mode.在调试模式下运行时,在拖放处理代码中引发异常。

I don't think you can debug a .NET program (with today tools) with breakpoints or exceptions being throw when in a DoDragDrop function call.我不认为您可以调试 .NET 程序(使用今天的工具),在DoDragDrop function调用中抛出断点或异常。

DoDragDrop is a big modal loop that eats most messages sent to a window. DoDragDrop是一个大的模态循环,它吃掉发送到 window 的大多数消息。 Unfortunately the .NET debugger facility or exception handler (in clr.dll) seems to also wait on this loop for some reason.不幸的是,.NET 调试器工具或异常处理程序(在 clr.dll 中)似乎也出于某种原因等待此循环。 So, hitting a breakpoint or handling an exception creates a hang in the program itself (and in the debugger too) that you can only break the dead lock by killing the debugged process the hard way ( taskkill /im myprocess.exe /f command line for example).因此,打断点或处理异常会在程序本身(以及调试器)中创建一个挂起,您只能通过硬方式杀死被调试的进程来打破死锁( taskkill /im myprocess.exe /f命令行例如)。

So my recommendation is to:所以我的建议是:

  • avoid putting breakpoints in these portions of code避免在这些代码部分放置断点

  • wrap these functions in try/catch block and use some non-intrusive trace mechanism, something like this:将这些函数包装在try/catch块中,并使用一些非侵入式跟踪机制,如下所示:

     void System.Runtime.InteropServices.ComTypes.IDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium) { try {.... } catch(Exception ex) { Trace.WriteLine("GetData Error: " + ex); throw; // rethrow as is } }

EDIT: This answer is wrong编辑:这个答案是错误的

I can explain why the UI hangs and how to solve it.我可以解释为什么 UI 挂起以及如何解决它。 There are two IO operations inside VirtualFile2_MouseButtonDown which you perform in a blocking way. VirtualFile2_MouseButtonDown 中有两个 IO 操作,您以阻塞方式执行。 This obviously blocks the UI thread until both operations finish.这显然会阻塞 UI 线程,直到两个操作都完成。

  1. Change the signature to private async void VirtualFile2_MouseButtonDown将签名更改为private async void VirtualFile2_MouseButtonDown
  2. Use await webClient.DownloadDataAsync使用 await webClient.DownloadDataAsync
  3. Use await stream.WriteAsync使用等待 stream.WriteAsync

This way, VirtualFile2_MouseButtonDown will return on the first IO operation and continuation tasks will be scheduled on the UI thread when the async IO operation is ready.这样,VirtualFile2_MouseButtonDown 将在第一个 IO 操作时返回,并且当异步 IO 操作准备好时,将在 UI 线程上安排继续任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM