简体   繁体   English

Directory.EnumerateFiles和File.Exists忽略本机DLL文件

[英]Directory.EnumerateFiles and File.Exists are ignoring native DLL files

Environment: C#, .NET 4.0, and mixed mode. 环境:C#,.NET 4.0和混合模式。

I have a complex application with several third-party dependencies. 我有一个复杂的应用程序与几个第三方依赖项。 When we received some reports of the application crashing we added some sanity checks to ensure that all the dependencies exist by traversing the Assembly dependencies. 当我们收到一些关于应用程序崩溃的报告时,我们添加了一些健全性检查,以确保通过遍历程序集依赖关系来存在所有依赖项。 Unfortunately, this does not check for the existence of the native DLL files our application uses. 不幸的是,这不会检查我们的应用程序使用的本机DLL文件是否存在。 Our intended solution is to iterate through all the DLL names and make sure there is at least a file with that name as a sanity check. 我们的预期解决方案是遍历所有DLL名称,并确保至少有一个具有该名称的文件作为完整性检查。

The Problem 问题

Both Directory.EnumerateFiles() and File.Exists() cannot see these native DLLs either. Directory.EnumerateFiles()和File.Exists()都无法看到这些本机DLL。 Code to reproduce this problem is as simple as the textbook "how to list files": 重现此问题的代码就像教科书“如何列出文件”一样简单:

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

Staring in the directory I was listing the files on, I could see the files I wanted to detect. 盯着我列出文件的目录,我可以看到我想要检测的文件。 They are not flagged as system files in any way. 它们不会以任何方式标记为系统文件。 Yet, whether I had the filter text or not, only .NET DLL files were listed. 但是,无论我是否有过滤文本,都只列出了.NET DLL文件。 I thought to rewrite the section of code more directly and frustratingly got the same results: 我想更直接地重写代码部分并且令人沮丧地得到了相同的结果:

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

I got the same exact results. 我得到了完全相同的结果。 All the native DLL files seemed to be invisible to .NET. 所有本机DLL文件似乎都是.NET不可见的。

Question

What causes this? 是什么导致这个? And more importantly, how can I detect the native DLL files exist if I can't even see them in the file system? 更重要的是,如果我甚至无法在文件系统中看到它们,如何检测本机DLL文件?

Are you sure your working directory is correct? 你确定你的工作目录是否正确? Otherwise Environment.CurrentDirectory will not point to what you expect. 否则, Environment.CurrentDirectory将不会指向您的期望。 If the DLL files are in the same directory as your executing code then you could instead do: 如果DLL文件与执行代码位于同一目录中,那么您可以改为:

Assembly.GetExecutingAssembly().Location
  • Make up a name for your own DLL, eg MySuperNiftyLibrary.dll. 为您自己的DLL组成一个名称,例如MySuperNiftyLibrary.dll。 It can be just a renamed text file. 它可以只是一个重命名的文本文件。 Put it in the folder you're looking at. 把它放在你正在看的文件夹中。 Run the code again. 再次运行代码。 See if that name is listed. 查看是否列出了该名称。 If that doesn't convince you, create a small .NET class library project with a distinctive name, and put that in the directory as well. 如果这不能说服您,请创建一个具有独特名称的小型.NET类库项目,并将其放在目录中。

    There's no reason Directory.EnumerateFiles would filter on .NET DLLs as opposed to other types of DLLs, so you can't possibly be looking at the right directory. Directory.EnumerateFiles没有理由过滤.NET DLL而不是其他类型的DLL,因此您无法查看正确的目录。

  • But if you are, then consider whether the DLLs you're looking for are in the top-level directory or a subdirectory. 但如果您是,那么请考虑您要查找的DLL是在顶级目录还是子目录中。 By default, EnumerateFiles only lists files in the top-level directory . 默认情况下, EnumerateFiles仅列出顶级目录中的文件 To list all files in all subdirectories, you need to use this overload of EnumerateFiles : 要列出所有子目录中的所有文件,您需要使用EnumerateFiles这个重载:

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

Then use shell, something like this should work: 然后使用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;
                }
            }

UPDATE: if you intend to use this on both XP and newer OSes, you need to reference Shell32.dll (Microsoft Shell controls and automation) on XP and compile there once, so that such dll is copied to your project. 更新:如果您打算在XP和更新的操作系统上使用它,您需要在XP上引用Shell32.dll(Microsoft Shell控件和自动化)并在那里编译一次,以便将这样的dll复制到您的项目中。 Because dll from Vista or 7 won't work on XP, and opposite it does. 因为来自Vista或7的dll不适用于XP,与之相反。 This is simpler approach that relies on Shell scripting. 这是一种更简单的方法,它依赖于Shell脚本。 Otherwise you can interop directly with Shell API, but it is more complicated... 否则你可以直接与Shell API互操作,但它更复杂......

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

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