打开文件对话框在路径长度超过260个字符时返回空字符串(或根本不返回)

5
我正在编写一个程序,需要从系统的任何位置读取文件。该程序的某些用户路径超过了260个字符的限制。 OpenFileDialog 无法处理路径超过260个字符的文件。
我已经尝试使用 System.Windows.Forms.OpenFileDialogMicrosoft.Win32.OpenFileDialog。在前者的情况下,当我浏览并选择文件后,单击“打开”时,窗口不会关闭,程序也不会继续执行。在后者的情况下,单击“打开”时,窗口将关闭,但路径为空字符串。
我已更新了计算机上的注册表。我已编辑了应用程序清单文件。我想尝试在我的路径前面添加“//?/”字符串,但没有路径可以添加。
var dialog = new OpenFileDialog
{
  // initialize dialog
}

if (dialog.ShowDialog() == DialogResult.OK) // DialogResult.OK replaced with true if using Microsoft.Win32.OpenFileDialog
{
  // if when using System.Windows.Forms.OpenFileDialog, I will never get to this point
  // if using Microsoft.Win32.OpenFileDialog, I will get here but dialog.FileNames will be empty
}

如果我已经更新了注册表和应用清单,我希望上述代码在长路径和短路径方面可以正常工作。我怀疑这只是不受支持,但我所有的搜索都显示人们提供的解决方案要么不起作用,要么只适用于特定情况。


你的目标是哪个 .net framework?显然,如果是4.6.2及以上版本,这不应该是个问题。 - Palle Due
我正在针对框架4.7.2。 - cdicker
1个回答

1
System.Windows.Forms.OpenFileDialog的情况下,我通过将ValidateNames设置为false来使其正常工作,以克服当用户单击“打开”时ShowDialog()没有返回的问题。
    System.Windows.Forms.OpenFileDialog openFileDialog_WindowsForms = new System.Windows.Forms.OpenFileDialog
    {
        CheckFileExists = true,
        CheckPathExists = true,
        ValidateNames = false // this will allow paths over 260 characters
    };

    if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        string[] fileNames = openFileDialog_WindowsForms.getFileNames_WindowsForms();

        foreach (var file in fileNames)
        {
            try
            {
                Console.WriteLine(File.ReadAllText(file));
            }
            catch (Exception ex)
            {
                Console.WriteLine("Couldn't open file from Windows.Forms.OpenFileDialog:" + ex.Message);
            }
        }

    };

使用反射来解决无法从 FilePathFilePaths 属性访问的路径。结果发现这些路径存在于一个私有属性中,我可以使用反射访问它们。
public static class OpenFileDialogLongPathExtension
{
    public static string[] getFileNames_WindowsForms(this System.Windows.Forms.OpenFileDialog dialog)
    {
        var fileNamesProperty = dialog.GetType().GetProperty("FileNamesInternal", BindingFlags.NonPublic | BindingFlags.Instance);
        var fileNamesFromProperty = (string[])fileNamesProperty?.GetValue(dialog);
        return fileNamesFromProperty;
    }
}

我曾尝试对于Microsoft.Win32.OpenFileDialog做类似的操作,但是私有属性似乎仍然无效,所以相同的解决方案不会起作用。无论如何,我希望这能帮助其他人。此示例使用.NET Framework 4.8创建。

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