static internal ApplicationCrashedEventArgs InitOnce() { lock ( _lock ) { if (_oneCrashOnly != null) { return(null); } return(_oneCrashOnly = new ApplicationCrashedEventArgs(CrashLogManager.CreateNew())); } }
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); }