在Windows资源管理器中获取拖放文件的文件路径

3

拖放是许多网站(包括本站)中讨论的一个热门话题,我也找到了一些不错的问题,但对于这种情况没有答案。

我有一个listView,其中有一些元素,我需要将它们放置在Windows资源管理器中。放置后,我只需要文件路径,不需要复制任何内容,只需路径即可。

类似的问题(以及它们为什么不适用于我):

我找到的唯一解决方案:

http://www.codeproject.com/Articles/23207/Drag-and-Drop-to-Windows-Folder-C

这个方法的确管用,但是非常“不实用”,它创建了一个文件监视器,创建一个虚拟文件,让DragDrop函数复制它,观察文件被创建的位置,最后删除它。在我的Windows8.1上测试结果导致资源管理器刷新不正确,我仍然可以看到该文件,直到我刷新屏幕(F5)。

这是唯一的方法吗?我还是不能相信我不能以更简单的方式实现这一点。

2个回答

2

先花一分钟考虑一下……如果你知道拖放,那么你就会知道拖动源负责将数据打包到正确的格式中,而拖放目标则负责以正确的格式检索数据。你的问题是,你的拖放目标不在你的WPF应用程序中,因此当数据被放下时,你几乎无法做任何事情。

一个更好的解决方案是实现自己的基本文件浏览器,然后作为你的应用程序的一部分,使用拖放操作访问文件路径会更简单。无论哪种方式,你都有很多工作要做。


