una servicio sea rufus que programa patcher paladins otra juego instancia instalacion existe este esta esperando error ejecutandose ejecutando disponible detecto aplicacion actualizado delphi persistence mutex instance semaphore

delphi - servicio - ya existe una instancia de rufus ejecutandose



¿Cómo puedo saber si ya se está ejecutando otra instancia de mi programa? (11)

Como Jon sugirió por primera vez, puedes intentar crear un mutex. Llamar a CreateMutex . Si obtiene un identificador no nulo, llame a GetLastError . Le dirá si usted fue el que creó el mutex o si el mutex ya estaba abierto antes ( Error_Already_Exists ). Tenga en cuenta que no es necesario adquirir la propiedad del mutex. El mutex no se usa para la exclusión mutua. Se está utilizando porque es un objeto kernel con nombre. Un evento o semáforo podría funcionar también.

La técnica mutex le da una respuesta booleana: Sí, hay otra instancia, o no, no la hay.

Con frecuencia quiere saber más que eso. Por ejemplo, es posible que desee conocer el manejador de la ventana principal de la otra instancia para que pueda decir que aparezca en primer plano en lugar de su otra instancia. Ahí es donde un archivo mapeado en memoria puede ser útil; puede contener información sobre la primera instancia para que las instancias posteriores puedan referirse a ella.

Tenga cuidado al elegir el nombre del mutex. Lea la documentación detenidamente y tenga en cuenta que algunos caracteres (como la barra diagonal inversa) no están permitidos en algunas versiones del sistema operativo, pero se requieren para ciertas funciones en otras versiones del sistema operativo.

También recuerda el problema de otros usuarios. Si su programa podría ejecutarse a través de un escritorio remoto o un cambio rápido de usuario, entonces podría haber otros usuarios ya ejecutando su programa, y ​​es posible que no desee restringir al usuario actual para que ejecute su programa. En ese caso, no use un nombre global. Si desea restringir el acceso para todos los usuarios, asegúrese de que los atributos de seguridad del objeto mutex sean tales que todos puedan abrirle un identificador. El uso de un puntero nulo para el parámetro lpSecurityAttributes no es suficiente para eso; el "descriptor de seguridad predeterminado" que MSDN menciona da acceso completo al usuario actual y no tiene acceso a otros.

Puede editar el archivo DPR de su programa. Ese suele ser un buen lugar para hacer este tipo de cosas. Si espera hasta el evento OnCreate de uno de sus formularios, entonces su programa ya tiene un poco de impulso para funcionar normalmente, por lo que es torpe intentar finalizar el programa en ese momento. Es mejor terminar antes de que se haya realizado demasiado trabajo de UI. Por ejemplo:

var mutex: THandle; mutexName: string; begin mutexName := ConstructMutexName(); mutex := CreateMutex(nil, False, PChar(mutexName)); if mutex = 0 then RaiseLastOSError; // Couldn''t open handle at all. if GetLastError = Error_Already_Exists then begin // We are not the first instance. SendDataToPreviousInstance(...); exit; end; // We are the first instance. // Do NOT close the mutex handle here. It must // remain open for the duration of your program, // or else later instances won''t be able to // detect this instance. Application.Initialize; Application.CreateForm(...); Application.Run; end.

Hay una cuestión de cuándo cerrar el controlador mutex. No tienes que cerrarlo. Cuando finalmente finaliza su proceso (incluso si falla), el sistema operativo cerrará automáticamente todos los identificadores pendientes, y cuando no haya más identificadores abiertos, el objeto mutex se destruirá (lo que permite que otra instancia de su programa se inicie y se considere a sí misma ser la primera instancia).

Pero es posible que desee cerrar el mango de todos modos. Supongamos que elige implementar la función SendDataToPreviousInstance que mencioné en el código. Si desea ser elegante, puede justificar el caso de que la instancia anterior ya se está cerrando y no puede aceptar nuevos datos. Entonces, realmente no querrás cerrar la segunda instancia. La primera instancia podría cerrar el identificador de mutex tan pronto como sepa que se está cerrando, convirtiéndose en una instancia de "pato cojo". La segunda instancia intentará crear el control mutex, tener éxito y considerarse la primera instancia real. La instancia anterior se cerrará ininterrumpidamente. Use CloseHandle para cerrar el mutex; llámalo desde el controlador de eventos OnClose de tu formulario principal, o donde sea que llames a Application.Terminate , por ejemplo.

