【问题标题】:Path.GetDirectoryName produces Win32Exception 'Access is denied'Path.GetDirectoryName 产生 Win32Exception '访问被拒绝'
【发布时间】:2019-11-27 02:31:44
【问题描述】:

您好我目前正在尝试获取正在运行的进程的目录并不断获取错误 System.ComponentModel.Win32Exception:“访问被拒绝” 我在下面使用的以下代码,我目前正在使用 try catch 来防止此错误,但是 try catch 被证明是一种需要宝贵处理时间的缓慢方法,我在这里询问是否有方法来检测是否存在进程的数据可通过布尔值访问,以防止需要 try catch 语句,从而减少处理时间。

string dir = System.IO.Path.GetDirectoryName(process.MainModule.FileName)

【问题讨论】:

  • this thread 回答你的问题了吗?
  • 这个文件在哪个目录下?
  • 可能会很慢,但是你需要多久获取一次目录名呢?您是否担心程序在执行时可能会潜伏到不同的目录?它看起来是一个使用单例并将结果缓存在第一次访问时static 的好地方。状态可以保存在另一个static 中,您可以及时返回这两个值。
  • 我几乎一直在获取目录名,程序的目的是查看是否有任何被列入黑名单的进程在运行,根据进程的路径等特定标准决定,然后杀死所有被列入黑名单的进程。我正在使用这个 atm 来阻止诸如 steamapps 文件夹之类的目录,几乎禁止所有 Steam 游戏。为了缓存数据,我会将进程的副本存储在列表中还是?
  • 抱歉,我没发现您正在查看其他进程。即便如此,我还是会缓存IdStartTime 以及您需要的任何其他信息。 Id/StartTime 对应该是唯一的。 (ID 被重复使用,但不太可能如此简单地使用并如此快速地重复使用,以至于 StartTime 不会改变。)Hashtable 将是一个合适的集合,keyId/ StartTime 对和 value 是需要的任何其他数据。不要忘记删除旧进程。

标签: c# process try-catch


【解决方案1】:

如果您查看documentation for the Process.MainModule property,您会发现如果 32 位进程尝试访问 64 位进程,它会抛出 Win32Exception。您可以通过查看Win32Exception.ErrorCode(在这种情况下我假设为0x00000005)和Win32Exception.Message 属性来检查是否是这种情况。您可以通过评估Environment.Is64BitProcess 来检索您的进程的位数。

即使作为 64 位进程运行,您的程序也不会被允许访问系统进程 (4) 的 MainModuleSystem Idle Process (0)。这将抛出一个带有消息的Win32Exception

无法枚举进程模块。

您可以使用Process.Id 来检查 0 或 4。

或者,Win32 API 允许您使用 LimitedQueryInformation 标志查询每个进程,这意味着您可以检查路径而不会收到异常。不幸的是,.NET 基类库没有公开这个标志,所以你需要 P/Invoke 来做到这一点。 以下 C# 控制台程序永远不会触发异常(在我的本地计算机上运行时)。如果它以本地管理员权限运行,它将返回除进程 0 和进程 4 之外的所有路径名。如果它以普通用户身份运行,它只列出它有权访问的那些进程的路径名,这是可以理解的。

using System;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace NewCmd
{
    class Program
    {
        [Flags]
        private enum ProcessAccessFlags : uint
        {
            QueryLimitedInformation = 0x00001000
        }

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool QueryFullProcessImageName
            (
            [In] IntPtr hProcess, 
            [In] int dwFlags, 
            [Out] StringBuilder lpExeName, 
            ref int lpdwSize
            );

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr OpenProcess
            (
            ProcessAccessFlags processAccess, 
            bool bInheritHandle, 
            int processId
            );

        static void Main(string[] args)
        {
            foreach (Process p in Process.GetProcesses())
            {
                Console.WriteLine(String.Format("Id: {0} Name: {1}", p.Id, p.ProcessName));
                Console.WriteLine(String.Format("Path: {0}", GetProcessFilename(p)));
            }
            Console.ReadLine();
        }

        static String GetProcessFilename(Process p)
        {
            int capacity = 2000;
            StringBuilder builder = new StringBuilder(capacity);
            IntPtr ptr = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, p.Id);
            if (QueryFullProcessImageName(ptr, 0, builder, ref capacity))
            {
                return builder.ToString();
            }
            else
            {
                return "[Missing]";
            }
        }
    }
}

【讨论】:

  • 谢谢,有没有办法识别它是否是一个独立于try catch的系统进程以避免异常?
  • @SebastianSouthwell,我已编辑我的答案以回复您的评论。
  • 谢谢你,我实施了你的调整,它就像一个魅力,现在处理时间从 3 秒减少到 0.15 秒,这低于我的需要,非常感谢。
猜你喜欢
  • 2021-09-04
  • 1970-01-01
  • 2014-10-04
  • 2017-09-15
  • 2016-08-15
  • 1970-01-01
  • 1970-01-01
  • 2019-08-30
  • 1970-01-01
相关资源
最近更新 更多