19

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

我知道Only part of a ReadProcessMemory or WriteProcessMemory request was completed当 32 位进程尝试访问 64 位进程时会引发异常,对于 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 位混合在一起的。

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

4

3 回答 3

19

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

.NET 的 Process.Modules 在内部使用 PSAPI.dll 中的函数 EnumProcessModules。此函数有一个已知问题,即它无法跨 32/64 位进程边界工作。因此,从 32 位进程枚举另一个 64 位进程(反之亦然)无法正常工作。

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

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

  • 它仅适用于 Windows Vista 或 Windows Server 2008
  • 目前 .NET 2.0 Framework 没有服务包或修补程序来使 Process.Modules 使用这个新 API
于 2012-06-21T09:10:54.273 回答
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);
    }                
}

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

只需考虑不要锁定进程列表并尽可能缩短锁定时间。

于 2012-06-17T00:25:34.993 回答
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您希望终止的进程,请考虑更改processToRemoveprocessesToRemove并将其类型更改为集合,在检查非零计数并锁定后迭代底部块中的该列表在该循环之外,以减少每个要杀死的进程获取和释放锁的开销。

于 2012-06-21T09:29:32.010 回答