¿Cómo puedo saber si una instancia de mi programa se está ejecutando? Pensé que podría hacer esto con un archivo de datos, pero sería complicado :(

Quiero hacer esto, ya que solo quiero que 1 instancia esté abierta en algún momento.



En el pasado, he usado un socket para evitar que se ejecuten varias instancias al mismo tiempo. Si el socket está en uso, no continúe con el programa; si está disponible, permita que todo se ejecute normalmente.


La solución normal es crear un mutex con nombre de todo el sistema .

  • Si logras crearlo, eres la única aplicación en ejecución.
  • Si no lo haces, sabes que hay uno diferente.

EDITAR:

No proporcioné el código porque no conozco a Delphi. Puedo proporcionar el código C # si eso fuera útil.


Me gustaría agregar un punto a la excelente respuesta de Rob Kennedy (aparte del hecho de que sería mejor hacer una función de su código en lugar de copiar todo en el archivo DPR. Solo necesita dos parámetros, el nombre del mutex, y un booleano si el mutext debe ser por usuario o por todo el sistema).

La respuesta no presta mucha atención a la denominación del mutex. Si espera que su programa se instale a través de Inno Setup (y quizás otras herramientas de configuración también) debe elegir el nombre cuidadosamente, ya que el mutex se puede usar para que el programa de instalación compruebe si la aplicación se está ejecutando actualmente, y alerta al usuario que deberían cerrar todas las instancias de la aplicación. Si elige permitir una instancia del programa por usuario, es posible que necesite crear un segundo mutex para todo el sistema, ya que es posible que la configuración no necesite ejecutar instancias de la aplicación para poder reemplazar los archivos. El nombre que se utilizará para la sincronización con un instalador InnoSetup debe estar codificado.


Puede crear un semáforo y detener la ejecución (poner el código en su archivo * .dpr) y traerle la aplicación en ejecución a la pantalla.

var Semafor: THandle; begin { Don''t start twice ... if already running bring this instance to front } Semafor := CreateSemaphore(nil, 0, 1, ''MY_APPLICATION_IS_RUNNING''); if ((Semafor <> 0) and { application is already running } (GetLastError = ERROR_ALREADY_EXISTS)) then begin RestoreWindow(''TMyApplication''); CloseHandle(Semafor); Halt; end; Application.CreateForm(....); Application.Initialize; Application.Run; CloseHandle(Semafor); end;

EDITAR (agregó el método RestoreWindow ):

El aFormName es el nombre de su clase de formulario principal en su aplicación.

procedure RestoreWindow(aFormName: string); var Wnd, App: HWND; begin Wnd := FindWindow(PChar(aFormName), nil); if (Wnd <> 0) then begin { Set Window to foreground } App := GetWindowLong(Wnd, GWL_HWNDPARENT); if IsIconic(App) then ShowWindow(App, SW_RESTORE); SetForegroundwindow(App); end; end;


Simplemente puede usar la función API de FindWindow. En la clase delphi, el nombre de la ventana es el mismo que el nombre de la clase, puede redefinir el nombre de la clase anulando la función CreateParams. Para verificar si existe una ventana, agregue el código antes de que se cree la ventana principal, antes de Application.Initialize;

Program test var handle :HWND; begin handle := FindWindow(''TMySuperApp'', nil); if IsWindow(handle) then begin //app is running exit; end. Application.Initialize; Application.CreateForm(TMySuperApp, SuperApp); Application.Run; end;


Usted crea un mutex del sistema .

No tengo el código Delphi, pero aquí está el código C ++:

HANDLE Mutex; const char MutexName[] = "MyUniqueProgramName"; Mutex = OpenMutex(MUTEX_ALL_ACCESS, false, MutexName); if (Mutex) throw Exception("Program is already running."); else Mutex = CreateMutex(NULL, true, MutexName);


Ver esta unidad (usando CreateMutex): UiApp

Además en esta página, puede leer las ventajas y desventajas de este trabajo con diferentes métodos (mutex, FindWindows, ...).

Esta unidad tiene la solución para activar la instancia previa de la aplicación cuando se detecta.

Saludos y disculpas por mi mal inglés.

Neftalí -Germán Estévez-


Yo diría que hay varias estrategias diferentes que puedes emplear. Pero la más fácil (y no específica de la plataforma) es la que usted mismo sugirió, es decir, al comienzo del programa verificar para ver si hay un archivo de bloqueo creado en un conjunto, ubicación específica. Si este archivo de bloqueo existe, entonces ya se está ejecutando otra instancia, si no existe, entonces no hay otra instancia ejecutándose. Cuando su programa sale, elimina el archivo de bloqueo.

Sin embargo, si empleas esta estrategia tienes otro problema, ¿qué ocurre si tu programa falla? El archivo de bloqueo aún permanece, y este caso específico necesita ser manejado.

Otra estrategia es la solución mutex para todo el sistema, donde registra su presencia dentro del sistema operativo (o también es plausible que esto se haga automágicamente). Cuando una segunda instancia intenta iniciar, comprueba si ya hay un proceso activo con una ID específica. Si ya existe, el segundo proceso elige no iniciar y opcionalmente enfoca la ventana del primer proceso (si el proceso en cuestión posee una ventana).

Sin embargo, esta estrategia es específica de la plataforma, y ​​la implementación diferirá de una plataforma a otra.