问题
I want to write a fast disk usage detect program, and found that FileSystemObject
is the fastest way to do this. And FileSystemObject
is in COM -> Microsoft Scripting Runtime
.
All the code is simple, and I parsed here.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DiskUsage
{
class Program
{
const string FolderPath = @"C:\Windows\System32";
static void Main(string[] args)
{
var startTime = DateTime.Now;
Scripting.FileSystemObject fso = new Scripting.FileSystemObject();
Scripting.Folder folder = fso.GetFolder(FolderPath);
Int64 dirSize = (Int64)folder.Size;
TimeSpan span = DateTime.Now.Subtract(startTime);
System.Console.WriteLine("{1} size: {0}", dirSize, FolderPath);
System.Console.WriteLine("use time: {0}", span);
System.Console.ReadKey();
}
}
}
And I setup the app.manifest
to
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
When I test my program, Security exception come at this line
Int64 dirSize = (Int64)folder.Size;
The Exception Info( I translate manually, sorry for my poor English. ) is
Unhandled exception type “System.Security.SecurityException” occurred in DiskUsage.exe
Other message: exception from HRESULT:0x800A0046 (CTL_E_PERMISSIONDENIED)
If I change FolderPath
to @"D:\Codes"
. It works fine. So I think the security setting in manifest is not effect to COM -> Microsoft Scripting Runtime
. Anyone know how to fix this? Please help, thanks.
回答1:
There is magic happening when that Size
property is called. Internally it still traverses the full folder tree and it's files to determine the size of the folder. If your current identity, elevated or not, doesn't have permission to list the files in any subfolder you're out of luck, the call to Size
will fail.
I've instead re-implemented the folder traversal using the Directory class found in System.IO but added some logging and exception handling so it will tell you the size of the folder, at least for the files you've access to.
Your main method needs to have this change:
Int64 dirSize;
try {
dirSize = (Int64)folder.Size;
}
catch(SecurityException sec)
{
dirSize = FolderSize(FolderPath);
}
If you run into the exception we make a call to the c# implementation of FolderSize
but this time it will compensate for the Unauthorized exceptions.
static Int64 FolderSize(string path)
{
long sum =0;
try
{
// scan folders
foreach(var dir in Directory.EnumerateDirectories(path))
{
//recursive call
sum += FolderSize( dir);
}
}
catch(UnauthorizedAccessException unath)
{
Console.WriteLine("{0} for folder {1}", unath.Message, path);
}
try
{
// scan files
foreach (var file in Directory.EnumerateFiles(path))
{
sum += new FileInfo(file).Length;
}
}
catch(UnauthorizedAccessException filesec)
{
Console.WriteLine("{0} for file {1}", filesec.Message, path);
}
return sum;
}
来源:https://stackoverflow.com/questions/36661777/security-exception-while-use-filesystemobject-in-c-sharp