Подтвердить что ты не робот

С# Только часть запроса ReadProcessMemory или WriteProcessMemory была завершена во время Process.Kill()

Я довольно широко изучал эту проблему и не могу найти ответа.

Я знаю, что исключение Only part of a ReadProcessMemory or WriteProcessMemory request was completed возникает, когда 32-разрядный процесс пытается получить доступ к 64-битовому процессу и тот же для 64-битного изменения 32-разрядного процесса.

Решение этой проблемы заключается в изменении целевой платформы на "Любой процессор". Я пробовал это и, к сожалению, это не решает мою проблему.

Следующий блок кода - это то, что продолжает бросать исключение. Программа, которая запускает этот код, используется для открытия приложений на удаленных компьютерах и ведет список всех процессов, которые сама программа открыла, чтобы мне не пришлось перебирать все процессы.

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-битными, смешанными вместе.

Есть ли что-нибудь, что я делаю, чего я не должен делать, или есть лучший способ сделать все это?

4b9b3361

Ответ 1

Как указано в комментариях страницы MSDN для Process.Modules и этот поток, есть известную проблему в Process.Modules при перечислении 32-битных процессов из 64-битного процесса и наоборот:

Внутренне .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 не имеет пакета обновления или исправления для того, чтобы Process.Modules использовали этот новый API

Ответ 2

Есть только некоторые проблемы, связанные с обработкой процессов и блокировкой, которые я бы изменил:

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

Я не отвечаю за щедрость, просто хотел дать некоторые идеи. Этот код не проверен, потому что я точно не знаю, что вы там делаете.

Просто подумайте над тем, чтобы не блокировать список процессов и не блокировать блокировку как можно короче.

Ответ 3

Я согласен с @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 и измените его тип на коллекцию, перейдете в этот список внизу блок после проверки ненулевого счета и блокировки за пределами этого цикла, чтобы уменьшить накладные расходы на получение и освобождение блокировок на каждый процесс, чтобы убить.