using System.Configuration; using System.Data; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Windows; using System.Collections.ObjectModel; namespace DrillTools { /// /// Interaction logic for App.xaml /// public partial class App : System.Windows.Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); RegisterShellContextMenu(); string? filePath = null; if (e.Args.Length > 0) { filePath = e.Args[0]; if (!IsValidDrillTapeFile(filePath)) filePath = null; } if (filePath == null) { ShowMainWindow(null); return; } // 防止选择窗口关闭后触发 OnLastWindowClose 导致应用退出 ShutdownMode = ShutdownMode.OnExplicitShutdown; // 只读取和解析文件一次,提取所有需要的信息 string content = CommandTypeFileReader.ReadAllText(filePath); var viewModel = new MainWindowViewModel { IsStartupDrillTapeFile = true, OriginalFilePath = filePath, ShouldCheckSortFileOnLoad = false }; viewModel.LoadToolsFromDrillTape(content); bool canClearParameters = DrillTapeParameterCleaner.CanClearParameters(content); bool canGeneratePpDrillTape = viewModel.CanGeneratePpDrillTape; string extension = Path.GetExtension(filePath).ToLowerInvariant(); bool canScaleDrillTape = extension == ".dr2" || extension == ".dpin"; double minDrill = viewModel.MinDrillDiameter; double minSlot = viewModel.MinSlotDiameter; double minEA = viewModel.MinEADiameter; bool isPpDrillTape = viewModel.IsPpDrillTape; double ppXSpacing = viewModel.PpXSpacing; double ppYSpacing = viewModel.PpYSpacing; bool hasOuter3175Spacing = viewModel.HasOuter3175Spacing; double outer3175XSpacing = viewModel.Outer3175XSpacing; double outer3175YSpacing = viewModel.Outer3175YSpacing; var selectionViewModel = new StartupSelectionViewModel { FileName = Path.GetFileNameWithoutExtension(filePath), MinDrillDiameter = minDrill, MinSlotDiameter = minSlot, MinEADiameter = minEA, IsPpDrillTape = isPpDrillTape, PpXSpacing = ppXSpacing, PpYSpacing = ppYSpacing, HasOuter3175Spacing = hasOuter3175Spacing, Outer3175XSpacing = outer3175XSpacing, Outer3175YSpacing = outer3175YSpacing }; // 叠板计算用的最小刀径独立遍历 Tools 计算,包含 0.749mm CalculateStackMinDiameters(viewModel.Tools, selectionViewModel); var selectionWindow = new StartupSelectionWindow( selectionViewModel, canClearParameters, canGeneratePpDrillTape, canScaleDrillTape); selectionWindow.ShowDialog(); switch (selectionWindow.SelectedAction) { case StartupAction.AdjustToolOrder: ShutdownMode = ShutdownMode.OnLastWindowClose; ShowMainWindow(filePath); break; case StartupAction.ExportHoleCount: PerformHeadlessExport(filePath); Shutdown(); break; case StartupAction.ClearParameters: PerformParameterCleanup(filePath); Shutdown(); break; case StartupAction.GeneratePpDrillTape: PerformPpDrillTapeGeneration(filePath); Shutdown(); break; case StartupAction.ScaleDrillTape: PerformDrillScaling(filePath); Shutdown(); break; default: Shutdown(); break; } } private static void ShowMainWindow(string? filePath) { try { MainWindow mainWindow = new MainWindow(filePath); mainWindow.Show(); } catch (Exception ex) { System.Windows.MessageBox.Show($"创建MainWindow时发生异常:\n{ex.GetType().Name} - {ex.Message}\n\n{ex.StackTrace}", "启动失败", MessageBoxButton.OK, MessageBoxImage.Error); throw; } } private static void PerformHeadlessExport(string filePath) { try { var viewModel = new MainWindowViewModel { ShouldCheckSortFileOnLoad = false }; string content = CommandTypeFileReader.ReadAllText(filePath); viewModel.OriginalFilePath = filePath; viewModel.LoadToolsFromDrillTape(content); if (viewModel.Tools.Count == 0) { System.Windows.MessageBox.Show("钻带文件中未找到有效的刀具数据,无法导出孔数报表。", "提示", MessageBoxButton.OK, MessageBoxImage.Warning); return; } viewModel.ExportDrillUsageReport(); } catch (OperationCanceledException) { } catch (Exception ex) { System.Windows.MessageBox.Show($"导出孔数报表失败:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } private static void PerformPpDrillTapeGeneration(string filePath) { try { var viewModel = new MainWindowViewModel { IsStartupDrillTapeFile = true, OriginalFilePath = filePath, ShouldCheckSortFileOnLoad = false }; string content = CommandTypeFileReader.ReadAllText(filePath); viewModel.LoadToolsFromDrillTape(content); string outputFilePath = viewModel.GeneratePpDrillTape(); System.Windows.MessageBox.Show( $"PP钻带已生成:\n{outputFilePath}", "生成PP钻带完成", MessageBoxButton.OK, MessageBoxImage.Information); } catch (Exception ex) { System.Windows.MessageBox.Show($"生成PP钻带失败:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } private static void PerformParameterCleanup(string filePath) { try { DrillTapeParameterCleaner.ClearParametersAndSave(filePath); System.Windows.MessageBox.Show( $"参数已清空,原文件已备份为:\n{Path.GetFileName(filePath)}.bak", "清空参数完成", MessageBoxButton.OK, MessageBoxImage.Information); } catch (Exception ex) { System.Windows.MessageBox.Show($"清空参数失败:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } private static void PerformDrillScaling(string filePath) { try { var scalingWindow = new DrillScalingWindow(); scalingWindow.ShowDialog(); if (scalingWindow.ScalingResult == null) return; var result = scalingWindow.ScalingResult.Value; string content = CommandTypeFileReader.ReadAllText(filePath); string scaledContent = Integration.ExcellonScaler.Scale(content, result.Kx, result.Ky); // 备份原文件 string backupFilePath = filePath + ".bak"; File.Copy(filePath, backupFilePath, true); // 写入缩放后的内容 using var writer = new StreamWriter(filePath, false, Encoding.GetEncoding(936)); writer.Write(scaledContent); // 系数记忆:紧跟钻带写回立即落盘,不滞后到完成提示之后。 // 属辅助功能,失败不回滚已完成的涨缩,失败原因随完成提示一并告知。 string? memoryWarning = null; try { ScalingProfileStore.Save(result.Mode, result.InputX, result.InputY, Path.GetFileName(filePath)); } catch (Exception ex) { memoryWarning = $"\n(系数记忆保存失败:{ex.Message})"; } string completionMessage = $"涨缩完成,原文件已备份为:\n{Path.GetFileName(filePath)}.bak"; if (memoryWarning != null) completionMessage += memoryWarning; System.Windows.MessageBox.Show( completionMessage, "涨缩完成", MessageBoxButton.OK, MessageBoxImage.Information); } catch (Exception ex) { System.Windows.MessageBox.Show($"涨缩失败:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); } } private static void RegisterShellContextMenu() { try { string exePath = Process.GetCurrentProcess().MainModule!.FileName!; string[] extensions = { ".drl", ".dr2", ".dr3", ".trg", ".dpin", ".txt" }; string menuText = "用DrillTools打开"; foreach (string ext in extensions) { string keyPath = $@"SystemFileAssociations\{ext}\shell\{menuText}\command"; using var key = Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(keyPath); key.SetValue("", $"\"{exePath}\" \"%1\""); } } catch { // 非管理员权限时注册可能失败,静默忽略不影响主功能 } } /// /// 验证是否为有效的钻带文件 /// /// 文件路径 /// 是否为有效钻带文件 private static bool IsValidDrillTapeFile(string filePath) { if (string.IsNullOrEmpty(filePath)) return false; if (!File.Exists(filePath)) return false; // 检查文件扩展名是否为支持的钻带文件格式 string extension = Path.GetExtension(filePath).ToLowerInvariant(); string[] supportedExtensions = { ".txt", ".drl", ".dr2", ".dr3", ".trg", ".dpin" }; return supportedExtensions.Contains(extension); } /// /// 从 MainWindowViewModel.Tools 独立遍历计算叠板用最小刀径。 /// 分类逻辑与 UpdateMinDiameterInfo 一致(按尾号使用标准),不排除 0.749mm; /// 特殊固定孔径(3.203 等)不参与叠板计算。 /// private static void CalculateStackMinDiameters( ObservableCollection tools, StartupSelectionViewModel selectionViewModel) { var (minDrill, minSlot, minEA) = ToolItem.CalculateMinDiameters(tools, exclude749ForDisplay: false); selectionViewModel.StackCalcMinDrill = minDrill; selectionViewModel.StackCalcMinSlot = minSlot; selectionViewModel.StackCalcMinEA = minEA; } } }