【问题标题】:Get x64 process mainmodule location from an x86 application?从 x86 应用程序获取 x64 进程主模块位置?
【发布时间】:2014-09-29 23:49:14
【问题描述】:

我正在尝试从Process.GetProcesses() 方法获取操作系统上正在运行的进程的所有文件路径,它在 x64 .NET 应用程序下完美运行,但如果我尝试从一个 x86 .NET 应用程序,因为 Process.MainModule.FileName 属性引发了一个 Win32 异常(用我的本地语言),说如下:A 32 bit process can't access to 64 bit process modules,好的,我理解这个问题,但是我该如何解决呢? .

引发此异常的代码示例(在 x86 .NET 解决方案下,而不是 AnyCPU 下):

Dim path As String = 
    Process.GetProcessesByName("Myx64Process").First.MainModule.FileName

我看到了另一种使用 WMI 查询获取 64 位进程文件路径的方法,但这种方法似乎不是更有效的方法,我正在寻找更好的方法,也许是通过 .NET 框架类库而不弄乱 WMI 接口,如果可能的话。

【问题讨论】:

  • 能否提供重新创建异常的示例代码?
  • 只要使用 WMI,就可以了。为什么这似乎不是一种有效的方法? .NET 的Process 中没有获取进程可执行路径的 API。您可以使用 P/Invoke 解决问题,但这肯定比使用 WMI 更糟糕。
  • 哦,由于赏金,无法关闭此问题,但它是重复的 - stackoverflow.com/questions/5497064/…
  • use WMI,it works fine. Why doesn't it seem like an efficient way? 老实说,您是否进行了简单的性能测试来比较或确定您在说什么?像这样运行 WMI 查询:SELECT ExecutablePath FROM Win32_Process Where Name = '{0}.exe' 迭代所有正在运行的进程(比如只有 30-35 个)大约需要 3-5 秒才能仅获取 1 个进程的信息,同时使用 Process 类迭代所有进程到做同样的事情需要不到 100 毫秒。当然,您可以注意到一个很大的不同,WMI 的使用对于更新进程列表效率不高。
  • 另外,我不知道你说这篇文章是重复的,因为它不是,我在你链接的那个网址中没有看到任何新内容以及关于 x64 的任何内容与我的问题有关。感谢您的评论

标签: .net vb.net winforms process


【解决方案1】:

为每个进程查询 WMI 会非常缓慢。您应该做的是返回 all 类,然后按进程 ID 进行“托管比较”。在下面的示例中,我读取了每个类的 all 属性并将每个类映射到其对应的Process。执行时间:165.53 ms。请注意,这包括Process.GetProcesses()。不,我没有超级计算机。

(注意:需要添加对System.Management.dll的引用)

Imports System.Management 

