为了账号安全,请及时绑定邮箱和手机立即绑定

在C#中访问Process.MainModule.FileName时如何避免Win32异常?

/ 猿问

在C#中访问Process.MainModule.FileName时如何避免Win32异常?

HUH函数 2019-11-18 13:07:24

我开始了一个新项目,列出了所有正在运行的进程的完整路径。访问某些进程时,程序崩溃并抛出Win32Exception。描述说列出过程模块时发生错误。最初,我认为可能会出现此问题,因为我正在64位平台上运行它,因此我针对x86和AnyCPU类型的CPU重新编译了它。我遇到了同样的错误。


Process p = Process.GetProcessById(2011);

string s = proc_by_id.MainModule.FileName;

错误发生在第2行。空白字段显示发生错误的进程: 屏幕截图


有什么办法可以解决此错误消息?


查看完整描述

3 回答

?
料青山看我应如是

请在此处查看Jeff Mercado的答案。


我稍微修改了他的代码,以仅获取特定进程的文件路径:


string s = GetMainModuleFilepath(2011);


private string GetMainModuleFilepath(int processId)

{

    string wmiQueryString = "SELECT ProcessId, ExecutablePath FROM Win32_Process WHERE ProcessId = " + processId;

    using (var searcher = new ManagementObjectSearcher(wmiQueryString))

    {

        using (var results = searcher.Get())

        {

            ManagementObject mo = results.Cast<ManagementObject>().FirstOrDefault();

            if (mo != null)

            {

                return (string)mo["ExecutablePath"];

            }

        }

    }

    return null;

}


查看完整回答
反对 回复 2019-11-18
?
慕慕0277861

如果要摆脱Win32Exception并获得最佳性能,请执行以下操作:


我们将使用Win32 API获取进程文件名

我们将实现一个缓存(仅供说明)

首先,您需要导入Win32 API


[DllImport("kernel32.dll")]

public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, int processId);


[DllImport("psapi.dll")]

static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, [In] [MarshalAs(UnmanagedType.U4)] int nSize);


[DllImport("kernel32.dll", SetLastError = true)]

[return: MarshalAs(UnmanagedType.Bool)]

static extern bool CloseHandle(IntPtr hObject);

其次,让我们编写返回进程文件名的函数。


[MethodImpl(MethodImplOptions.AggressiveInlining)]

public static string GetProcessName(int pid)

{

      var processHandle = OpenProcess(0x0400 | 0x0010, false, pid);


      if (processHandle == IntPtr.Zero)

      {

          return null;

      }


      const int lengthSb = 4000;


      var sb = new StringBuilder(lengthSb);


      string result = null;


      if (GetModuleFileNameEx(processHandle, IntPtr.Zero, sb, lengthSb) > 0)

      {

          result = Path.GetFileName(sb.ToString());

      }


      CloseHandle(processHandle);


      return result;

}

最后,让我们实现一个缓存,这样我们就不必经常调用此函数。创建一个具有属性(1)进程名称(2)创建时间的类ProcessCacheItem。添加一个const ItemLifetime,并将其设置为60秒。创建一个字典,其中的键-进程PID和值是ProcessCacheItem的对象实例。当您要获取进程名称时,请首先签入缓存。如果缓存中的项目已过期,请将其删除并添加刷新的项目。


查看完整回答
反对 回复 2019-11-18
?
互换的青春

当您尝试访问该MainModule属性时,将引发异常。该属性的文档未列出Win32Exception可能的例外,但是查看该属性的IL显然可以发现,访问它可能会引发此异常。通常,如果您尝试执行操作系统中不可能或不允许的操作,它将抛出此异常。


Win32Exception具有该属性,NativeErrorCode并且还Message可以解释问题所在。您应该使用该信息来解决问题。NativeErrorCode是Win32错误代码。我们可以整日猜测问题出在哪里,但是真正解决这个问题的唯一方法是检查错误代码。


但是要继续猜测,这些异常的来源之一是从32位进程访问64位进程。这样做会引发Win32Exception以下消息:


32位进程无法访问64位进程的模块。


您可以通过评估获得过程的位数Environment.Is64BitProcess。


即使以64位进程运行,也永远不允许您访问MainModule进程4(系统)或进程0(系统空闲进程)。这将引发Win32Exception以下消息:


无法枚举过程模块。


如果您遇到的问题是要在任务管理器中创建类似于进程列表的进程列表,则必须以特殊方式处理进程0和4,并给它们指定特定的名称(就像任务管理器一样)。请注意,在Windows的旧版本上,系统进程的ID为8。


查看完整回答
反对 回复 2019-11-18

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信