【问题标题】:Directory.EnumerateFiles and File.Exists are ignoring native DLL filesDirectory.EnumerateFiles 和 File.Exists 忽略本机 DLL 文件
【发布时间】:2012-02-09 19:25:00
【问题描述】:

环境:C#、.NET 4.0 和混合模式。

我有一个包含多个第三方依赖项的复杂应用程序。当我们收到一些应用程序崩溃的报告时,我们添加了一些健全性检查,以通过遍历 Assembly 依赖项来确保所有依赖项都存在。不幸的是,这不会检查我们的应用程序使用的本机 DLL 文件是否存在。我们预期的解决方案是遍历所有 DLL 名称,并确保至少有一个具有该名称的文件作为完整性检查。

问题

Directory.EnumerateFiles() 和 File.Exists() 也看不到这些原生 DLL。重现这个问题的代码就像教科书《如何列出文件》一样简单:

foreach(string file in
        Directory.EnumerateFiles(Environment.CurrentDirectory, "*.dll"))
{
    string entry = Path.GetFileName(file);
    if (! RequiredFiles.Contains(entry))
    {
        /* Do error handling */
    }
}

盯着我列出文件的目录,我可以看到我想要检测的文件。它们不会以任何方式标记为系统文件。然而,无论我是否有过滤器文本,都只列出了 .NET DLL 文件。我想更直接地重写这段代码,结果却是一样的沮丧:

foreach(string dependency in RequiredFiles)
{
    string fileName = Environment.CurrentDirectory + '\\' + dependency;
    if(! File.Exists(fileName))
    { /* do error handling */ }
}

我得到了完全相同的结果。 .NET 似乎看不到所有本机 DLL 文件。

问题

这是什么原因造成的?更重要的是,如果我什至在文件系统中都看不到原生 DLL 文件,如何检测它们是否存在?

【问题讨论】:

  • 你能在一个空白项目中重现这个吗?我严重怀疑原生 DLL 真的会像那样“不可见”。听起来好像发生了其他事情;错误的 CurrentDirectory、某种影子复制、64 位操作系统文件系统重定向上的 32 位进程等。ClickOnce 部署可能会忽略本机 DLL。类似的东西。

标签: c# .net c#-4.0


【解决方案1】:
  • 为你自己的 DLL 起一个名字,例如MySuperNiftyLibrary.dll。它可以只是一个重命名的文本文件。把它放在你正在查看的文件夹中。再次运行代码。查看是否列出了该名称。如果这不能说服您,请创建一个具有独特名称的小型 .NET 类库项目,并将其也放入目录中。

    与其他类型的 DLL 相比,Directory.EnumerateFiles 没有理由过滤 .NET DLL,因此您不可能查看正确的目录。

  • 但如果是,请考虑您要查找的 DLL 是在顶级目录中还是在子目录中。 默认情况下,EnumerateFiles 仅列出顶级目录中的文件。要列出所有子目录中的所有文件,你需要使用EnumerateFiles这个重载:

Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)

【讨论】:

  • 我现在不觉得自己像个白痴。经过我所有的检查和三重检查,我确信我在寻找正确的目录。直到您发布此答案后,我才发现我确实在查看一个几乎相同但不同的目录。唯一缺少的文件是本机 DLL...
【解决方案2】:

您确定您的工作目录正确吗?否则Environment.CurrentDirectory 不会指向您所期望的。如果 DLL 文件与您的执行代码位于同一目录中,那么您可以这样做:

Assembly.GetExecutingAssembly().Location

【讨论】:

  • 检查了路径,与我正在查看的路径相同。
【解决方案3】:

然后使用shell,这样的东西应该可以工作:

            Shell32.Shell shl = null;
            Shell32.Folder folder = null;
            try
            {
                shl = new Shell32.Shell();
                folder = shl.NameSpace(Environment.CurrentDirectory);
                foreach (Shell32.FolderItem file in folder.Items())
                {
                    if (!RequiredFiles.Contains(file.path))
                    {/* do error handling */}
                }
            }
            catch
            { }
            finally
            {
                if (folder != null)
                {
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(folder);
                    folder = null;
                }
                if (shl != null)
                {
                    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(shl);
                    shl = null;
                }
            }

更新:如果您打算在 XP 和较新的操作系统上使用它,您需要在 XP 上引用 Shell32.dll(Microsoft Shell 控件和自动化)并在那里编译一次,以便将此类 dll 复制到您的项目中。因为来自 Vista 或 7 的 dll 无法在 XP 上运行,反之亦然。这是一种更简单的方法,它依赖于 Shell 脚本。否则你可以直接和Shell API互操作,但是比较复杂……

【讨论】:

    猜你喜欢
    • 2013-05-02
    • 2011-03-17
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-17
    • 2015-10-11
    • 1970-01-01
    相关资源
    最近更新 更多