你好,非常感谢您的回答 :) 我的应用程序已经有一个文件浏览器,但它在远程路径上,并且下载文件的过程已经实现,我需要目标路径来启动我的下载过程。我的程序从不同的路径生成下载和上传队列,所以我只需要目标路径就可以让所有这些工作正常运行 :) - HypeZ
我明白获取文件拖放时的文件路径没有可行的办法。我对此感兴趣是因为有以下问题:当使用移动(而非复制)从我的应用程序中拖放文件并且文件已经存在于目标目录中,我无法检测用户是否选择在Windows“替换文件对话框”中取消操作(http://miksovsky.blogs.com/flowstate/WindowsLiveWriter/image_thumb_1.png),如果无法取消操作,则该文件将会丢失,因为它应该被移动,而不是复制。或者,有没有方法可以检测到这一点? - salle55

1
  1. 当你从ListView中拖动任何项时,立即创建一个空的FileDrop项目。
  2. 由于在拖动过程中鼠标按钮始终按下,因此启动一个计时器,在释放按下的鼠标按钮时触发事件。
  3. 当按钮被释放时,获取鼠标所在窗口的窗口句柄。将该句柄与任何打开的Windows资源管理器窗口进行匹配。
  4. 如果找到了匹配的窗口,则获取该Windows资源管理器窗口的位置URL,并操作该Windows资源管理器窗口的可用URL以获取(UNC) Windows路径。

在设计模式下创建一个Windows表单,并添加一个名为lvFilesListView。将其AllowDrop属性设置为True。 然后向表单添加一个计时器并将其命名为dropTimer。将时间间隔设置为50。将Enabled设置为False。 在dropTimer的事件中,双击,使事件成为dropTimer_Tick

转到代码后面并粘贴以下代码。

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;

namespace test
{
    public partial class Form1 : Form
    {

        [DllImport("user32.dll")]
        static extern int GetForegroundWindow();

        [DllImport("user32.dll")]
        static extern short GetKeyState(VirtualKeyStates nVirtKey);


        enum VirtualKeyStates : int
        {
            VK_LBUTTON = 0x01,
            VK_RBUTTON = 0x02,
        }

        bool IsKeyPressed(VirtualKeyStates testKey)
        {
            bool keyPressed = false;
            short result = GetKeyState(testKey);
            switch (result)
            {
                case 0:
                    keyPressed = false;
                    break;
                case 1:
                    keyPressed = false;
                    break;
                default:
                    keyPressed = true;
                    break;
            }
            return keyPressed;
        }

        int GetActiveWindowHandle()
        {
            const int nChars = 256;
            int handle = 0;
            StringBuilder Buff = new StringBuilder(nChars);
            handle = GetForegroundWindow();
            if (GetWindowText(handle, Buff, nChars) > 0)
                return handle;
            else
                return 0;
        }

        private string GetWindowsExplorerPathFromWindowHandle(int handle)
        {
            // Add a project COM reference to Microsoft Internet Controls 1.1
            SHDocVw.ShellWindows shellWindows = new SHDocVw.ShellWindowsClass(); 
            string fileName;
            string path = "";
            foreach ( SHDocVw.InternetExplorer ie in shellWindows )
            {    
                fileName = Path.GetFileNameWithoutExtension(ie.FullName).ToLower();
                if (fileName.Equals("explorer") && ie.HWND == handle)
                {
                    path = ie.LocationURL;
                    path = path.ToLower();
                    path = path.Replace("file://", "");
                    if (path.StartsWith("/"))
                        path = path.Substring(1);
                    path = path.Replace("/", "\\");
                    if (!path.Contains(":")) // unc paths
                        path = "\\\\" + path;
                    break;
                }
            }
            return path; 
        }

        // Replace the created event from the designer with this event:
        //
        private void lvFiles_ItemDrag(object sender, ItemDragEventArgs e)
        {
            // fake drag and drop effect (start)
            string dataFormat = DataFormats.FileDrop;
            string[] data = new string[1];
            data[0] = "";
            DataObject dataObject = new DataObject(dataFormat, data);

            // catch mouse events
            if (IsKeyPressed(VirtualKeyStates.VK_LBUTTON))
                MouseButtonPressed = MouseButtons.Left;
            else if (IsKeyPressed(VirtualKeyStates.VK_RBUTTON))
                MouseButtonPressed = MouseButtons.Right;
            else
                MouseButtonPressed = MouseButtons.None;
            if (MouseButtonPressed == MouseButtons.Left || MouseButtonPressed == MouseButtons.Right) 
                this.dropTimer.Enabled = true;

            // fake drag and drop effect (launch)
            DoDragDrop(dataObject, DragDropEffects.Copy);
        }


        private void dropTimer_Tick(object sender, EventArgs e)
        {
            bool mouseButtonsReleased = false;
            if (MouseButtonPressed == MouseButtons.Left && !IsKeyPressed(VirtualKeyStates.VK_LBUTTON))
                mouseButtonsReleased = true;
            else if (MouseButtonPressed == MouseButtons.Right && !IsKeyPressed(VirtualKeyStates.VK_RBUTTON))
                mouseButtonsReleased = true;
            if (mouseButtonsReleased)
            {
                dropTimer.Enabled = false;
                int handle = GetActiveWindowHandle();
                string dropPath = GetWindowsExplorerPathFromWindowHandle(handle);

                MessageBox.Show(dropPath); // Here is where the Windows Explorer path is shown
            }
        }

    }
}

以某种方式填充您的 ListView,将任何 ListView 项拖动到 Windows Explorer 窗口中;放置路径将显示。


谢谢,但我找不到ExplorerHelper.GetActiveWindowHandle(); 我使用了这个方法,但是它不起作用,总是返回0: [DllImport("user32.dll", EntryPoint = "GetActiveWindow", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] static extern IntPtr GetActiveWindowHandle(); - HypeZ
我用 GetForegroundWindow() 成功解决了问题,但是这样做无法获取用户拖放文件的正确文件夹!GetActiveWindow() 不能解决这个问题,它是指调用线程正在使用的活动 Windows,而不是 explorer.exe。所以...ExplorerHelper 在这里可能很有用:D - HypeZ
抱歉,请再次从上面获取代码,我从我的ExplorerHelper类中添加了GetActiveWindow,并添加了GetForeGroundWindow()。我很好奇你现在是否能让它工作! - Marcel Pennock
谢谢你的帮助 :) 不幸的是,GetForegroundWindow()函数无法获取正确的拖放目标 :( 如果你在桌面上拖放,它会失败(返回0),如果你在文件夹上拖放,你也无法获取该文件夹路径。这是一个部分解决方案,很酷很方便但只是部分 :( 无论如何还是非常感谢你! - HypeZ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接