Public Class Win32Process

    Public Property Caption() As String
    Public Property CommandLine() As String
    Public Property CreationClassName() As String
    Public Property CreationDate() As DateTime?
    Public Property CSCreationClassName() As String
    Public Property CSName() As String
    Public Property Description() As String
    Public Property ExecutablePath() As String
    Public Property ExecutionState() As UInt16?
    Public Property Handle() As String
    Public Property HandleCount() As UInt32?
    Public Property InstallDate() As DateTime?
    Public Property KernelModeTime() As UInt64?
    Public Property MaximumWorkingSetSize() As UInt32?
    Public Property MinimumWorkingSetSize() As UInt32?
    Public Property Name() As String
    Public Property OSCreationClassName() As String
    Public Property OSName() As String
    Public Property OtherOperationCount() As UInt64?
    Public Property OtherTransferCount() As UInt64?
    Public Property PageFaults() As UInt32?
    Public Property PageFileUsage() As UInt32?
    Public Property ParentProcessId() As UInt32?
    Public Property PeakPageFileUsage() As UInt32?
    Public Property PeakVirtualSize() As UInt64?
    Public Property PeakWorkingSetSize() As UInt32?
    Public Property Priority() As UInt32?
    Public Property PrivatePageCount() As UInt64?
    Public Property ProcessId() As UInt32?
    Public Property QuotaNonPagedPoolUsage() As UInt32?
    Public Property QuotaPagedPoolUsage() As UInt32?
    Public Property QuotaPeakNonPagedPoolUsage() As UInt32?
    Public Property QuotaPeakPagedPoolUsage() As UInt32?
    Public Property ReadOperationCount() As UInt64?
    Public Property ReadTransferCount() As UInt64?
    Public Property SessionId() As UInt32?
    Public Property Status() As String
    Public Property TerminationDate() As DateTime?
    Public Property ThreadCount() As UInt32?
    Public Property UserModeTime() As UInt64?
    Public Property VirtualSize() As UInt64?
    Public Property WindowsVersion() As String
    Public Property WorkingSetSize() As UInt64?
    Public Property WriteOperationCount() As UInt64?
    Public Property WriteTransferCount() As UInt64?

    Public Shared Function GetProcesses() As Win32Process()
        Using searcher As New ManagementObjectSearcher("select * from Win32_Process")
            Return (
                From
                    item As ManagementObject
                In
                    searcher.[Get]().Cast(Of ManagementObject)()
                Select New Win32Process() With {
                    .Caption = CType(item.Properties("Caption").Value, String),
                    .CommandLine = CType(item.Properties("CommandLine").Value, String),
                    .CreationClassName = CType(item.Properties("CreationClassName").Value, String),
                    .CreationDate = ManagementUtils.ToDateTime(item.Properties("CreationDate").Value),
                    .CSCreationClassName = CType(item.Properties("CSCreationClassName").Value, String),
                    .CSName = CType(item.Properties("CSName").Value, String),
                    .Description = CType(item.Properties("Description").Value, String),
                    .ExecutablePath = CType(item.Properties("ExecutablePath").Value, String),
                    .ExecutionState = CType(item.Properties("ExecutionState").Value, UInt16?),
                    .Handle = CType(item.Properties("Handle").Value, String),
                    .HandleCount = CType(item.Properties("HandleCount").Value, UInt32?),
                    .InstallDate = ManagementUtils.ToDateTime(item.Properties("InstallDate").Value),
                    .KernelModeTime = CType(item.Properties("KernelModeTime").Value, UInt64?),
                    .MaximumWorkingSetSize = CType(item.Properties("MaximumWorkingSetSize").Value, UInt32?),
                    .MinimumWorkingSetSize = CType(item.Properties("MinimumWorkingSetSize").Value, UInt32?),
                    .Name = CType(item.Properties("Name").Value, String),
                    .OSCreationClassName = CType(item.Properties("OSCreationClassName").Value, String),
                    .OSName = CType(item.Properties("OSName").Value, String),
                    .OtherOperationCount = CType(item.Properties("OtherOperationCount").Value, UInt64?),
                    .OtherTransferCount = CType(item.Properties("OtherTransferCount").Value, UInt64?),
                    .PageFaults = CType(item.Properties("PageFaults").Value, UInt32?),
                    .PageFileUsage = CType(item.Properties("PageFileUsage").Value, UInt32?),
                    .ParentProcessId = CType(item.Properties("ParentProcessId").Value, UInt32?),
                    .PeakPageFileUsage = CType(item.Properties("PeakPageFileUsage").Value, UInt32?),
                    .PeakVirtualSize = CType(item.Properties("PeakVirtualSize").Value, UInt64?),
                    .PeakWorkingSetSize = CType(item.Properties("PeakWorkingSetSize").Value, UInt32?),
                    .Priority = CType(item.Properties("Priority").Value, UInt32?),
                    .PrivatePageCount = CType(item.Properties("PrivatePageCount").Value, UInt64?),
                    .ProcessId = CType(item.Properties("ProcessId").Value, UInt32?),
                    .QuotaNonPagedPoolUsage = CType(item.Properties("QuotaNonPagedPoolUsage").Value, UInt32?),
                    .QuotaPagedPoolUsage = CType(item.Properties("QuotaPagedPoolUsage").Value, UInt32?),
                    .QuotaPeakNonPagedPoolUsage = CType(item.Properties("QuotaPeakNonPagedPoolUsage").Value, UInt32?),
                    .QuotaPeakPagedPoolUsage = CType(item.Properties("QuotaPeakPagedPoolUsage").Value, UInt32?),
                    .ReadOperationCount = CType(item.Properties("ReadOperationCount").Value, UInt64?),
                    .ReadTransferCount = CType(item.Properties("ReadTransferCount").Value, UInt64?),
                    .SessionId = CType(item.Properties("SessionId").Value, UInt32?),
                    .Status = CType(item.Properties("Status").Value, String),
                    .TerminationDate = ManagementUtils.ToDateTime(item.Properties("TerminationDate").Value),
                    .ThreadCount = CType(item.Properties("ThreadCount").Value, UInt32?),
                    .UserModeTime = CType(item.Properties("UserModeTime").Value, UInt64?),
                    .VirtualSize = CType(item.Properties("VirtualSize").Value, UInt64?),
                    .WindowsVersion = CType(item.Properties("WindowsVersion").Value, String),
                    .WorkingSetSize = CType(item.Properties("WorkingSetSize").Value, UInt64?),
                    .WriteOperationCount = CType(item.Properties("WriteOperationCount").Value, UInt64?),
                    .WriteTransferCount = CType(item.Properties("WriteTransferCount").Value, UInt64?)
                }
            ).ToArray()
        End Using
    End Function

