C # Только часть запроса 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-битными, смешанными вместе.

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

 Vincent14 июн. 2012 г., 23:48
О хорошо Это также может быть сделано локально без указания имени компьютера. Вам нужно только установить PowerShell на них, и вы можете проверить убийства из командной строки.
 Vincent14 июн. 2012 г., 22:08
Я не знаю всей вашей программы, но, поскольку у вас, похоже, есть права на удаленное уничтожение, рассматривали ли вы возможность использования PowerShell и удаленного уничтожения? Вы даже можете вызвать командлеты из C #, если это необходимо.4sysops.com/archives/…
 Vincent14 июн. 2012 г., 22:22
Это может сработать. Я не могу сказать наверняка, хотя. Но способ, которым Windows убивает процессы, может отличаться от C # до Wmi.
 Kyle Uithoven14 июн. 2012 г., 23:02
@Vincent: Я думаю, что я хотел сказать, я бы предпочел, чтобы этот код работал, чем делал это. У меня вся эта система уже запущена и работает, и я бы не хотел выполнять удаленные убийства, поскольку у меня нет доступа к ним "удаленно".
 Kyle Uithoven14 июн. 2012 г., 22:13
@Vincent: это способ, которым это работает. У меня есть "Сервер" программа, которую я запускаю на компьютере, и все компьютеры в одной комнате являются "клиентами"; этого сервера компьютера. Все клиенты запускают клиентскую программу, которая принимает сообщения TCP. Чтобы закрыть программу, я отправляю клиенту сообщение TCP для закрытия определенного процесса, и клиент обрабатывает уничтожение своих собственных программ.

Ответы на вопрос(3)

Решение Вопроса

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

Internally .NET's Process.Modules is using function EnumProcessModules from PSAPI.dll. This function has a known issue that it cannot work across 32/64 bit process boundary. Therefore enumerating another 64-bit process from 32-bit process or vice versa doesn't work correctly.

Решение, похоже, заключается в использованииEnumProcessModulesEx функция (которая должна вызываться через P / Invoke), однако эта функция доступна только в более поздних версиях Windows.

We fixed this issue by adding a new function called EnumProcessModulesEx to PSAPI.dll (http://msdn2.microsoft.com/en-us/library/ms682633.aspx), but we currently cannot use it in this case:

it only works on Windows Vista or Windows Server 2008 currently .NET 2.0 Framework don't have a service pack or hotfix to make Process.Modules use this new API
 21 июн. 2012 г., 19:24
На самом деле это исключение. Я столкнулся с той же проблемой с Process.Modules.
 Kyle Uithoven21 июн. 2012 г., 20:55
Спасибо за информацию о Process.Modules. Я подумал, что это, скорее всего, проблема в .NET Framework. Я дам отзыв, когда я проверю функцию EnumProcessModulesEx.
 21 июн. 2012 г., 18:31
Вероятно, это не та проблема, с которой сталкивается @Kyle, потому что эта ошибка молча не сможет перечислить некоторые модули, не вызывая исключения.

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

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

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

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

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

Ваш ответ на вопрос