HEX-Dump Control

    • C#
    • .NET (FX) 4.5–4.8

    Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von Facebamm.

      HEX-Dump Control

      Hallo :D

      Ich hab da ein kleines Control gezeichnet, welches mir den HexDump eines Buffers anzeigt :D

      #Feature
      Strg-A - Markiert alles
      Strg-C - Kopiert den Hex-Code
      Strg-D - Entfernt alle markierungen

      Page Up-Down - Scrollt eine page runter oder hoch
      Pfeil-Tasten sind supportet.
      Scrollen per maus

      #Bugs
      Scrollbar an der Seite - fixed from @RodFromGermany

      # Quellcode - 04/11/2020 - 14:12
      Spoiler anzeigen

      Quellcode

      1. using System;
      2. using System.Windows.Forms;
      3. using System.Runtime.InteropServices;
      4. using System.Drawing;
      5. using System.Drawing.Drawing2D;
      6. using System.ComponentModel;
      7. using System.Linq;
      8. using System.Threading;
      9. using System.Collections.Generic;
      10. using System.Runtime.CompilerServices;
      11. using System.Threading.Tasks;
      12. namespace _7dbg.UI
      13. {
      14. /*
      15. TODO:
      16. Scrollbar [/]
      17. Scrollen [x]
      18. Keys:
      19. Copy (STRG-C), [x]
      20. Select all (STRG-A), [x]
      21. Deselect all (STRG-D) [x]
      22. Number-Hover [x]
      23. Change
      24. Convert
      25. Suchen
      26. Mark [/]
      27. */
      28. [Docking(DockingBehavior.Ask)]
      29. class HexDump : Control
      30. {
      31. private static string s_offsetMask = IntPtr.Size == 4 ? "0x{0:X08}" : "0x{0:X016}";
      32. private static char[] s_asciiTable = new char[]
      33. {
      34. '.','.','.','.','.','.','.','.','.','.',
      35. '.','.','.','.','.','.','.','.','.','.',
      36. '.','.','.','.','.','.','.','.','.','.',
      37. '.','.','.','!','"','#','$','%','&','\'',
      38. '(',')','*','+',',','-','.','/','0','1',
      39. '2','3','4','5','6','7','8','9',':',';',
      40. '<','=','>','?','@','A','B','C','D','E',
      41. 'F','G','H','I','J','K','L','M','N','O',
      42. 'P','Q','R','S','T','U','V','W','X','Y',
      43. 'Z','[','\\',']','^','_','`','a','b','c',
      44. 'd','e','f','g','h','i','j','k','l','m',
      45. 'n','o','p','q','r','s','t','u','v','w',
      46. 'x','y','z','{','|','}','~','.','€','.',
      47. '‚','ƒ','„','…','†','‡','ˆ','‰','Š','‹',
      48. 'Œ','.','Ž','.','.','‘','’','“','”','•',
      49. '–','—','˜','™','š','›','œ','.','ž','Ÿ',
      50. ' ','¡','¢','£','¤','¥','¦','§','¨','©',
      51. 'ª','«','¬','.','®','¯','°','±','²','³',
      52. '´','µ','¶','·','¸','¹','º','»','¼','½',
      53. '¾','¿','À','Á','Â','Ã','Ä','Å','Æ','Ç',
      54. 'È','É','Ê','Ë','Ì','Í','Î','Ï','Ð','Ñ',
      55. 'Ò','Ó','Ô','Õ','Ö','×','Ø','Ù','Ú','Û',
      56. 'Ü','Ý','Þ','ß','à','á','â','ã','ä','å',
      57. 'æ','ç','è','é','ê','ë','ì','í','î','ï',
      58. 'ð','ñ','ò','ó','ô','õ','ö','÷','ø','ù', // 240
      59. 'ú','û','ü','ý','þ','ÿ','Ā', // 250
      60. };
      61. #region Control Props
      62. // Later user
      63. private int _height;
      64. private int _width;
      65. #endregion
      66. private Color _DefaultSelectionBackground = Color.Transparent;
      67. private Color _SelectionBackground = Color.DodgerBlue;
      68. /// <summary>
      69. /// background color from seleted text
      70. /// </summary>
      71. public Color SelectionBackground
      72. {
      73. get => _SelectionBackground;
      74. set
      75. {
      76. if (_SelectionBackground == value) return;
      77. _SelectionBackground = value;
      78. Invalidate();
      79. }
      80. }
      81. #region Offset
      82. /// <summary>
      83. /// true: show the offset on left side. Otherwise hide the offset
      84. /// </summary>
      85. private bool _isOffsetEnabled;
      86. /// <summary>
      87. /// true: show the offset on left side. Otherwise hide the offset
      88. /// </summary>
      89. [Category("Layout")]
      90. public bool OffsetEnabled
      91. {
      92. get => _isOffsetEnabled;
      93. set
      94. {
      95. if (_isOffsetEnabled == value) return;
      96. _isOffsetEnabled = value;
      97. CalcXArea();
      98. Invalidate();
      99. }
      100. }
      101. /// <summary>
      102. /// The left and right space from offset text
      103. /// </summary>
      104. private (int Left, int Right) _offsetAreaPadding = (0, 8);
      105. /// <summary>
      106. /// The left and right space from offset text
      107. /// </summary>
      108. [Category("Layout")]
      109. public (int Left, int Right) OffsetAreaPadding
      110. {
      111. get => _offsetAreaPadding;
      112. set
      113. {
      114. if (_offsetAreaPadding.Left == Left && _offsetAreaPadding.Right == Right) return;
      115. _offsetAreaPadding = value;
      116. CalcXArea();
      117. Invalidate();
      118. }
      119. }
      120. #endregion
      121. private Color _selectedByteColor = Color.LimeGreen;
      122. /// <summary>
      123. /// max line displayable
      124. /// </summary>
      125. private int _lines;
      126. /// <summary>
      127. /// text size from a single hex value
      128. /// </summary>
      129. private Size _byteSize;
      130. /// <summary>
      131. /// text size from the offset text
      132. /// </summary>
      133. private Size _offsetAreaSize;
      134. /// <inheritdoc/>
      135. public override Font Font
      136. {
      137. get => base.Font;
      138. set
      139. {
      140. if (base.Font == value) return;
      141. base.Font = value;
      142. _asciiSize = TextRenderer.MeasureText(" ", Font);
      143. _byteSize = TextRenderer.MeasureText(" ", Font);
      144. _offsetAreaSize = TextRenderer.MeasureText(string.Format(s_offsetMask, 0), Font);
      145. CalcLinesPerPage();
      146. CalcXByteAreaWidth();
      147. CalcXArea();
      148. Invalidate();
      149. }
      150. }
      151. /// <summary>
      152. /// Data to display
      153. /// </summary>
      154. private byte[] _buffer;
      155. /// <summary>
      156. /// Handle to pinned data in memory
      157. /// </summary>
      158. private GCHandle _bufferHandle;
      159. /// <summary>
      160. /// Ptr to the pinned data in memory
      161. /// </summary>
      162. private IntPtr _bufferPtr;
      163. /// <summary>
      164. /// Offset for data to display
      165. /// </summary>
      166. private int _bufferOffset = 0;
      167. /// <summary>
      168. /// Start Offset for displaying bytes
      169. /// </summary>
      170. public int Offset
      171. {
      172. get => _bufferOffset;
      173. set
      174. {
      175. if (_bufferOffset == value) return;
      176. if (value >= Buffer.Length) throw new ArgumentOutOfRangeException("The offset must be smaller than the buffer length");
      177. if (value < 0) throw new ArgumentOutOfRangeException("The offset must be greater or equal to 0");
      178. _bufferOffset = value;
      179. Invalidate();
      180. }
      181. }
      182. /// <summary>
      183. /// Data to display
      184. /// </summary>
      185. [Category("Data")]
      186. public byte[] Buffer
      187. {
      188. get => _buffer;
      189. set
      190. {
      191. _buffer = value;
      192. if (_bufferHandle.IsAllocated) _bufferHandle.Free();
      193. _bufferHandle = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
      194. _bufferPtr = _bufferHandle.AddrOfPinnedObject();
      195. CalcScrollbar();
      196. Invalidate();
      197. }
      198. }
      199. #region Dump
      200. /// <summary>
      201. /// start point for drawing the center area (byte display area)
      202. /// </summary>
      203. private int _xByteAreaOffset;
      204. /// <summary>
      205. /// the width from the center area (byte display area)
      206. /// </summary>
      207. private int _xByteAreaWidth;
      208. /// <summary>
      209. /// the current byte where mouse is hovered - lates
      210. /// </summary>
      211. private byte? _selectedByteValue;
      212. /// <summary>
      213. /// Bytes to displayed in a row
      214. /// </summary>
      215. private int _displayesBytes = 15;
      216. /// <summary>
      217. /// Bytes to displayed in a row
      218. /// </summary>
      219. [Category("Layout")]
      220. public int DisplayedBytes
      221. {
      222. get => _displayesBytes;
      223. set
      224. {
      225. if (_displayesBytes == value) return;
      226. if (value == 0) throw new ArgumentNullException(nameof(DisplayedBytes));
      227. _displayesBytes = value;
      228. CalcXByteAreaWidth();
      229. CalcXArea();
      230. CalcScrollbar();
      231. Invalidate();
      232. }
      233. }
      234. /// <summary>
      235. /// The left and right space from offset text
      236. /// </summary>
      237. private (int Left, int Right) _byteAreaPadding = (8, 8);
      238. /// <summary>
      239. /// The left and right space from offset text
      240. /// </summary>
      241. [Category("Layout")]
      242. public (int Left, int Right) BytePadding
      243. {
      244. get => _offsetAreaPadding;
      245. set
      246. {
      247. if (_byteAreaPadding.Left == Left && _byteAreaPadding.Right == Right) return;
      248. _byteAreaPadding = value;
      249. CalcXArea();
      250. Invalidate();
      251. }
      252. }
      253. #endregion
      254. #region Ascii
      255. /// <summary>
      256. /// size from a single ascii char
      257. /// </summary>
      258. private Size _asciiSize;
      259. /// <summary>
      260. /// start point for drawing the right area (ascii display area)
      261. /// </summary>
      262. private int _xAsciiAreaOffset;
      263. /// <summary>
      264. /// the width from the right area (ascii display area)
      265. /// </summary>
      266. private int _xAsciiAreaWidth;
      267. /// <summary>
      268. /// true: show the offset on right side. Otherwise hide the offset
      269. /// </summary>
      270. private bool _isAsciiEnabled;
      271. /// <summary>
      272. /// true: show the offset on right side. Otherwise hide the offset
      273. /// </summary>
      274. [Category("Layout")]
      275. public bool AsciiEnabled
      276. {
      277. get => _isAsciiEnabled;
      278. set
      279. {
      280. if (_isAsciiEnabled == value) return;
      281. _isAsciiEnabled = value;
      282. CalcXArea();
      283. Invalidate();
      284. }
      285. }
      286. /// <summary>
      287. /// The left and right space from offset text
      288. /// </summary>
      289. private (int Left, int Right) _AsciiAreaPadding = (8, 0);
      290. /// <summary>
      291. /// The left and right space from offset text
      292. /// </summary>
      293. [Category("Layout")]
      294. public (int Left, int Right) AsciiPadding
      295. {
      296. get => _offsetAreaPadding;
      297. set
      298. {
      299. if (_AsciiAreaPadding.Left == Left && _AsciiAreaPadding.Right == Right) return;
      300. _AsciiAreaPadding = value;
      301. CalcXArea();
      302. Invalidate();
      303. }
      304. }
      305. #endregion
      306. #region Scrollbar
      307. /// <summary>
      308. /// Descript if the content longer then the client can display
      309. /// </summary>
      310. private bool _isScrollbarNeeded;
      311. /// <summary>
      312. /// The client height - the thumb height
      313. /// </summary>
      314. private int _scrollArea;
      315. /// <summary>
      316. /// Byte to overjump by a single pixel scroll (up/down).
      317. /// </summary>
      318. private int _scrollSteps;
      319. /// <summary>
      320. /// the current y position from the thumb
      321. /// </summary>
      322. private int _scrollbarThumbY = 0;
      323. /// <summary>
      324. /// the final height of the thumb
      325. /// </summary>
      326. private int _scrollbarThumbHeight;
      327. /// <summary>
      328. /// the background color for the scrollbar
      329. /// </summary>
      330. private Color _scrollbarBackground = Color.FromArgb(30, 30, 30);
      331. /// <summary>
      332. /// the background brush for the scrollbar
      333. /// </summary>
      334. private SolidBrush _scrollbarBackgroundBrush = new SolidBrush(Color.FromArgb(30, 30, 30));
      335. /// <summary>
      336. /// Background color for the scrollbar
      337. /// </summary>
      338. [Category("Layout")]
      339. public Color ScrollBarBackground
      340. {
      341. get => _scrollbarBackground;
      342. set
      343. {
      344. if (_scrollbarBackground == value) return;
      345. _scrollbarBackground = value;
      346. Interlocked.Exchange(ref _scrollbarBackgroundBrush, new SolidBrush(_scrollbarBackground))?.Dispose();
      347. Invalidate();
      348. }
      349. }
      350. /// <summary>
      351. /// the foreground color for the scrollbar
      352. /// </summary>
      353. private Color _scrollbarForeground = Color.FromArgb(55, 55, 55);
      354. /// <summary>
      355. /// the foreground brush for the scrollbar
      356. /// </summary>
      357. private SolidBrush _scrollbarForegroundBrush = new SolidBrush(Color.FromArgb(55, 55, 55));
      358. /// <summary>
      359. /// Foreground color for the scrollbar
      360. /// </summary>
      361. [Category("Layout")]
      362. public Color ScrollBarForeground
      363. {
      364. get => _scrollbarForeground;
      365. set
      366. {
      367. if (_scrollbarForeground == value) return;
      368. _scrollbarForeground = value;
      369. Interlocked.Exchange(ref _scrollbarForegroundBrush, new SolidBrush(_scrollbarForeground))?.Dispose();
      370. Invalidate();
      371. }
      372. }
      373. /// <summary>
      374. /// Width from the scrollbar
      375. /// </summary>
      376. private int _scollbarWidth = 10;
      377. /// <summary>
      378. /// Width from the scrollbar
      379. /// </summary>
      380. [Category("Layout")]
      381. public int ScrollbarWidth
      382. {
      383. get => _scollbarWidth;
      384. set
      385. {
      386. if (_scollbarWidth == value) return;
      387. _scollbarWidth = value;
      388. Invalidate();
      389. }
      390. }
      391. /// <summary>
      392. /// min height from the scrollbar thumb
      393. /// </summary>
      394. private int _scrollbarThumbMinHeight = 30;
      395. /// <summary>
      396. /// Min height from the scrollbar thumb
      397. /// </summary>
      398. [Category("Layout")]
      399. public int ScrollbarThumbMinHeight
      400. {
      401. get => _scrollbarThumbMinHeight;
      402. set
      403. {
      404. if (_scrollbarThumbMinHeight == value) return;
      405. _scrollbarThumbMinHeight = value;
      406. Invalidate();
      407. }
      408. }
      409. #endregion
      410. #region Key Handling
      411. private bool _mouseOnScrollbarThumb = false;
      412. private int _mouseClickYOnScollbar = 0;
      413. private int? _selectionStartOffset;
      414. private int? _selectionEndOffset;
      415. private bool _mouseOnByteArea = false;
      416. private bool _mouseOnAsciiArea = false;
      417. #endregion
      418. public HexDump()
      419. {
      420. SetStyle(ControlStyles.UserPaint
      421. | ControlStyles.OptimizedDoubleBuffer
      422. | ControlStyles.Selectable
      423. | ControlStyles.UserMouse
      424. | ControlStyles.ResizeRedraw,
      425. true);
      426. SuspendLayout();
      427. Font = new Font(FontFamily.GenericMonospace, 10, FontStyle.Regular);
      428. BackColor = Color.FromArgb(45, 45, 45);
      429. ForeColor = Color.Silver;
      430. Buffer = Enumerable.Range(0, 500).Select(x => (byte)x).ToArray();
      431. ResumeLayout(false);
      432. }
      433. protected override void OnKeyDown(KeyEventArgs e)
      434. {
      435. if (e.KeyCode == Keys.C && e.Control)
      436. {
      437. if (_selectionStartOffset.HasValue && _selectionEndOffset.HasValue)
      438. {
      439. IEnumerable<byte> copyBuffer = Buffer.Skip(_selectionStartOffset.Value)
      440. .Take(_selectionEndOffset.Value - _selectionStartOffset.Value);
      441. string copyCode = string.Join(" ", copyBuffer.Select(x => x.ToString("X2")));
      442. Clipboard.SetText(copyCode);
      443. }
      444. }
      445. if (e.KeyCode == Keys.A && e.Control)
      446. {
      447. _selectionStartOffset = 0;
      448. _selectionEndOffset = Buffer.Length;
      449. }
      450. if (e.KeyCode == Keys.D && e.Control)
      451. {
      452. if (_selectionStartOffset.HasValue && _selectionEndOffset.HasValue)
      453. {
      454. _selectionStartOffset = null;
      455. _selectionEndOffset = null;
      456. }
      457. }
      458. if (e.KeyCode == Keys.Home)
      459. {
      460. Offset = 0;
      461. }
      462. if (e.KeyCode == Keys.End)
      463. {
      464. Offset = Buffer.Length - (int)(_lines * .5);
      465. }
      466. }
      467. protected override void OnMouseDown(MouseEventArgs e)
      468. {
      469. if (e.Button == MouseButtons.Left)
      470. {
      471. if (Width - _scollbarWidth <= e.X
      472. && e.X <= Width
      473. && _scrollbarThumbY <= e.Y
      474. && e.Y <= _scrollbarThumbY + _scrollbarThumbHeight)
      475. {
      476. _mouseClickYOnScollbar = e.Y - _scrollbarThumbY;
      477. _mouseOnScrollbarThumb = true;
      478. }
      479. else if (_xByteAreaOffset <= e.X && e.X <= _xByteAreaOffset + _xByteAreaWidth)
      480. {
      481. _mouseOnByteArea = true;
      482. _selectionStartOffset = GetByteOffset(e.X, e.Y);
      483. _selectionEndOffset = null;
      484. }
      485. else if (_xAsciiAreaOffset <= e.X && e.X <= _xAsciiAreaOffset + _xAsciiAreaWidth)
      486. {
      487. _mouseOnAsciiArea = true;
      488. }
      489. }
      490. }
      491. protected override void OnMouseMove(MouseEventArgs e)
      492. {
      493. if (_mouseOnScrollbarThumb)
      494. {
      495. _scrollbarThumbY = e.Y - _mouseClickYOnScollbar;
      496. if (_scrollbarThumbY < 0)
      497. {
      498. _scrollbarThumbY = 0;
      499. }
      500. if (_scrollbarThumbY > Height - _scrollbarThumbMinHeight)
      501. {
      502. _scrollbarThumbY = Height - _scrollbarThumbMinHeight;
      503. }
      504. CalcScrollingFromPosition();
      505. Invalidate();
      506. }
      507. else if (_xByteAreaOffset <= e.X && e.X <= _xByteAreaOffset + _xByteAreaWidth)
      508. {
      509. if (_bufferHandle.IsAllocated)
      510. {
      511. int hoveredByteOffset = GetByteOffset(e.X, e.Y);
      512. if (hoveredByteOffset < 0)
      513. {
      514. hoveredByteOffset = 0;
      515. }
      516. else if (hoveredByteOffset > Buffer.Length)
      517. {
      518. hoveredByteOffset = Buffer.Length;
      519. }
      520. _selectedByteValue = Marshal.ReadByte(_bufferPtr + hoveredByteOffset);
      521. if (_selectionStartOffset.HasValue && _mouseOnByteArea)
      522. {
      523. _selectionEndOffset = GetByteOffset(e.X, e.Y);
      524. }
      525. }
      526. Invalidate();
      527. return;
      528. }
      529. }
      530. protected override void OnMouseUp(MouseEventArgs e)
      531. {
      532. if (e.Button == MouseButtons.Left)
      533. {
      534. if (_mouseOnScrollbarThumb)
      535. {
      536. _mouseOnScrollbarThumb = false;
      537. }
      538. if (_mouseOnByteArea)
      539. {
      540. if (_selectionStartOffset.HasValue)
      541. {
      542. _selectionEndOffset = GetByteOffset(e.X, e.Y);
      543. }
      544. _mouseOnByteArea = false;
      545. }
      546. if (_mouseOnAsciiArea)
      547. {
      548. _mouseOnAsciiArea = false;
      549. }
      550. }
      551. }
      552. protected override void OnMouseWheel(MouseEventArgs e)
      553. {
      554. if (e.Delta > 0)
      555. {
      556. _bufferOffset -= 16;
      557. if (_bufferOffset < 0)
      558. {
      559. _bufferOffset = 0;
      560. }
      561. }
      562. else if (e.Delta < 0)
      563. {
      564. _bufferOffset += 16;
      565. if (_bufferOffset > Buffer.Length)
      566. {
      567. _bufferOffset = Buffer.Length;
      568. }
      569. }
      570. Invalidate();
      571. }
      572. protected override void OnSizeChanged(EventArgs e)
      573. {
      574. CalcLinesPerPage();
      575. CalcScrollbar();
      576. base.OnSizeChanged(e);
      577. _height = Height;
      578. _width = Width;
      579. }
      580. protected override void OnPaint(PaintEventArgs e)
      581. {
      582. if (_bufferPtr == IntPtr.Zero) return;
      583. e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
      584. //e.Graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
      585. int xAreaOffset = 0;
      586. int bufferOffset = _bufferOffset;
      587. IntPtr bufferPtr = _bufferPtr;
      588. int? selectionStart = _selectionStartOffset;
      589. int? selectionEnd = _selectionEndOffset;
      590. bool selectionAvailable = selectionStart.HasValue && selectionEnd.HasValue;
      591. // check if selection available, true -> order
      592. if (selectionAvailable)
      593. {
      594. if (selectionEnd < selectionStart)
      595. {
      596. int? selectionTmpBuffer = selectionStart;
      597. selectionStart = selectionEnd;
      598. selectionEnd = selectionTmpBuffer;
      599. }
      600. }
      601. for (int iLine = 0; iLine < _lines + 1; iLine++)
      602. {
      603. if (bufferOffset >= _buffer.Length) break;
      604. DrawAtOffsetArea(e.Graphics, _offsetAreaPadding.Left, xAreaOffset, bufferOffset);
      605. int xByteAreaOffset = _xByteAreaOffset;
      606. int xAsciiAreaOffset = _xAsciiAreaOffset;
      607. for (int i = 0; i < _displayesBytes; i++)
      608. {
      609. byte value = Marshal.ReadByte(bufferPtr + bufferOffset);
      610. //byte value = _buffer[bufferOffset];
      611. string hexValue = value.ToString("X2");
      612. Color bgrColor = selectionAvailable
      613. && bufferOffset >= selectionStart.Value
      614. && bufferOffset <= selectionEnd.Value
      615. ? _SelectionBackground
      616. : _DefaultSelectionBackground;
      617. if (_selectedByteValue.HasValue && value == _selectedByteValue)
      618. {
      619. DrawAtByteArea(e.Graphics, xByteAreaOffset, xAreaOffset, _selectedByteColor, bgrColor, hexValue);
      620. DrawAtAsciiArea(e.Graphics, xAsciiAreaOffset, xAreaOffset, _selectedByteColor, bgrColor, s_asciiTable[value].ToString());
      621. }
      622. else
      623. {
      624. DrawAtByteArea(e.Graphics, xByteAreaOffset, xAreaOffset, ForeColor, bgrColor, hexValue);
      625. DrawAtAsciiArea(e.Graphics, xAsciiAreaOffset, xAreaOffset, ForeColor, bgrColor, s_asciiTable[value].ToString());
      626. }
      627. xByteAreaOffset += _byteSize.Width;
      628. xAsciiAreaOffset += _asciiSize.Width / 2;
      629. bufferOffset += 1;
      630. }
      631. xAreaOffset += _byteSize.Height;
      632. }
      633. if (_isScrollbarNeeded)
      634. {
      635. int xScrollbarOffset = Width - _scollbarWidth;
      636. e.Graphics.FillRectangle(_scrollbarBackgroundBrush, xScrollbarOffset, 0, _scollbarWidth, Height);
      637. e.Graphics.FillRectangle(_scrollbarForegroundBrush, xScrollbarOffset, _scrollbarThumbY, _scollbarWidth, _scrollbarThumbHeight);
      638. }
      639. }
      640. private void DrawAtOffsetArea(Graphics e, int xOffset, int yOffset, int value)
      641. {
      642. if (_isOffsetEnabled)
      643. {
      644. TextRenderer.DrawText(e, string.Format(s_offsetMask, value), Font, new Point(xOffset, yOffset), ForeColor, TextFormatFlags.Left);
      645. }
      646. }
      647. private void DrawAtByteArea(Graphics e, int xOffset, int yOffset, Color foreColor, Color backColor, string valueStrg)
      648. {
      649. TextRenderer.DrawText(e, valueStrg, Font, new Point(xOffset, yOffset), foreColor, backColor, TextFormatFlags.Left);
      650. }
      651. private void DrawAtAsciiArea(Graphics e, int xOffset, int yOffset, Color foreColor, Color backColor, string value)
      652. {
      653. if (_isAsciiEnabled)
      654. {
      655. TextRenderer.DrawText(e, value, Font, new Point(xOffset, yOffset), foreColor, backColor, TextFormatFlags.Left);
      656. }
      657. }
      658. private void CalcLinesPerPage()
      659. {
      660. _lines = Height / _byteSize.Height;
      661. CalcScrollbar();
      662. }
      663. private void CalcScrollbar()
      664. {
      665. if (_bufferHandle.IsAllocated)
      666. {
      667. _isScrollbarNeeded = Buffer.Length / _displayesBytes / _byteSize.Height > _lines;
      668. if (_isScrollbarNeeded)
      669. {
      670. // buffer.Length / _displayesBytes = maxlines => maxlines * _byteSize.Height = maxHeight
      671. int dumpHeightInPx = Buffer.Length / _displayesBytes * _byteSize.Height;
      672. _scrollbarThumbHeight = Height / dumpHeightInPx;
      673. if (_scrollbarThumbHeight < _scrollbarThumbMinHeight)
      674. {
      675. _scrollbarThumbHeight = _scrollbarThumbMinHeight;
      676. }
      677. int newScrollArea = Height - _scrollbarThumbHeight;
      678. if (_scrollArea != 0)
      679. {
      680. _scrollSteps = Buffer.Length / newScrollArea;
      681. _scrollbarThumbY = (int)Map(_scrollbarThumbY, 0, _scrollArea, 0, newScrollArea);
      682. }
      683. else
      684. {
      685. _scrollSteps = Buffer.Length / newScrollArea;
      686. }
      687. _scrollArea = newScrollArea;
      688. }
      689. }
      690. }
      691. private void CalcScrollingFromPosition()
      692. {
      693. _bufferOffset = _scrollSteps * _scrollbarThumbY;
      694. }
      695. private void CalcXArea()
      696. {
      697. _xByteAreaOffset = _isOffsetEnabled
      698. ? _offsetAreaPadding.Left + _offsetAreaSize.Width + _offsetAreaPadding.Right + /* 1 + */ _byteAreaPadding.Left
      699. : _xByteAreaOffset = _byteAreaPadding.Left;
      700. if (_isAsciiEnabled)
      701. {
      702. _xAsciiAreaOffset = _xByteAreaOffset + _xByteAreaWidth + _byteAreaPadding.Right + AsciiPadding.Left;
      703. _xAsciiAreaWidth = (int)(_asciiSize.Width * _displayesBytes * .5);
      704. }
      705. }
      706. private void CalcXByteAreaWidth()
      707. {
      708. _xByteAreaWidth = _displayesBytes * _byteSize.Width;
      709. }
      710. private int GetByteOffset(int mouseX, int mouseY)
      711. {
      712. int itemY = mouseY / _byteSize.Height;
      713. int itemX = ((mouseX - _xByteAreaOffset) / _byteSize.Width);
      714. return (itemY * _displayesBytes) + itemX + _bufferOffset;
      715. }
      716. private double Map(double value, double start1, double stop1, double start2, double stop2, bool withinBounds = true)
      717. {
      718. double newValue = (value - start1) / (stop1 - start1) * (stop2 - start2) + start2;
      719. if (!withinBounds)
      720. {
      721. return newValue;
      722. }
      723. if (start2 < stop2)
      724. {
      725. return Constrain(newValue, start2, stop2);
      726. }
      727. else
      728. {
      729. return Constrain(newValue, stop2, start2);
      730. }
      731. }
      732. private double Constrain(double n, double low, double high)
      733. {
      734. return System.Math.Max(System.Math.Min(n, high), low);
      735. }
      736. public bool FindFirst(byte[] src, out int? offset, int startOffset = 0, int endOffset = -1, bool failChecks = true)
      737. {
      738. InitSearch(src, startOffset, endOffset, out GCHandle srcHandle, out IntPtr srcPtr, failChecks);
      739. (bool Status, int? InnerOffset) result = Task.Run<(bool Status, int? Offset)>(() =>
      740. {
      741. int innerEndOffet = endOffset == -1
      742. ? Buffer.Length - src.Length
      743. : endOffset > Buffer.Length - src.Length
      744. ? Buffer.Length - src.Length
      745. : endOffset;
      746. byte firstSrcByte = Marshal.ReadByte(srcPtr);
      747. for (int i = startOffset; i < innerEndOffet; i++)
      748. {
      749. if (Marshal.ReadByte(_bufferPtr + i) == firstSrcByte)
      750. {
      751. if (IsSquenzEqual(_bufferPtr + i, srcPtr, src.Length))
      752. {
      753. return (true, i);
      754. }
      755. }
      756. }
      757. return (false, null);
      758. }).Result;
      759. srcHandle.Free();
      760. offset = result.InnerOffset;
      761. return result.Status;
      762. }
      763. public bool FindLast(byte[] src, out int? offset, int startOffset = 0, int endOffset = -1, bool failChecks = true)
      764. {
      765. InitSearch(src, startOffset, endOffset, out GCHandle srcHandle, out IntPtr srcPtr, failChecks);
      766. (bool Status, int? InnerOffset) result = Task.Run<(bool Status, int? Offset)>(() =>
      767. {
      768. int innerEndOffet = endOffset == -1
      769. ? Buffer.Length - src.Length
      770. : endOffset > Buffer.Length - src.Length
      771. ? Buffer.Length - src.Length
      772. : endOffset;
      773. byte firstSrcByte = Marshal.ReadByte(srcPtr);
      774. for (int i = innerEndOffet; i >= startOffset; i--)
      775. {
      776. if (Marshal.ReadByte(_bufferPtr + i) == firstSrcByte)
      777. {
      778. if (IsSquenzEqual(_bufferPtr + i, srcPtr, src.Length))
      779. {
      780. return (true, i);
      781. }
      782. }
      783. }
      784. return (false, null);
      785. }).Result;
      786. srcHandle.Free();
      787. offset = result.InnerOffset;
      788. return result.Status;
      789. }
      790. public int[] FindAll(byte[] src, int startOffset = 0, int endOffset = -1, bool failChecks = true)
      791. {
      792. InitSearch(src, startOffset, endOffset, out GCHandle srcHandle, out IntPtr srcPtr, failChecks);
      793. return Task.Run(() =>
      794. {
      795. List<int> offsets = new List<int>();
      796. int innerEndOffet = endOffset == -1
      797. ? Buffer.Length - src.Length
      798. : endOffset > Buffer.Length - src.Length
      799. ? Buffer.Length - src.Length
      800. : endOffset;
      801. byte firstSrcByte = Marshal.ReadByte(srcPtr);
      802. Parallel.For(startOffset, endOffset, i =>
      803. {
      804. if (Marshal.ReadByte(_bufferPtr + i) == firstSrcByte)
      805. {
      806. if (IsSquenzEqual(_bufferPtr + i, srcPtr, src.Length))
      807. {
      808. offsets.Add(i);
      809. }
      810. }
      811. });
      812. return offsets.ToArray();
      813. }).Result;
      814. }
      815. [MethodImpl(MethodImplOptions.AggressiveInlining)]
      816. private void InitSearch(byte[] srcBuffer, in int startOffset, in int endOffset, out GCHandle srcHandle, out IntPtr srcPtr, bool failChecks)
      817. {
      818. if (failChecks)
      819. {
      820. if (startOffset < 0)
      821. {
      822. throw new ArgumentOutOfRangeException("startOffset bust be bigger then 0");
      823. }
      824. if (endOffset != -1 && endOffset >= Buffer.Length)
      825. {
      826. throw new ArgumentOutOfRangeException("endOffset bust be smaller then the buffer length");
      827. }
      828. if (startOffset >= Buffer.Length)
      829. {
      830. throw new ArgumentOutOfRangeException("startOffset bust be smaller then the buffer length");
      831. }
      832. if (startOffset >= Buffer.Length)
      833. {
      834. throw new ArgumentOutOfRangeException("startOffset bust be smaller then the buffer length");
      835. }
      836. if (startOffset >= endOffset)
      837. {
      838. throw new ArgumentOutOfRangeException("startOffset bust be smaller then the endOffset");
      839. }
      840. }
      841. srcHandle = GCHandle.Alloc(srcBuffer, GCHandleType.Pinned);
      842. srcPtr = srcHandle.AddrOfPinnedObject();
      843. }
      844. [MethodImpl(MethodImplOptions.AggressiveInlining)]
      845. private bool IsSquenzEqual(IntPtr baseOffset, IntPtr srcPtr, int size)
      846. {
      847. for (int y = 1; y < size; y++)
      848. {
      849. if (Marshal.ReadByte(baseOffset + y) != Marshal.ReadByte(srcPtr + y))
      850. {
      851. return false;
      852. }
      853. }
      854. return true;
      855. }
      856. }
      857. }


      #Bilder
      Spoiler anzeigen

      Hover über eine Hex-Zahl, wird sie überall markiert

      Texte markiern und Kopieren auch kein Problem







      aus dem Problemstellungsforum in den Sourcecodeaustausch verschoben ~VaporiZed

      Dieser Beitrag wurde bereits 10 mal editiert, zuletzt von „Facebamm“ ()

      @Facebamm Ein feines Control hast Du Dir da ausgedacht.
      Mich hat etwas gestört, dass bei MouseWheel und den Control-Tasten die Scrollbar am Rand nicht mitging.
      Hier ein entsprechender Patch:
      In den Prozeduren IsInputKey() und OnMouseWheel()
      die neue Prozedur CalcScollbar() vor Invalidate() aufrufen:

      C#-Quellcode

      1. private void CalcScollbar()
      2. {
      3. if (_Buffer != null)
      4. {
      5. _ScrollbarYOffset = (int)(_CurrentOffset / (double)(_Buffer.Length - (_NLine * _CaptureBytes + _CaptureBytes)) * (Height - 10)) - 5;
      6. }
      7. }
      Fiel fergniegen.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      @Facebamm Wie wäre es mit
      • Finden von Byte-Folgen
      • Merken der Such-Muster in einer XML-Datei
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Also einfach nur eine property in der ich ein sequenz geben und die danach sucht bzw mir die stellen makiert (dazu müsste dann noch ein farbe mit)...
      oder eine Methode der ich eine sequenz gebe und mir alle offsets gibt?
      oder .... ?

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Facebamm“ ()

      @Facebamm Suchen wie in Word oder Notepad.
      Beginnend beimder aktuellen Adresse und Anzeigen der gefundenen Adresse oben im Bild.
      Weitersuchen anbieten.
      Auchstring als Bytes oder Ascii.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Praktisches Control, habe aber ein paar Problemchen

      1 Hatte das Control mit Dock = Fill gehabt, beim resizen wurde erst sehr spät vermutlich durch einen anderenTrigger neu gezeichnet.
      2 Setz doch bitte im Code einen Default-Wert für SelectionBackground, hatte mich gewundert warum mir keine Selection angezeigt wurde, die Forecolor hatte sich in diesem Bereich auch nicht geändert, erst nachdem ich eine farbe eingestellt hatte für SelectionBackground
      3 Die Scrollbar muss besser, ich kann nicht/nur sehr schwer mit der Scrollbar zum Anfang oder zum Ende scrollen, siehe das GIF im Anhang.

      Ich fände eine Fußzeile mit den verschiedenen Interpretationen der selektierten Bytes hilfreich, siehe auch Bild im Anahng, so zeigt es der HxD-Editor an der Seite.
      Bilder
      • Unbenannt.jpg

        529,79 kB, 1.091×904, 136 mal angesehen
      • InstantGif_2020.10.24-07.27.gif

        3 MB, 864×540, 113 mal angesehen
      • Unbenannt.jpg

        106,17 kB, 295×746, 130 mal angesehen

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Takafusa“ ()

      @Takafusa Du musst im Resize-Event des Parent-Fensters HexCtrl.Invalidate() aufrufen.
      Das Control ist auf eine bestimmte Breite ausgelegt, so dass immer dieselbe Anzahl an Bytes dargestellt werden,
      so ähnlich wie ein DateTime-Control.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Wahrscheinlich reicht schon ein this.Invalitate() nach Aufruf von this.CalcPageLine() in der Methode OnSizeChanged.

      Für ein Control wäre aber eigentlich schon wie @RodFromGermany sagt die OnResize-Methode vorgesehen, oder würdest du die OnResize-Methode in die Form1 nehmen? das HexDump-Control lässt sich ja auf die Form1 ziehen.

      Freundliche Grüsse

      exc-jdbi
      Ich hab schonmal ein vorab update gemacht, was die scrollbar einwenig fix ... (im oberen bereich gibt es noch einen großen jump)
      und ich hab das Invalitate() bei OnSizeChanged reingenommen damit der glitch effekt weggeht.

      @RodFromGermany also, ich bin zu dem entschluss gekommen, das ich eine dir deine int FindFirst(byte[]), int FindNext(byte[]), int FindFrom(int offset, byte[]), int FindLast(byte[]) geben werde, denn ich würde ungern jetzt noch irgendwem ein Control aufzwingen um eine suche stattfinden zu lassen... ich kann gern noch ein Standart-Such-Fenster machen.

      @Takafusa ja, an sowas gab ich auch schon gedacht und ich werd es nicht als leiste machen sondern als so kleines ToolTip-Fenster


      Was auch noch kommen wird ist, das man das ganze editieren kann und die Scrollbar und ein ContextMenu
      So, ich hab jetzt ein paar such funktionen hinzugefügt.
      Style anpassungen in den Desginer aufgenommen.
      Die Scrollbar überarbeitet.
      Wobei ich da immer noch ran muss, denn irgendwie geht die nicht richtig im 'Default' fall.
      Definiere

      Facebamm schrieb:

      'Default' fall.
      und beschreibe den Effekt.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!

      RodFromGermany schrieb:

      und beschreibe den Effekt.


      Ich lade mein test exe (BsgLauncher.10.4.1.1205.exe [Escape from Tarkov]) und hierbei tauchte die scrollbar auf ... nun hab ich den fall das die Scrollbar nicht auftauch bei der verwendung von

      Quellcode

      1. Buffer = Enumerable.Range(0, 500).Select(x => (byte)x).ToArray();
      im ctor.

      Das muss ich mir noch anschauen wieso und weshalb ...

      // edit
      Und was mir aufgefallen ist, dass der GC ganz schön zu arbeiten hat sobald ich scrolle oder über etwas hover, das muss ich auch noch lösen. Wobei ich noch nicht mal weiß wo ich vergesse aufzuräumen

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Facebamm“ ()

      @Facebamm Lass mal die Codeanalyse darüber laufen.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Also ich bin dem ganzen jetzt auf die Spur gekommen und es liegt am TextRenderer.drawtext.
      Nehm ich den TextRenderer.drawtext raus und stattdessen e.Graphics.DrawString geht alles. ?(

      Problem ist, das system kann ich nicht beeinflussen :/