End Class

Friend Class ManagementUtils

    Friend Shared Function ToDateTime(value As Object) As DateTime?
        If (value Is Nothing) Then
            Return CType(Nothing, DateTime?)
        End If
        Return ManagementDateTimeConverter.ToDateTime(CType(value, String))
    End Function

End Class

测试

Dim watch As New Stopwatch()

watch.[Start]()

Dim result As New Dictionary(Of Process, Win32Process)
Dim processes As Win32Process() = Win32Process.GetProcesses()

Process.GetProcesses().AsParallel().ForAll(
    Sub(p As Process)
        SyncLock result
            result.Add(p, (From item In processes.AsEnumerable() Where (item.ProcessId.HasValue AndAlso (CUInt(p.Id) = item.ProcessId.Value)) Select item).FirstOrDefault())
        End SyncLock
    End Sub)

watch.[Stop]()

Debug.WriteLine("Time: {0} ms, Win32ProcessCount={1}, ProcessCount={1}", watch.Elapsed.TotalMilliseconds, processes.Length, result.Count)
Debug.WriteLine("**************")
Debug.WriteLine(String.Join(Environment.NewLine, (From pair As KeyValuePair(Of Process, Win32Process) In result Select String.Format("Id={0}, Matched={1}", pair.Key.Id.ToString("X8"), (Not pair.Value Is Nothing)))))

结果

