问题:路径含 ( ) & % ! ^ @ 等字符时报"文件路径包含不允许的命令行特殊字符",
(D2-f)、(1) 这类正常业务文件名直接命中。
根因:读取统一入口把路径拼进命令行(cmd.exe /d /c type "..."),为"防炸"在 03d9b8b
引入 ForbiddenPathChars 黑名单——并非业务需求,是实现的自我约束。
实测:真正会坏的只有 %VAR%(必坏) 与延迟展开开启时的 !VAR!,而 ( ) & ^ @ 空格在
双引号内均正常;且 type 是字节透传,这层 cmd 对当初的编码问题毫无帮助。
改动:
- 新增 AnsiFileReader.cs:FileStream + StreamReader(默认 936 解码 + BOM 探测,
与旧 StreamReader 解码路径逐字符等价),不经命令行
- 删除 CommandTypeFileReader.cs 及其 ForbiddenPathChars 字符校验
- 路径只保留"非空"与"文件存在"校验;IO 异常包装为
InvalidOperationException("读取文件失败:{路径}({原因})")并保留 InnerException
- 15 处调用点同步改名;更新 CLAUDE.md 与 Docs 说明
验证:14 个 demo_drl 样例新旧实现字符串/行数逐字符一致;含特殊字符路径(含 %TEMP% 字面
路径,旧实现 rc=1)可读可解析;UTF-8/UTF-16 BOM 结果与旧实现一致;
dotnet build -p:Platform=x86 0 错误且警告集与基线逐条相同。
353 lines
14 KiB
C#
353 lines
14 KiB
C#
using System;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
|
||
namespace DrillTools
|
||
{
|
||
/// <summary>
|
||
/// Interaction logic for MainWindow.xaml
|
||
/// </summary>
|
||
public partial class MainWindow : Window
|
||
{
|
||
private MainWindowViewModel ViewModel => (MainWindowViewModel)DataContext;
|
||
|
||
public MainWindow(string? initialFilePath = null)
|
||
{
|
||
//System.Diagnostics.Debug.WriteLine("=== MainWindow构造函数开始执行 ===");
|
||
//System.Diagnostics.Debug.WriteLine($"参数 initialFilePath: {initialFilePath ?? "null"}");
|
||
|
||
try
|
||
{
|
||
//System.Diagnostics.Debug.WriteLine("调用 InitializeComponent()...");
|
||
InitializeComponent();
|
||
//System.Diagnostics.Debug.WriteLine("InitializeComponent() 执行完成");
|
||
|
||
//System.Diagnostics.Debug.WriteLine("创建 MainWindowViewModel...");
|
||
var viewModel = new MainWindowViewModel();
|
||
//System.Diagnostics.Debug.WriteLine("MainWindowViewModel 创建完成");
|
||
viewModel.IsStartupDrillTapeFile = !string.IsNullOrEmpty(initialFilePath);
|
||
|
||
//System.Diagnostics.Debug.WriteLine("设置 DataContext...");
|
||
DataContext = viewModel;
|
||
//System.Diagnostics.Debug.WriteLine("DataContext 设置完成");
|
||
|
||
//System.Diagnostics.Debug.WriteLine("初始化拖放功能...");
|
||
InitializeDragDrop();
|
||
//System.Diagnostics.Debug.WriteLine("拖放功能初始化完成");
|
||
|
||
// 如果有初始文件路径,在窗口加载完成后自动加载
|
||
if (!string.IsNullOrEmpty(initialFilePath))
|
||
{
|
||
//System.Diagnostics.Debug.WriteLine("注册文件加载事件...");
|
||
this.Loaded += (sender, e) => LoadInitialFile(initialFilePath, viewModel);
|
||
//System.Diagnostics.Debug.WriteLine("文件加载事件注册完成");
|
||
}
|
||
|
||
//System.Diagnostics.Debug.WriteLine("=== MainWindow构造函数执行完成 ===");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
//System.Diagnostics.Debug.WriteLine($"MainWindow构造函数中发生异常: {ex.GetType().Name} - {ex.Message}");
|
||
//System.Diagnostics.Debug.WriteLine($"异常堆栈: {ex.StackTrace}");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载初始文件
|
||
/// </summary>
|
||
/// <param name="filePath">文件路径</param>
|
||
/// <param name="viewModel">视图模型</param>
|
||
private async void LoadInitialFile(string filePath, MainWindowViewModel viewModel)
|
||
{
|
||
try
|
||
{
|
||
// 异步加载文件以避免阻塞UI
|
||
await System.Threading.Tasks.Task.Run(() =>
|
||
{
|
||
string drillTapeContent = AnsiFileReader.ReadAllText(filePath);
|
||
|
||
// 在UI线程中更新界面
|
||
this.Dispatcher.Invoke(() =>
|
||
{
|
||
try
|
||
{
|
||
// 保存原始文件路径
|
||
viewModel.IsStartupDrillTapeFile = true;
|
||
viewModel.OriginalFilePath = filePath;
|
||
|
||
// 加载钻带内容
|
||
viewModel.LoadToolsFromDrillTape(drillTapeContent);
|
||
|
||
// 显示成功提示
|
||
//System.Windows.MessageBox.Show(
|
||
// $"已成功加载钻带文件:\n{System.IO.Path.GetFileName(filePath)}\n\n刀具数量:{viewModel.Tools.Count}把",
|
||
// "文件加载完成",
|
||
// System.Windows.MessageBoxButton.OK,
|
||
// System.Windows.MessageBoxImage.Information);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.MessageBox.Show(
|
||
$"加载钻带文件失败:\n{ex.Message}",
|
||
"错误",
|
||
System.Windows.MessageBoxButton.OK,
|
||
System.Windows.MessageBoxImage.Error);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.MessageBox.Show(
|
||
$"读取文件时发生错误:\n{ex.Message}",
|
||
"错误",
|
||
System.Windows.MessageBoxButton.OK,
|
||
System.Windows.MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化拖放功能
|
||
/// </summary>
|
||
private void InitializeDragDrop()
|
||
{
|
||
DragDropHelper.EnableDragDrop<ToolItem>(ToolsListView, InsertionIndicator);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载示例数据按钮点击事件
|
||
/// </summary>
|
||
private void LoadSampleDataButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
ViewModel.LoadSampleData();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载钻带文件按钮点击事件
|
||
/// </summary>
|
||
private void LoadDrillTapeButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
var openFileDialog = new Microsoft.Win32.OpenFileDialog
|
||
{
|
||
Filter = "钻带文件 (*.txt;*.drl;*.dr2;*.dpin)|*.txt;*.drl;*.dr2;*.dpin|所有文件 (*.*)|*.*",
|
||
Title = "选择钻带文件"
|
||
};
|
||
|
||
if (openFileDialog.ShowDialog() == true)
|
||
{
|
||
try
|
||
{
|
||
// 保存原始文件路径
|
||
ViewModel.IsStartupDrillTapeFile = false;
|
||
ViewModel.OriginalFilePath = openFileDialog.FileName;
|
||
|
||
string drillTapeContent = AnsiFileReader.ReadAllText(openFileDialog.FileName);
|
||
|
||
ViewModel.LoadToolsFromDrillTape(drillTapeContent);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.MessageBox.Show($"加载钻带文件失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重排刀序按钮点击事件
|
||
/// </summary>
|
||
private void ReorderToolsButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
string reorderedDrillTape = ViewModel.ReorderAndRenumberTools();
|
||
ViewModel.DrillTapeContent = reorderedDrillTape;
|
||
System.Windows.MessageBox.Show("刀序重排完成", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
// 用户取消操作,不显示错误消息
|
||
//System.Diagnostics.Debug.WriteLine("用户取消了刀序重排操作");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.MessageBox.Show($"重排刀序失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用顺序到钻带按钮点击事件
|
||
/// </summary>
|
||
private void ApplyOrderButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
string reorderedDrillTape = ViewModel.ReorderAndRenumberTools(true);
|
||
ViewModel.DrillTapeContent = reorderedDrillTape;
|
||
System.Windows.MessageBox.Show("刀具顺序已应用到钻带", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
// 用户取消操作,不显示错误消息
|
||
//System.Diagnostics.Debug.WriteLine("用户取消了保存操作");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.MessageBox.Show($"应用刀具顺序失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 导出孔数报表按钮点击事件
|
||
/// </summary>
|
||
private void ExportDrillUsageReportButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
ViewModel.ExportDrillUsageReport();
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
return;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.MessageBox.Show($"导出孔数报表失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成 PP 钻带按钮点击事件
|
||
/// </summary>
|
||
private void GeneratePpDrillTapeButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
string outputFilePath = ViewModel.GeneratePpDrillTape();
|
||
System.Windows.MessageBox.Show($"PP钻带已生成:\n{outputFilePath}", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.MessageBox.Show($"生成PP钻带失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成排序种子按钮点击事件
|
||
/// </summary>
|
||
private void GenerateSortSeedButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
ViewModel.GenerateGeneralSortSeedFile(ViewModel.Tools);
|
||
System.Windows.MessageBox.Show("通用排序种子文件已生成", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
// 用户取消操作,不显示错误消息
|
||
//System.Diagnostics.Debug.WriteLine("用户取消了生成排序种子操作");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.MessageBox.Show($"生成排序种子失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 使用指定钻带的刀序按钮点击事件
|
||
/// </summary>
|
||
private void UseReferenceDrillTapeButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
ViewModel.ReorderToolsByReferenceDrillTape();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 使用指定种子的刀序按钮点击事件
|
||
/// </summary>
|
||
private void UseSortSeedButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
ViewModel.ReorderToolsBySortSeedFile();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试参考钻带功能按钮点击事件
|
||
/// </summary>
|
||
private void TestReferenceDrillTapeButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
ViewModel.TestReorderByReferenceDrillTape();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 上移按钮点击事件
|
||
/// </summary>
|
||
private void MoveUpButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
ViewModel.MoveSelectedToolUp();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 下移按钮点击事件
|
||
/// </summary>
|
||
private void MoveDownButton_Click(object sender, RoutedEventArgs e)
|
||
{
|
||
ViewModel.MoveSelectedToolDown();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 刀具列表双击事件
|
||
/// </summary>
|
||
private void ToolsListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||
{
|
||
if (sender is System.Windows.Controls.ListView listView && listView.SelectedItem is ToolItem selectedTool)
|
||
{
|
||
ViewModel.ShowToolDetail(selectedTool);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 拖放文件进入窗口事件
|
||
/// </summary>
|
||
protected override void OnDragEnter(System.Windows.DragEventArgs e)
|
||
{
|
||
if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop))
|
||
{
|
||
e.Effects = System.Windows.DragDropEffects.Copy;
|
||
}
|
||
else
|
||
{
|
||
e.Effects = System.Windows.DragDropEffects.None;
|
||
}
|
||
base.OnDragEnter(e);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 拖放文件到窗口事件
|
||
/// </summary>
|
||
protected override void OnDrop(System.Windows.DragEventArgs e)
|
||
{
|
||
if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop))
|
||
{
|
||
string[] files = (string[])e.Data.GetData(System.Windows.DataFormats.FileDrop);
|
||
if (files.Length > 0)
|
||
{
|
||
try
|
||
{
|
||
// 保存原始文件路径
|
||
ViewModel.IsStartupDrillTapeFile = false;
|
||
ViewModel.OriginalFilePath = files[0];
|
||
|
||
string drillTapeContent = AnsiFileReader.ReadAllText(files[0]);
|
||
|
||
ViewModel.LoadToolsFromDrillTape(drillTapeContent);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Windows.MessageBox.Show($"加载钻带文件失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
}
|
||
base.OnDrop(e);
|
||
}
|
||
}
|
||
}
|