當使用 TRichEdit 開啟二進位檔(如 .exe、.obj、.bin)時,預設會嘗試以文字方式解碼,導致顯示亂碼。本文示範如何繼承 TConversion 類別並覆寫 ConvertReadStream,註冊自訂轉換格式,讓 RichEdit 自動將指定副檔名的檔案以十六進制檢視器模式呈現——類似 UltraEdit 的經典十六進制檢視格式:位址、十六進位位元組、ASCII 字元對照。
//---------------------------------------------------------------------------
// 從 TConversion 衍生自訂轉換類別
class THexConversion : public TConversion
{
public:
virtual int __fastcall ConvertReadStream(TStream *pStream,
char *pSrcBuffer, int nBufSize);
};
//---------------------------------------------------------------------------
// 覆寫讀取串流轉換邏輯
int __fastcall THexConversion::ConvertReadStream(TStream *pStream,
char *pSrcBuffer, int nBufSize)
{
String strTemp;
unsigned char szDstBuffer[16];
int n, nResult;
// 緩衝區太小直接返回
if (nBufSize <= 82) return 0;
// 1. 顯示位址(8 位十六進位 + "h: ")
strTemp = strTemp.sprintf("%.8xh: ", pStream->Position);
// 2. 讀取 16 位元組
n = pStream->Read(szDstBuffer, 16);
if (n == 0) return 0;
// 3. 十六進位位元組,每 4 組加一空格
for (int i = 0; i < n; i++)
{
AppendStr(strTemp, IntToHex(szDstBuffer[i], 2) + ' ');
if ((i + 1) % 4 == 0) AppendStr(strTemp, ' ');
}
// 4. 填充對齊至固定寬度
String str;
str.StringOfChar(' ', 65 - strTemp.Length());
AppendStr(strTemp, str + "; ");
// 5. ASCII 字元區:可列印字元顯示原字,否則顯示 '.'
for (int i = 0; i < n; i++)
{
if ((szDstBuffer[i] < 32) || (szDstBuffer[i] > 126))
szDstBuffer[i] = '.';
AppendStr(strTemp, (char)szDstBuffer[i]);
}
AppendStr(strTemp, "\n");
StrCopy(pSrcBuffer, strTemp.c_str());
nResult = strTemp.Length();
// 6. 回報進度(選用)
Form1->Process(pStream->Position);
Application->ProcessMessages();
return nResult;
}
void __fastcall TForm1::FormCreate(TObject *Sender)
{
// 將 bin、obj、exe 三種副檔名關聯至 THexConversion
RichEdit1->RegisterConversionFormat(NULL, "bin", __classid(THexConversion));
RichEdit1->RegisterConversionFormat(NULL, "obj", __classid(THexConversion));
RichEdit1->RegisterConversionFormat(NULL, "exe", __classid(THexConversion));
}
// 表單類別需宣告:void __fastcall Process(int nPos);
void __fastcall TForm1::Process(int nPos)
{
StatusBar1->SimpleText = "正在處理... " + String(nPos);
StatusBar1->Update();
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
RichEdit1->Lines->LoadFromFile("C:\\123\\123.exe");
StatusBar1->SimpleText = "載入完成!";
}
| 技術點 | 說明 |
|---|---|
| TConversion 機制 | RichEdit 內建的串流轉換架構,支援依副檔名動態掛載自訂解碼器。 |
| ConvertReadStream | 核心虛擬函式,負責從 TStream 讀取原始位元組並轉換為 RichEdit 可顯示的文字緩衝區。 |
| 固定 16 位元組區塊 | 模仿標準十六進位編輯器排版,每行 16 位元組,便於人眼對照位址與內容。 |
| ASCII 過濾 | 將控制字元(<32)與擴展 ASCII(>126)替換為 '.',避免亂碼干擾閱讀。 |
| 進度回報 | 利用 Application->ProcessMessages() 保持 UI 響應,適合大型二進位檔案載入。 |
ConvertWriteStream 實現十六進位編輯後存檔功能。RegisterConversionFormat。FindDialog 實現十六進位模式下的關鍵字/位元組搜尋。TMemoryStream 一次讀入全部資料再分塊格式化。透過繼承 TConversion,我們以極少的程式碼為 TRichEdit 賦予了專業級十六進位檢視能力,展示了 VCL 架構擴充性的強大與優雅。