C# 在 Process.Kill() 期间,只有一部分 ReadProcessMemory 或 WriteProces

本文关键字:一部分 ReadProcessMemory WriteProces 期间 Process Kill | 更新日期: 2023-09-27 18:36:54

我一直在广泛地研究这个问题,似乎找不到答案。

我知道当 32 位进程尝试访问 64 位进程时会引发Only part of a ReadProcessMemory or WriteProcessMemory request was completed异常,而 64 位进程修改 32 位进程也是如此。

该问题的解决方案是将平台目标更改为"任何 CPU"。我已经尝试过这个,不幸的是这并不能解决我的问题。

下一个代码块是不断引发异常的代码块。运行此代码的程序用于打开远程计算机上的应用程序,并保留程序本身打开的所有进程的列表,这样我就不必遍历所有进程。

Process processToRemove = null;
lock (_runningProcesses)
{
    foreach (Process p in _runningProcesses)
    {
        foreach (ProcessModule module in p.Modules)
        {
            string[] strs = text.Split('''');
            if (module.ModuleName.Equals(strs[strs.Length - 1]))
            {
                processToRemove = p;
                break;
            }
        }
        if (processToRemove != null)
        {
            break;
        }
    }
    if (processToRemove != null)
    {
        processToRemove.Kill();
        _runningProcesses.Remove(processToRemove);
    }
}

这些进程可以而且很可能是 32 位和 64 位混合在一起。

我正在做的事情是我不应该做的事情,还是有更好的方法来做这一切?

C# 在 Process.Kill() 期间,只有一部分 ReadProcessMemory 或 WriteProces

正如 Process.Modules 和此线程的 MSDN 页面的评论中所述,从 64 位进程枚举 32 位进程时,Process.Modules中存在一个已知问题,反之亦然:

内部。NET 的 Process.Modules 正在使用函数 EnumProcessModules 来自PSAPI.dll。此函数存在无法正常工作的已知问题 跨 32/64 位进程边界。因此枚举另一个 64位进程的32位进程,反之亦然不起作用 正确。

解决方案似乎是使用 EnumProcessModulesEx 函数(必须通过 P/Invoke 调用),但是此功能仅在更高版本的 Windows 上可用。

我们通过添加 一个名为 EnumProcessModulesEx 到 PSAPI 的新函数.dll (http://msdn2.microsoft.com/en-us/library/ms682633.aspx),但我们 目前无法在这种情况下使用它:

  • 它仅适用于Windows Vista或Windows Server 2008
  • 目前 .NET 2.0 Framework 没有 Service Pack 或修补程序来使 Process.Modules 使用此新 API
关于

进程的处理和锁定,我只会更改一些问题:

object lockObject = new object();
List<Process> processesToRemove = new List<Process>();
foreach (Process p in _runningProcesses)
{
    foreach (ProcessModule module in p.Modules)
    {
        string[] strs = text.Split('''');
        if (module.ModuleName.Equals(strs[strs.Length - 1]))
        {
            processesToRemove.Add(p);
            break;
        }
    }                    
}                
lock (lockObject)
{
    foreach (Process p in processesToRemove)
    {                 
        p.Kill();
        _runningProcesses.Remove(p);
    }                
}

我不是在回答赏金,只是想给出一些想法。此代码未经过测试,因为我不完全知道您要在那里做什么。

只需考虑不要锁定进程列表并保持锁定尽可能短。

我同意@sprinter252的观点,即_runningProcesses不应该在这里用作您的同步对象。

//Somewhere that is accessible to both the thread getting the process list and the thread the 
//code below will be running, declare your sync, lock while adjusting _runningProcesses
public static readonly object Sync = new object();
IList<Process> runningProcesses;
lock(Sync)
{
    runningProcesses = _runningProcesses.ToList();
}
Process processToRemove = null;
foreach (Process p in _runningProcesses)
{
    foreach (ProcessModule module in p.Modules)
    {
        string[] strs = text.Split('''');
        if (module.ModuleName.Equals(strs[strs.Length - 1]))
        {
            processToRemove = p;
            break;
        }
    }
    if (processToRemove != null)
    {
        break;
    }
}
if (processToRemove != null)
{
    //If we've got a process that needs killing, re-lock on Sync so that we may 
    //safely modify the shared collection
    lock(Sync)
    {
        processToRemove.Kill();
        _runningProcesses.Remove(processToRemove);
    }
}

如果此代码包装在循环中以继续检查要终止的进程_runningProcesses,请考虑将processToRemove更改为processesToRemove并将其类型更改为集合,在检查非零计数后在底部块中迭代该列表,并在该循环之外锁定,以减少获取和释放每个要终止的进程的锁的开销。