时间:165.53 毫秒,Win32ProcessCount=96,ProcessCount=96
**************
Id=00001B1C,Matched=True
Id=000019FC,Matched =真
Id=000006EC,匹配=真
Id=000007B0,匹配=真
Id=00001CC0,匹配=真
Id=00001024,匹配=真
Id=00000AC0,匹配=真
Id=0000078C,匹配=真
Id=00001BA8,匹配=真
Id=00000B7C,匹配=真
Id=00000304,匹配=真
Id=0000079C,匹配=True
Id=00000238, 匹配=True
Id=00000F80, 匹配=True
Id=000003C0, 匹配=True
Id=00000170, 匹配=True
Id=00000234, 匹配=真
Id=00001634,匹配=真
Id=00000230,匹配=真
Id=00001B94,匹配=真
Id=00000540,匹配=真
Id=00001254,匹配=真
Id=00001A04,匹配=真
Id=000002EC,匹配=真
Id=00000474,匹配=真
Id=00000910,匹配=真
Id=000005B8,匹配=True
Id=000004F0, Matched=True
Id=00000114, Matched=True
Id=000015D8, Matched=True
Id=00000738, Matched=True
Id=0000144C, Matched =T rue
Id=0000133C, Matched=True
Id=00001384, Matched=True
Id=000007F8, Matched=True
Id=00000294, Matched=True
Id=000012BC, Matched= True
Id=00000D58, Matched=True
Id=00000B08, Matched=True
Id=00001F08, Matched=True
Id=00000AFC, Matched=True
Id=00000B04, Matched= True
Id=00001750, Matched=True
Id=000008B0, Matched=True
Id=0000199C, Matched=True
Id=000001C0, Matched=True
Id=00000970, Matched= True
Id=00000720, Matched=True
Id=0000136C, Matched=True
Id=000001B8, Matched=True
Id=000001B4, Matched=True
Id=000012A0, Matched= True
Id=00000D3C, Matched=True
Id=0000093C, Matched=True
Id=00001890, Matched=True
Id=000012D0, Matched=True
Id=000003F8, Matched= True
Id=00000330, Matched=True
Id=00000AE0, Matched=True
Id=00000954, Matched=True
Id=000002B4, Matched=True
Id=00000C64, Matched= True
Id=00000574, Matched=True
Id=00001FD4, Matched=True
Id=000018BC, Matched=True
Id=00001A44, Matched=True
Id=0000 0B94,匹配=真
Id=00000630,匹配=真
Id=000003E0,匹配=真
Id=00000004,匹配=真
Id=0000102C,匹配=真
Id= 000005C0, 匹配=真
Id=00000000, 匹配=真
Id=000009D0, 匹配=真
Id=00000C1C, 匹配=真
Id=00000218, 匹配=真
Id= 00000A88, 匹配=真
Id=00000B70, 匹配=真
Id=000002D4, 匹配=真
Id=00000398, 匹配=真
Id=0000020C, 匹配=真
Id= 000009B8,匹配=真
Id=0000082C,匹配=真
Id=00001298,匹配=真
Id=000009B0,匹配=真
Id=00000760,匹配=真
Id= 00000F40, 匹配=真
Id=00000758, 匹配=真
Id=00001128, 匹配=真
Id=000005C8, 匹配=真
Id=00000C24, 匹配=真
Id= 00001900, 匹配=真
Id=0000124C, 匹配=真
Id=00001148, 匹配=真
Id=0000120C, 匹配=真
Id=00000CA8, 匹配=真

【讨论】:

  • 一句话,太棒了。谢谢你
【解决方案2】:

事实是你不能这样做。

Here是原因: "注意: 32 位进程无法访问 64 位进程的模块。如果您尝试从 32 位进程中获取有关 64 位进程的信息,您将收到 Win32Exception例外。”

而且,正如您所看到的 hereProcess.MainModule 属性会在“32 位进程试图访问64 位进程的模块。".

This question 声明您应该“捕获异常并继续前进”。

您似乎是通过Process.MainModule 直接访问模块,因此32 位程序集将无法访问64 位模块。 更好的解释here

确保您确实需要 32 位版本的应用程序(如果您没有引用任何 32 位 DLL,那么您应该将您的程序集编译为“任何 CPU”,这样可以避免该问题)。

【讨论】:

  • 谢谢,但正如我在我的问题中指出的那样,我知道并且我理解为什么会出现问题,我要求的是解决方案,而不是对问题的解释。我看到许多用 C/C++ 开发的 x86 任务管理器,它们可以列出 x64 进程并管理其“属性”(当然这些应用程序我确定不使用 WMI 查询,因为更新进程列表太慢了每 100-500 毫秒)。感谢您的回答
  • @ElektroStudios 在这里阅读stackoverflow.com/questions/3801517/… 第一个答案。此外,他的回答并不完全正确,因为您可以在运行时加载 ntdlls 的 wow64 函数,并使用它们从在 wow64 下运行的 32 位进程读取 64 位进程的内存。我还没有找到以这种方式访问​​模块的方法(我正在寻找)。我会尝试更新,尽管我使用的是 C++。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-08
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 2015-07-27
相关资源
最近更新 更多