C#在Process.Kill()期间只完成了ReadProcessMemory或WriteProcessMemory请求的一部分

时间:2012-06-11 19:41:23

标签: c# exception process

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

我知道当32位进程尝试访问64位进程时会抛出Only part of a ReadProcessMemory or WriteProcessMemory request was completed异常,而对于修改32位进程的64位进程则抛出异常。

该问题的解决方案是将平台目标更改为“任何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位混合在一起。

我有什么我不应该做的事情,还是有更好的方法来做所有这些?

3 个答案:

答案 0 :(得分:15)

详见the MSDN page for Process.Modulesthis thread的注释,在{64}进程枚举32位进程时Process.Modules存在已知问题,反之亦然:

  

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

解决方案似乎是使用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
  •   

答案 1 :(得分:3)

关于流程的处理和我将要更改的锁定只有一些问题:

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);
    }                
}

我没有回答赏金,只是想提出一些想法。此代码未经过测试,因为我并不确切知道您要在那里做什么。

请考虑不要锁定进程列表并尽可能缩短锁定。

答案 2 :(得分:0)

我同意@ 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并将其类型更改为集合,迭代在检查非零计数之后在底部块中的那个列表,并在该循环之外锁定,以减少获取和释放每个进程锁定的开销以杀死。