Reputation: 11463
Environment: C#, .NET 4.0, and mixed mode.
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. 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.
The Problem
Both Directory.EnumerateFiles() and File.Exists() cannot see these native DLLs either. 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. 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.
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?
Upvotes: 4
Views: 1640
Reputation: 3929
Are you sure your working directory is correct? Otherwise Environment.CurrentDirectory
will not point to what you expect. If the DLL files are in the same directory as your executing code then you could instead do:
Assembly.GetExecutingAssembly().Location
Upvotes: 2
Reputation: 210300
Make up a name for your own DLL, e.g. 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.
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.
But if you are, then consider whether the DLLs you're looking for are in the top-level directory or a subdirectory. By default, EnumerateFiles
only lists files in the top-level directory. To list all files in all subdirectories, you need to use this overload of EnumerateFiles
:
Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)
Upvotes: 2
Reputation: 9990
Then use shell, something like this should work:
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. Because dll from Vista or 7 won't work on XP, and opposite it does. This is simpler approach that relies on Shell scripting. Otherwise you can interop directly with Shell API, but it is more complicated...
Upvotes: 0