كيف يمكنني اختبار ما إذا كان هناك تثبيت آخر قيد التقدم بالفعل؟

StackOverflow https://stackoverflow.com/questions/140820

  •  02-07-2019
  •  | 
  •  

سؤال

بافتراض أنني أحاول أتمتة تثبيت شيء ما على نظام التشغيل Windows وأريد محاولة اختبار ما إذا كان هناك تثبيت آخر قيد التقدم قبل محاولة التثبيت.ليس لدي سيطرة على برنامج التثبيت ويجب أن أفعل ذلك في إطار التشغيل الآلي.هل هناك طريقة أفضل للقيام بذلك، بعض واجهات برمجة تطبيقات Win32؟، بدلاً من مجرد اختبار ما إذا كان msiexec قيد التشغيل؟

[التحديث 2]

لقد قمت بتحسين الكود السابق الذي كنت أستخدمه للوصول إلى كائن المزامنة (mutex) مباشرةً، وهو أكثر موثوقية بكثير:

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;
}
هل كانت مفيدة؟

المحلول

انظر الوصف _MSIExecute Mutex على MSDN.

نصائح أخرى

كنت أتلقى استثناءً غير معالج باستخدام الكود أعلاه.لقد أشرت إلى هذه المقالة مع هذا واحد

إليك الكود المحدث الخاص بي:

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

}

آسف لاختطاف مشاركتك!

لقد كنت أعمل على هذا - لمدة أسبوع تقريبًا - باستخدام ملاحظاتك (شكرًا لك) وذلك من مواقع أخرى - الكثير من الأسماء (شكرًا لكم جميعًا).

لقد عثرت على معلومات تكشف أن الخدمة يمكن أن تقدم معلومات كافية لتحديد ما إذا كانت خدمة MSIEXEC قيد الاستخدام بالفعل.الخدمة هي "msserver" - Windows Installer - ومعلوماتها هي الحالة والإيقاف.

يتحقق رمز VBScript التالي من ذلك.

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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top