WPF App.OnStartup()与写入文件和FileWatcher崩溃

在处理使用Singleton实例模式的WPF应用程序来确保只有一个实例正在运行时,我有一个非常疯狂的问题。 然而,单实例检测和命令行转发机制工作正常,作为启动代码的一部分,该启动代码在辅助实例上退出,将文件写入磁盘,由主应用程序通过FileWatcher获取该文件。 次级实例经常因内核级错误而崩溃

检查辅助实例和随机崩溃的启动代码是这样做的:

  protected override void OnStartup(StartupEventArgs e) { bool isOnlyInstance = false; Mutex = new Mutex(true, @"MarkdownMonster", out isOnlyInstance); if (!isOnlyInstance) { filesToOpen = " "; var args = Environment.GetCommandLineArgs(); if (args != null && args.Length > 1) { StringBuilder sb = new StringBuilder(); for (int i = 1; i < args.Length; i++) { sb.AppendLine(args[i]); } filesToOpen = sb.ToString(); } File.WriteAllText(mmApp.Configuration.FileWatcherOpenFilePath, filesToOpen); Mutex.Dispose(); // This blows up when writing files and file watcher watching // No idea why - Environment.Exit() works with no issue ShutdownMode = ShutdownMode.OnMainWindowClose; App.Current.Shutdown(); return; } // ... } 

检查写入的文件的代码将加载到主窗体的构造函数中:

  openFileWatcher = new FileSystemWatcher( Path.GetDirectoryName(mmApp.Configuration.FileWatcherOpenFilePath), Path.GetFileName(mmApp.Configuration.FileWatcherOpenFilePath)) { NotifyFilter = NotifyFilters.LastWrite, EnableRaisingEvents = true }; openFileWatcher.Changed += openFileWatcher_Changed; openFileWatcher.Created += openFileWatcher_Changed; 

处理程序然后检查文件是这样的:

  private void openFileWatcher_Changed(object sender, FileSystemEventArgs e) { string filesToOpen = null; // due to write timing we may have to try a few times for (int i = 0; i < 100; i++) { try { if (File.Exists(mmApp.Configuration.FileWatcherOpenFilePath)) { filesToOpen = File.ReadAllText(mmApp.Configuration.FileWatcherOpenFilePath); File.Delete(mmApp.Configuration.FileWatcherOpenFilePath); filesToOpen = filesToOpen.TrimEnd(); } break; } catch { Thread.Sleep(10); } } Dispatcher.Invoke(() => { if (!string.IsNullOrEmpty(filesToOpen)) { foreach (var file in StringUtils.GetLines(filesToOpen)) { MessageBox.Show(file); this.OpenTab(file.Trim()); } } if (WindowState == WindowState.Minimized) WindowState = WindowState.Normal; this.Activate(); }); } 

所有这一切的逻辑工作正常。 应用程序正确检测到总是写出文件的辅助实例,并且第一个实例选取文件并激活/加载命令行中指定的文件。

但是,辅助实例崩溃难以解决的错误( AppDomain.UnhandledException事件挂钩,但不会触发),popup一个Windows错误对话框到桌面上。

二次装载大约有80%的时间是在启动的时候崩溃 – 这是不一致的,但是更频繁。

如果我删除File.WriteAllText()代码,不会发生崩溃。 如果我删除FileWatcher代码,不会发生崩溃。 如果两者都是活跃的: 繁荣 。 IOW,文件写入和FileWatcher都需要发生以便崩溃 – 如果一个不活动,则不会发生崩溃。 我尝试用try / catch包装File.WriteAllText()调用,但它不会被触发。 代码退出我的用户function后,发生故障,我似乎无法控制的错误。

其他古怪:

  • 在debugging下不会发生故障
  • 我无法从Windows崩溃附加debugging器
  • OnStartup()中的MessageBox.Show()只是闪烁MB(不是模态)

我也尝试用App.Current.Shutdown()replaceApp.Current.Shutdown()代码,这样更好 – 崩溃的频率要低得多,但是它们仍然有10%的时间发生。

当所有的辅助实例正在做的时候,什么可能导致应用程序的硬崩溃,将文件写出到磁盘?

UPDATE
所以事实certificate,崩溃问题根本与文件写入/ FileWatcher操作无关。 我创build了一个相同代码的NamedPipe版本,仍然看到失败。

事实certificate,真正的罪魁祸首是WPF用来在启动时向屏幕启动图像的SplashScreen 。 尽pipeWPF并不是一个完整的“窗口”,但是这个窗口是在一个新的线程上启动的,并且在SplashScreen线程完成之前完全初始化完成初始化之前closures,导致内核崩溃。 解决方法是:a)删除启animation面; b)手动pipe理启animation面,不要提前退出; c)在退出之前显式closures启animation面:

 SplashScreen.Close(TimeSpan.MinValue); Environment.Exit(0); 

我写了一篇博客文章,更详细地介绍了这个问题:

http://weblog.west-wind.com/posts/2016/May/13/Creating-Single-Instance-WPF-Applications-that-open-multiple-Files

尝试使用FileStream来代替,然后您可以确保使用FileStream.Flush关闭文件句柄

 using (FileStream fs = File.Create(mmApp.Configuration.FileWatcherOpenFilePath)) { byte[] info = new UTF8Encoding(true).GetBytes(filesToOpen); fs.Write(info, 0, info.Length); fs.Flush(); }