¿Cómo pruebo si ya hay otra instalación en curso?
-
02-07-2019 - |
Pregunta
Suponiendo que estoy tratando de automatizar la instalación de algo en Windows y quiero probar si otra instalación está en progreso antes de intentar la instalación. No tengo control sobre el instalador y tengo que hacer esto en el marco de automatización. ¿Hay una mejor manera de hacer esto, alguna win32 api ?, que simplemente probar si msiexec se está ejecutando?
[Actualización 2]
Mejorado el código anterior que había estado usando para acceder directamente al mutex, esto es mucho más confiable:
using System.Threading;
[...]
/// <summary>
/// Wait (up to a timeout) for the MSI installer service to become free.
/// </summary>
/// <returns>
/// Returns true for a successful wait, when the installer service has become free.
/// Returns false when waiting for the installer service has exceeded the timeout.
/// </returns>
public static bool WaitForInstallerServiceToBeFree(TimeSpan maxWaitTime)
{
// The _MSIExecute mutex is used by the MSI installer service to serialize installations
// and prevent multiple MSI based installations happening at the same time.
// For more info: http://msdn.microsoft.com/en-us/library/aa372909(VS.85).aspx
const string installerServiceMutexName = "Global\\_MSIExecute";
try
{
Mutex MSIExecuteMutex = Mutex.OpenExisting(installerServiceMutexName,
System.Security.AccessControl.MutexRights.Synchronize | System.Security.AccessControl.MutexRights.Modify);
bool waitSuccess = MSIExecuteMutex.WaitOne(maxWaitTime, false);
MSIExecuteMutex.ReleaseMutex();
return waitSuccess;
}
catch (WaitHandleCannotBeOpenedException)
{
// Mutex doesn't exist, do nothing
}
catch (ObjectDisposedException)
{
// Mutex was disposed between opening it and attempting to wait on it, do nothing
}
return true;
}
Solución
Consulte la descripción del _MSIExecute Mutex en MSDN.
Otros consejos
Estaba obteniendo una excepción no controlada usando el código anterior. Crucé este artículo con este one
Aquí está mi código actualizado:
/// <summary>
/// Wait (up to a timeout) for the MSI installer service to become free.
/// </summary>
/// <returns>
/// Returns true for a successful wait, when the installer service has become free.
/// Returns false when waiting for the installer service has exceeded the timeout.
/// </returns>
public static bool IsMsiExecFree(TimeSpan maxWaitTime)
{
// The _MSIExecute mutex is used by the MSI installer service to serialize installations
// and prevent multiple MSI based installations happening at the same time.
// For more info: http://msdn.microsoft.com/en-us/library/aa372909(VS.85).aspx
const string installerServiceMutexName = "Global\\_MSIExecute";
Mutex MSIExecuteMutex = null;
var isMsiExecFree = false;
try
{
MSIExecuteMutex = Mutex.OpenExisting(installerServiceMutexName,
System.Security.AccessControl.MutexRights.Synchronize);
isMsiExecFree = MSIExecuteMutex.WaitOne(maxWaitTime, false);
}
catch (WaitHandleCannotBeOpenedException)
{
// Mutex doesn't exist, do nothing
isMsiExecFree = true;
}
catch (ObjectDisposedException)
{
// Mutex was disposed between opening it and attempting to wait on it, do nothing
isMsiExecFree = true;
}
finally
{
if(MSIExecuteMutex != null && isMsiExecFree)
MSIExecuteMutex.ReleaseMutex();
}
return isMsiExecFree;
}
Perdón por secuestrar tu publicación
He estado trabajando en esto, durante aproximadamente una semana, usando sus notas (Gracias) y las de otros sitios, demasiadas para nombrar (Gracias a todos).
Me topé con información que revelaba que el Servicio podría proporcionar suficiente información para determinar si el servicio MSIEXEC ya está en uso. El Servicio es 'msiserver' (Windows Installer) y su información es tanto de estado como de aceptación.
El siguiente código VBScript verifica esto.
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Check = False
Do While Not Check
WScript.Sleep 3000
Set colServices = objWMIService.ExecQuery("Select * From Win32_Service Where Name="'msiserver'")
For Each objService In colServices
If (objService.Started And Not objService.AcceptStop)
WScript.Echo "Another .MSI is running."
ElseIf ((objService.Started And objService.AcceptStop) Or Not objService.Started) Then
WScript.Echo "Ready to install an .MSI application."
Check = True
End If
Next
Loop