Example #1
0
 static internal ApplicationCrashedEventArgs InitOnce()
 {
     lock ( _lock )
     {
         if (_oneCrashOnly != null)
         {
             return(null);
         }
         return(_oneCrashOnly = new ApplicationCrashedEventArgs(CrashLogManager.CreateNew()));
     }
 }
Example #2
0
        static public IDisposable Initialize(CKAppParameters app)
        {
            if (_params != null)
            {
                throw new InvalidOperationException("initonce");
            }
            _params = app;

            // This is the mutex used as a flag for installer.
            // Since it is "Global\", it is shared among multiple terminal services client.
            // We keep a reference on it. It will be released at the end of the process.
            Mutex mutextForInstaller = new Mutex(false, _params.GlobalMutexName);
            // This unique Application key is "local": it is not shared among terminal server connections.
            bool  isNew;
            Mutex mutex = new Mutex(true, @"Local\" + _params.LocalMutexName, out isNew);

            if (!isNew)
            {
                mutex.Dispose();
                return(null);
            }
            Debug.Assert(_params.ApplicationDataPath.EndsWith(@"\"));

            // This call also initializes the CrashLogManager subsystem.
            AppRecoveryManager.Initialize(_params.ApplicationDataPath + @"CrashLogs\");
            try
            {
                // Here is where handling any existing CrashLogDirectory must be processed.
                // If the logs are sent (or are to be sent), this directory must no more exist otherwise the user will
                // be prompted again next time the application runs.
                CrashLogManager.HandleExistingCrashLogs();

                // Handle existing updates after crash logs: this way the crash mechanism
                // can be updated!
                UpdateManager.Initialize(_params.CommonApplicationDataPath, _params.ApplicationDataPath);
                if (!UpdateManager.LaunchExistingUpdater())
                {
                    mutex.Dispose();
                    return(null);
                }
                return(mutex);
            }
            catch (Exception ex)
            {
                CrashLogManager.CreateNew().WriteLineException(ex);
                mutex.Dispose();
                return(null);
            }
        }
        /// <summary>
        /// Must be called once and only once.
        /// Registers the application for notification by windows of a failure if <see cref="IsOSRecoveryAvailable"/> is true.
        /// Initializes the <see cref="CrashLogManager"/> with the given directory.
        /// </summary>
        /// <returns>True if successfully registered for restart notification. False otherwise.</returns>
        /// <remarks>
        /// <para>
        /// The <see cref="AppDomain.CurrentDomain.UnhandledException"/> event is listened and react to such unhandled exceptions
        /// int two different ways: If <see cref="IsOSRecoveryAvailable"/> is true, the exception is memorized and will be dumped out
        /// to the crash log during application recovery. If it is false, this immediately triggers the <see cref="ApplicationCrashed"/>
        /// event.
        /// </para>
        /// <para>
        /// Windows forms is configured to let unhandled execptions be thrown thanks to a call to <see cref="Application.SetUnhandledExceptionMode"/> with <see cref="UnhandledExceptionMode.ThrowException"/>.
        /// </para>
        /// <para>
        /// This method also initializes the <see cref="CurrentCrashCount"/> from the <see cref="Environment.GetCommandLineArgs"/> (if any).
        /// </para>
        /// </remarks>
        public static bool Initialize(string crashLogDirectory)
        {
            CrashLogManager.Initialize(crashLogDirectory);
            Debug.Assert(_registeredExceptions == null, "Since CrashLogManager.Initialize above is called once and only once.");
            try
            {
                _registeredExceptions = new List <string>();
                AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
                System.Windows.Forms.Application.SetUnhandledExceptionMode(System.Windows.Forms.UnhandledExceptionMode.ThrowException);
                if (!CK.Core.OSVersionInfo.IsWindowsVistaOrGreater)
                {
                    return(_isOSRecoveryAvailable = false);
                }

                string[] args = Environment.GetCommandLineArgs();
                if (args != null && args.Length == 3 && args[1] == _crashcountParameterName)
                {
                    int.TryParse(args[2], out _crashCount);
                }
                // TODO: Parameters passing is far from perfect here. One should better reinject the current parameters and append the crash count.
                uint i = RecoveryFunctions.RegisterApplicationRestart(String.Format("{0} {1}", _crashcountParameterName, _crashCount + 1), RestartFlags.NONE);
                if (i == 0)
                {
                    // Hook the callback function.
                    _recoverCallback = new ApplicationRecoveryCallback(HandleApplicationCrashByOS);
                    IntPtr ptrOnApplicationCrash = Marshal.GetFunctionPointerForDelegate(_recoverCallback);
                    i = RecoveryFunctions.RegisterApplicationRecoveryCallback(ptrOnApplicationCrash, IntPtr.Zero, 50000, 0);
                    return(_isOSRecoveryAvailable = true);
                }
            }
            catch (Exception ex)
            {
                CrashLogManager.CreateNew().WriteLineException(ex);
            }
            return(false);
        }