FedericoBoccaccioPersonale/Programmi-HexEditorView

GitHub: FedericoBoccaccioPersonale/Programmi-HexEditorView

一个基于 VB.NET 8 的 WinForms 十六进制查看器用户控件,提供高性能的二进制数据分析和编辑能力,旨在弥补 ImHex 的功能局限。

Stars: 0 | Forks: 0

# Speciali\Hex Editor 视图 (UserControl VB.NET 8) ✨👨‍💻 🇮🇹 https://federicoboccaccio.wordpress.com/hex-editor-view-vb-net-8/ # 下载 [最新版本](https://github.com/FedericoBoccaccioPersonale/Programmi-HexEditorView/releases/latest) # 注意 你可以下载可执行文件来查看它的运行效果,但这是一个用户控件的示例。 这是一个面向其他开发者的项目,而不是一个可直接使用的程序。 # 信息 在 GitHub 上有主仓库,在 GitLab 上有用于备份的克隆版本。 # 📚 文档:HexEditorView - WinForms 十六进制查看器 ## 1. 目的与当前功能 `HexEditorView` 组件是一个为 .NET Windows Forms 定制的用户控件 (UserControl)。其目的是为原始数据文件提供高性能的十六进制和 ASCII 视图,旨在作为一个模块集成到更庞大的 WinForms 编辑器中。 最终目标是弥补 ImHex 的局限性(它无法实现其承诺的功能),但实际上它允许你分析和研究未知格式的二进制文件,识别标记,从而设置要显示的内容,或者自定义这个基础程序并将其集成到更大的项目中。 **已实现的主要功能:** * **三列逻辑视图:** 格式化的 Offset(例如 `0000 00A4`),16列十六进制字节,以及一列 ASCII。 * **Regex 引擎:** 自动高亮(可自定义文本颜色和背景色)被解析为 ASCII 文本的特定字节序列,允许直观地识别 pattern 或签名(例如 "PMOC")。 * **鼠标选择:** 通过拖放 进行流畅的选择,*仅*能在十六进制数据单元格上使用。 * **修改选择 (Shift+Click):** 智能修改现有选择,将逻辑上较近的端点移动到点击位置,同时保持另一端固定。 * **内置选择控件:** 控件现在拥有一个独立的底部面板,带有两个 `NumericUpDown` 用于手动设置十六进制的起始和结束字节,无需依赖外部控件。 * **状态栏(带解码):** 内置信息标签,实时显示选择的十进制和十六进制大小、起始和结束 Offset,并且如果选择在 1 到 8 字节之间,会**自动解码无符号整数值 (Little Endian)**。这个功能有待扩展,但就我目前的目的而言已经足够了。 * **序列搜索 (`TrovaSequenza`):** 内置函数,用于从当前选择位置开始搜索字节数组,并自动滚动视图至结果处。 * **零分配导出:** 公共事件 `SelezioneModificata` 通过 `ArraySegment(Of Byte)` 公开所选数据,将数组复制的内存开销降至零。 ### 额外功能 ## 2. 架构与实现 该控件基于原生的 `DataGridView` 控件,经过了大量的修改和“强化”,以实现底层编辑器的行为: * **Virtual Mode:** 数据不会加载到物理单元格中。`CellValueNeeded` 事件直接从加载到内存中的字节数组中读取,允许控件毫无延迟地处理庞大的数组。 * **基于 Sparse Dictionary 的 Regex 预处理:** 正则表达式的搜索不会在重绘期间的 runtime 进行。在加载期间,会生成一个名为 `_colorMap` 的 `Dictionary(Of Integer, ByteFormatting)`。与并行数组相比,字典仅为真正匹配 pattern 的字节分配内存,将无用的 RAM 消耗降至零。文本扫描进一步限制在安全区块(前 10 MB)内,以防止内存饱和。即使要搜索的字符串跨越多行,这也允许进行搜索。 * **原子赋值 (Zero-Loop):** 修改选择的起始和结束位置通过唯一的方法 `SetSelection(inizio, fine)` 完成。旧的写入属性已被移除,因为它们会触发双重触发和语义错误的内存状态。 * **渲染拦截:** `CellPainting` 事件覆盖了标准绘制。它手动绘制选择的背景、Regex 颜色,最重要的是,逐个渲染 ASCII 字符,以确保与 monospace font 完美对齐。 * **尺寸锁定:** 根据所选 `Consolas` 字体计算出的像素宽度,代码在数学上强制了列宽,并锁定了整个控件的 `MinimumSize` 和 `MaximumSize` 属性,防止界面变形。 * 属性 **MappingMode** 允许你选择如何显示非基本 ASCII 字符(Strict、Extended 或 ControlPictures Unicode)。 ## 3. 问题与解决历史 * **问题:** *滚动或拖动选择时的视觉闪烁。* * **解决方案:** 通过 *Reflection* 在 DataGridView 上启用 `DoubleBuffered` 属性,强制控件先在内存中绘制再显示到屏幕上。我认为强制使用 Reflection 是 NET 平台的一个设计错误。 * **问题:** *可见的原生选择。* DataGridView 默认会高亮点击的单元格(包括 Offset 和 ASCII 列),造成混乱。 * **解决方案:** 通过设置 `SelectionBackColor = Transparent` 在视觉上关闭它。此外,拦截 `SelectionChanged` 事件以持续强制执行 `ClearSelection()`。 * **问题:** *ASCII 列中的文本模糊或未对齐。* 默认系统 (`TextRenderer`) 会偏移 monospaced 字符,而纯 `Graphics.DrawString` 渲染在 Windows 11 上运行良好,但在 Windows 10 上会导致不准确 🤮。 * **解决方案:** 除了使用严格的 `StringFormat.GenericTypographic` 结构外,还在图形引擎上强制执行 `TextRenderingHint.ClearTypeGridFit` 属性,以强制像素在任何 OS 上完美对齐到屏幕网格。但不管怎样它在 Windows 10 上依然表现糟糕 🤮🤮🤮。 * **问题:** *文本重叠的视觉伪影。* 在使用 Shift 快速选择期间,某些字节看起来像是加粗或重叠了。 * **解决方案:** 在自定义绘制中插入显式调用 `e.PaintBackground`,强制系统在写入新状态之前“清除”单个单元格的画布。 * **问题:** *使用 Shift+Click 时选择收缩错误。* 在现有选择内部或附近点击时,逻辑会将两个端点都移动到点击的字节上。 * **解决方案:** 重构逻辑,引入**锚点**和**移动点**的概念。程序现在计算点击与选择边界之间的距离:将较远的端点固定为锚点,并使用点击的位置作为新的移动点。 * **问题:** DataGridView 在不需要时会隐藏滚动条,这会在右侧留下一个讨厌的空白矩形。 这是一个问题,因为它没有任何 ScrollBarsAlwaysVisible 属性。除了其他的基础工具之外。 由于我拒绝添加一个新组件叠加在真正的组件之上,它只能保持这样。还有一个问题是,如果没有鼠标悬停在上面,它会被画得很细。 * **解决方案:** 在 Paint 事件中使用原生 `ScrollBarRenderer` 类重绘 ScrollBar。遗憾的是,这并不能解决“现代”的视觉显示问题。 * **问题:** *从外部或内部 UI 修改选择时出现无限循环。* * **解决方案:** 界面 (NumericUpDown) 和后端之间的同步更新导致了无限递归。通过实现防循环标志 `_isUpdatingUI` 解决,该标志在同步值时临时停用事件。 * **问题:** *完全删除文件时崩溃 (Negative Index Exception)。* * **解决方案:** 将数据替换为最终大小为 0 时,指令 `Dim newData(-1)` 会导致软件崩溃。插入了一个 guard 捕获 `newTotalLen = 0`,并使用空数组 (`New Byte() {}`) 重新初始化控件,清理元数据。 * **问题:** *由于 Regex 导致处理 1GB 文件时内存耗尽。* 将 1GB 的二进制文件转换为 String 并创建并行数组会立即使 RAM 饱和。 * **解决方案:** (参见架构部分)。改用用于颜色的 *Sparse Dictionary*,并引入文本分析的安全限制 (`Math.Min(10MB)`)。 ## 4A. 数据操作(带复制) `HexEditorView` 控件已进行扩展,不仅支持可视化,还支持直接操作虚拟内存(字节数组)。引入了安全函数来提取和注入数据,动态管理主缓冲区大小的变化。 **已实现的方法:** * **`GetSelectedBytes() As Byte()`** * **目的:** 提取用户当前高亮选择的内存部分的独立副本。 * **行为:** 使用 `Array.Copy` 保证最高速度。它不会改变内存中的原始数组。如果没有活动选择,则返回空数组 (`Byte() {}`),避免空引用异常。 * **`ReplaceSelectedBytes(newBytes As Byte())`** * **目的:** 用作为参数提供的新 payload 替换高亮选择的数据。支持 overwrite(覆盖)、insert(插入)和 delete(删除/收缩)操作。 * **行为(自动处理的场景):** * **相同长度 (overwrite):** 如果 payload 与选择的大小相同,则执行就地复制 `O(N)`,无需重新分配底层数组,从而最大化性能。 * **不同长度 (Insert/Shrink):** 如果 payload 更大或更小,该方法会重新计算总大小(`Dimensione_Originale - Dimensione_Selezionata + Dimensione_Nuovi_Dati`)创建一个新 buffer,将替换块前后未修改的部分“粘贴”进去。 * 如果重新计算的大小达到 `0`,它会安全清空控件,防止出现与负数组限制相关的异常。 * **内部状态管理:** 每次替换操作后,控件会自动更新 `DataGridView` 的可视大小、NumericUpDown 的限制,重新计算整个 Regex 的颜色映射,并调整鼠标选择范围,以完美包裹刚刚插入的新数据。 ## 4B. 数据操作(无复制) `HexEditorView` 控件支持安全的数据提取和注入,保持优化的内存占用,并动态管理主缓冲区大小的变化。 **已实现的方法:** * **`GetSelectedBytesSenzaRiallocazione() As ArraySegment(Of Byte)`** * **目的:** 提供对当前高亮选择的内存部分的直接只读访问。 * **行为 (Zero-Allocation):** 它不创建新的内存数组并复制数据,而是返回一个 `ArraySegment(Of Byte)` 结构。它充当源 buffer (`_fileData`) 上的虚拟“窗口”,指示对底层数组的引用、起始 offset 和选择的长度。这完全消除了提取数据时的内存开销和 CPU 时间。如果没有活动的选择,则返回一个空 segment,可通过 `.Count = 0` 属性进行检查。 ## 5. 二进制搜索 (查找) 该控件包含一个基础的线性二进制 pattern 搜索引擎。 * **`TrovaSequenza(pattern As Byte())`** * **目的:** 从当前选择的末尾(如果无选择则从文件开头)开始定位特定的字节序列。 * **行为:** 遍历 buffer 比较元素。当识别出 pattern 时,通过原子方法 `SetSelection` 自动更新 `SelStartByte` 和 `SelEndByte`,并执行 `DataGridView` (`FirstDisplayedScrollingRowIndex`) 的自动滚动,将相关行显示在屏幕上。如果直到文件末尾都没有找到,则从索引 0 重新开始搜索。否则,显示一个信息 MessageBox。 * 评估一种新方法,该方法返回一对起始和结束值而不更新选择。当前方法将使用此新方法。 ## 相较于之前版本的修改 * 添加了搜索方法 * 改进了 Windows 10 上的显示 * 集成了高达 8 字节的 LitteEndian 十进制值查看器 * 集成了选择开始和结束的查看器/修改器(并移除了无限循环) * 支持(未经测试)大于 1GB 的文件
标签:多人体追踪