manejo hilos winapi process multithreading mutex singleinstance

winapi - manejo - hilos en c++>



Win32: ¿Cómo obtener el proceso/thread que posee un mutex? (5)

Esto debería hacer que comiences con la solicitud original para obtener un proceso que posea un mutex.

Está en C #, pero las llamadas de Win32 son las mismas.

class HandleInfo { [DllImport("ntdll.dll", CharSet = CharSet.Auto)] public static extern uint NtQuerySystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, out int ReturnLength); [DllImport("kernel32.dll", SetLastError = true)] internal static extern IntPtr VirtualAlloc(IntPtr address, uint numBytes, uint commitOrReserve, uint pageProtectionMode); [DllImport("kernel32.dll", SetLastError=true)] internal static extern bool VirtualFree(IntPtr address, uint numBytes, uint pageFreeMode); [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_HANDLE_INFORMATION { public int ProcessId; public byte ObjectTypeNumber; public byte Flags; // 1 = PROTECT_FROM_CLOSE, 2 = INHERIT public short Handle; public int Object; public int GrantedAccess; } static uint MEM_COMMIT = 0x1000; static uint PAGE_READWRITE = 0x04; static uint MEM_DECOMMIT = 0x4000; static int SystemHandleInformation = 16; static uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; public HandleInfo() { IntPtr memptr = VirtualAlloc(IntPtr.Zero, 100, MEM_COMMIT, PAGE_READWRITE); int returnLength = 0; bool success = false; uint result = NtQuerySystemInformation(SystemHandleInformation, memptr, 100, out returnLength); if (result == STATUS_INFO_LENGTH_MISMATCH) { success = VirtualFree(memptr, 0, MEM_DECOMMIT); memptr = VirtualAlloc(IntPtr.Zero, (uint)(returnLength + 256), MEM_COMMIT, PAGE_READWRITE); result = NtQuerySystemInformation(SystemHandleInformation, memptr, returnLength, out returnLength); } int handleCount = Marshal.ReadInt32(memptr); SYSTEM_HANDLE_INFORMATION[] returnHandles = new SYSTEM_HANDLE_INFORMATION[handleCount]; using (StreamWriter sw = new StreamWriter(@"C:/NtQueryDbg.txt")) { sw.WriteLine("@ Offset/tProcess Id/tHandle Id/tHandleType"); for (int i = 0; i < handleCount; i++) { SYSTEM_HANDLE_INFORMATION thisHandle = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure( new IntPtr(memptr.ToInt32() + 4 + i * Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION))), typeof(SYSTEM_HANDLE_INFORMATION)); sw.WriteLine("{0}/t{1}/t{2}/t{3}", i.ToString(), thisHandle.ProcessId.ToString(), thisHandle.Handle.ToString(), thisHandle.ObjectTypeNumber.ToString()); } } success = VirtualFree(memptr, 0, MEM_DECOMMIT); } }

Estoy trabajando en una aplicación de la cual solo debe existir una instancia en un momento dado. Hay varias posibilidades para lograr esto:

  • Compruebe los procesos en ejecución para uno que coincida con el nombre de nuestro EXE (no confiable)
  • Encuentra la ventana principal (no confiable, y no siempre tengo una ventana principal)
  • Crear un mutex con un nombre único (GUID)

La opción mutex me parece la más confiable y elegante.

Sin embargo, antes de que termine mi segunda instancia, deseo publicar un mensaje en la instancia que ya se está ejecutando. Para esto, necesito un control para el hilo (o el proceso) que posee el mutex.

Sin embargo, parece que no hay función de API para obtener el creador / propietario de un mutex determinado. ¿Acabo de pasarlo por alto? ¿Hay alguna otra manera de llegar a este hilo / proceso? ¿Hay alguna otra manera de hacerlo?

Actualización : este tipo simplemente transmite un mensaje a todos los procesos en ejecución. Supongo que es posible, pero realmente no me gusta ...


Nunca entendí realmente lo racional detrás de usar un Mutex que no tiene capacidad de señalización. En su lugar, crearía un evento (usando CreateEvent) que tiene las mismas propiedades que crear un mutex (es decir, con un nombre puede devolver que el objeto ya existía) pero puede establecer el indicador de evento en el nuevo proceso, siempre que el original proceso está esperando en el indicador de evento, se puede notificar cuando necesita activarse.


Siempre puede hacerlo de la manera UNIX y crear un archivo "pid", colocando el id. De proceso de la instancia que se está ejecutando actualmente en ese archivo. Luego haga que la aplicación elimine el archivo cuando salga.

Cuando se inicia una nueva instancia, debe verificar que el proceso en el archivo PID esté realmente activo (en caso de que la aplicación salga anormalmente y el archivo no se elimine)


Crea un área de memoria compartida con el nombre fijo:

http://msdn.microsoft.com/en-us/library/aa366551%28VS.85%29.aspx

Luego puede poner cualquier estructura que le guste adentro, incluyendo identificación de proceso, HWND, etc.

Hay una opción portátil : crear un socket en un puerto (con un número fijo) y esperar (aceptar) en él. La segunda instancia de la aplicación fallará ya que el puerto ya está ocupado. Luego, la segunda instancia puede conectarse al socket de la instancia principal y enviar la información deseada.

Espero que esto ayude...


No creo que haya una forma trivial de resolver el propietario real de un Mutex, pero el proceso que lo posee puede crear otros elementos secundarios cuyas vidas están ligadas a él. Hay muchos mecanismos que son adecuados para devolver la llamada a través del proceso sin tener una ventana principal.

  1. Registre un objeto en la tabla de objetos ejecutables COM. Los clientes que no pueden tomar posesión del Mutex pueden buscar al propietario a través del ROT y devolver la llamada al propietario. Un File Moniker debería ser adecuado para registrarse aquí.
  2. Crea un fragmento de memoria compartida que contenga detalles de ubicación para el proceso de propietario. A partir de ahí, escriba en el búfer el identificador de proceso y el manejador de subprocesos de un subproceso que puede recibir mensajes de Windows, y luego use PostThreadMessage () para enviar una notificación. Cualquier otro proceso competitivo puede abrir la memoria compartida de solo lectura para determinar dónde enviar un mensaje de Windows.
  3. Escuche en el proceso del propietario en un Socket o Named Pipe. Probablemente exagerado y no un buen partido para sus necesidades.
  4. Use un archivo compartido con bloqueo. No me gusta esto porque el propietario tendrá que sondear, y no manejará con gracia el potencial de N otros procesos que podrían estar tratando de contactar al propietario al mismo tiempo.

Aquí hay enlaces de referencia para las dos primeras opciones.

  1. IRunningObjectTable @ MSDN , File Monikers @ MSDN
  2. Creación de memoria compartida con nombre en MSDN