2012-06-11 16 views
12

He estado investigando este tema bastante extensamente y parece que no puedo encontrar una respuesta.C# Sólo se completó una parte de una solicitud de ReadProcessMemory o WriteProcessMemory durante Process.Kill()

Sé que la excepción Only part of a ReadProcessMemory or WriteProcessMemory request was completed se produce cuando un proceso de 32 bits intenta acceder a un proceso de 64 bits y lo mismo para un proceso de 64 bits que modifica un proceso de 32 bits.

La solución a este problema es cambiar el objetivo de la plataforma a 'Cualquier CPU'. Lo he intentado y, lamentablemente, esto no soluciona mi problema.

El siguiente bloque de código es lo que sigue arrojando la excepción. El programa que ejecuta este código se usa para abrir aplicaciones en computadoras remotas y mantiene una lista de todos los procesos que el programa mismo abrió para que no tenga que recorrer todos los procesos.

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

Estos procesos pueden y muy probablemente serán de 32 bits y de 64 bits, mezclados.

¿Hay algo que esté haciendo que no debería estar haciendo o hay una forma mejor de hacer todo esto?

+0

No conozco todo el programa, pero como parece que tiene los derechos para matar a distancia, ¿ha considerado utilizar PowerShell y eliminarlo remotamente? incluso puede invocar cmdlets desde C# si es necesario. http://4sysops.com/archives/query-and-kill-a-process-on-a-remote-computer-using-powershell-and-wmi/ – Vincent

+0

@Vincent: esta es la forma en que funciona. Tengo un programa "Servidor" que ejecuto en una computadora y todas las computadoras en la misma sala son "clientes" de esta computadora servidor. Todos los clientes ejecutan un programa de cliente que acepta mensajes TCP. Para cerrar un programa, le envío al cliente un mensaje TCP para cerrar un determinado proceso y el cliente maneja la destrucción de sus propios programas. –

+0

Puede funcionar. Sin embargo, no puedo decirlo con certeza. Pero la forma en que Windows mata los procesos puede ser diferente de C# a Wmi. – Vincent

Respuesta

13

Como se detalla en los comentarios de the MSDN page for Process.Modules y this thread no es un problema conocido en Process.Modules al enumerar los procesos de 32 bits a partir de un proceso de 64 bits y viceversa:

Process.Modules de Internamente .NET está usando la función de EnumProcessModules de PSAPI.dll. Esta función tiene un problema conocido que no puede funcionar en un límite de proceso de 32/64 bits. Por lo tanto, enumerar otro proceso de 64 bits del proceso de 32 bits o viceversa no funciona correctamente en .

La solución parece ser la de utilizar la función de EnumProcessModulesEx, (que debe ser llamado a través de P/Invoke), sin embargo esta función sólo está disponible en versiones posteriores de Windows.

Hemos solucionado este problema agregando una nueva función llamada EnumProcessModulesEx a PSAPI.DLL (http://msdn2.microsoft.com/en-us/library/ms682633.aspx), pero actualmente no puede utilizarlo en este caso:

  • que sólo funciona en Windows Vista o Windows Server 2008
  • Actualmente .NET Framework 2.0 no tienen un Service Pack o una revisión para hacer del proceso.Módulos utilizan esta nueva API
+0

Probablemente este no sea el problema con el que @Kyle se está ejecutando, porque este error silenciosamente no podrá enumerar ciertos módulos, sin lanzar una excepción. –

+0

En realidad arroja una excepción. Me he encontrado con el mismo problema con Process.Modules. – Will

+0

Gracias por la información sobre los Process.Modules. Pensé que probablemente era un problema en .NET Framework. Daré feedback cuando pruebo la función EnumProcessModulesEx. –

3

Sólo hay algunas cuestiones relacionadas con el manejo de los procesos y el bloqueo que iba a cambiar:

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

No voy a responder por el favor, sólo quería darle algunas ideas. Este código no se prueba porque no sé exactamente qué estás tratando de hacer allí.

Simplemente considere no bloquear la lista de procesos y mantener el bloqueo lo más corto posible.

0

Estoy de acuerdo con @ sprinter252 que _runningProcesses no deben utilizarse como su objeto de sincronización aquí.

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

Si este código se envuelve en un bucle para seguir verificando _runningProcesses para el proceso que desea matar, considere cambiar processToRemove a processesToRemove y cambiar su tipo a una colección, iterar sobre esa lista en el bloque inferior después un control para un conteo distinto de cero y bloqueo fuera de ese bucle para disminuir la sobrecarga de obtener y liberar bloqueos por proceso para matar.

Cuestiones relacionadas