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;
}
¿Fue útil?

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top