本文件針對 CB_IMGPSScanImp.pas 中的核心方法與隱藏物件進行原始碼級別的邏輯拆解與推導。
在 Delphi 中,若要動態讀取編譯進 OCX 的 VS_VERSION_INFO 資源,標準作法是呼叫一系列的 Windows API。這段實作通常包含以下三個關鍵概念:
取得檔案路徑後,讀取版本資訊會經過三部曲,而 VerQueryValue 是最後負責「解析」的關鍵:
它會負責初始化全域變數、設定第三方元件的預設值、並建立暫存資料夾。
```pascal
procedure TCB_IMGPSScanX.ActiveFormCreate(Sender: TObject);
begin
// 1. 預設變數初始化
Def_DeviceDelete := True;
Def_ScannerReverse := False;
// 2. 建立本機暫存目錄
ForceDirectories('C:\Temp\IMGPSScan');
// 3. UI 語系初始化
InitialLanguage;
end;
```
這個方法會讀取網頁傳進來的參數(如 DPI、色彩),設定給 Scanner 物件,然後發出擷取指令。
```pascal
procedure TCB_IMGPSScanX.StatrTwainScan;
begin
// 設定解析度與顏色
Scanner.Resolution := StrToIntDef(Fimgdpi, 200);
if Fscancolor = 'C' then
Scanner.PixelType := ptColor
else
Scanner.PixelType := ptGray;
// 啟動掃描 (會喚起實體掃描機)
Scanner.Acquire;
end;
```
源碼邏輯推導:
```pascal
procedure TCB_IMGPSScanX.ScannerAcquire(Sender: TObject; DibHandle: THandle; var Handled: Boolean);
var
MyStream: TMemoryStream;
MyGraphic: TDibGraphic;
begin
// 1. 將 DibHandle 轉換為 Delphi 影像物件
MyGraphic := TDibGraphic.Create;
MyGraphic.Handle := DibHandle;
// 2. 影像處理 (如去斜、黑白轉換)
// 3. 存入記憶體串流或實體檔案
// ...
end;三大核心資料物件解釋:
TMemoryStream:**記憶體串流**。它的作用像是一塊存在 RAM 裡的虛擬硬碟。掃描後的圖檔在還沒存到實體硬碟前,會先放在這裡進行格式轉換 (如轉成 JPEG) 或進行 MD5 計算,因為在記憶體中操作速度最快。
OnAcquire 事件中,DeleteStm 主要用於「空白頁判定」。其源碼邏輯如下:```pascal
// 判定是否啟動空白頁刪除功能
if Def_DeviceDelete then
begin
// 1. 在 Heap 記憶體中建立一個暫存串流物件
DeleteStm := TMemoryStream.Create;
try
// 2. 將當前掃描到的影像物件 (MyGraphic) 寫入記憶體串流
// 這會根據 TIFF G4 等格式進行壓縮,產生實際的檔案位元組資料
MyGraphic.SaveToStream(DeleteStm);
// 3. 核心判定:檢查該影像在記憶體中所佔用的位元組大小 (Size)
// 若小於預設門檻值 (Def_DeviceDeleteSize, 如 3072 Bytes)
if DeleteStm.Size < Def_DeviceDeleteSize then
begin
// 4. 若符合空白頁特徵,則不進行存檔動作,直接跳出此 Procedure
// 並告知掃描控制項此頁已處理完畢 (Handled := True)
Handled := True;
Exit;
end;
finally這對應到 uses 區段中的 EnImgScr 套件。TImageScrollBox 是 Envision 提供的一個 UI 元件,專門用來顯示超出螢幕大小的掃描圖檔,支援平滑拖曳與縮放。這個方法通常用來把剛掃描完的 DibHandle 餵給畫面上的 ISB 元件顯示。
此方法透過迴圈尋找一個尚未被使用的目錄名稱(格式為「未配號 + 四位數字」)。
Function TCB_IMGPSScanX.GetNoNameCase(Path:String):String; // 取未配號XXXX
var
i : Integer; // 宣告迴圈計數器
begin
// 1. 啟動一個從 1 到 9999 的迴圈,尋找可用的索引值
for i := 1 to 9999 do
begin
// 2. 檢查特定路徑下的目錄是否已存在
// _Msg('未配號'):取得「未配號」字串(可能具備多國語言處理)
// Add_Zoo(i, 4):將數字 i 補齊為 4 位數(例如 1 變為 0001)
if Not DirectoryExists(Path + _Msg('未配號') + Add_Zoo(i, 4)) then
begin
// 3. 若該目錄不存在,代表此名稱可用,設定 Result 並跳出迴圈
Result := _Msg('未配號') + Add_Zoo(i, 4);
Break; // 找到第一個可用的名稱後立即停止搜尋
end;
end;
end;
這兩個方法是 OCX 與網頁 (JS) 溝通的雙向橋樑。
源碼實作解析:
程式一開始會先寫死一組標準值,例如 Def_ScanDpi := 300 (預設 300 DPI)、Def_DeviceDeleteSize := 3072 (空白頁判定門檻為 3KB)。
透過 for i := 0 to WORK_INF_List.Count - 1 do 迴圈遍歷設定檔清單。使用 GetSQLData 取得參數代號 (PARA_NO) 與內容 (PARA_CONTENT)。
屬性設定對照表:
下表整理了此方法中設定的所有關鍵屬性、其對應的參數代號及功能說明。
| 屬性名稱 (內部變數) | 對應 PARA_NO | PARA_CONTENT 處理方式(GetSQLData) | 功能說明 |
| --- | --- | --- | --- |
| Def_DeviceDelete | SCAN_BLANKDEL_USE | 'Y' -> True, Else -> False | 空白頁自動刪除開關。 |
| Def_DeviceDeleteSize | SCAN_BLANKDEL_SIZE | StrToInt (若空則 0) | 空白頁判定門檻 (Bytes)。 |
| Def_ScannerReverse | SCAN_REVERSE | 'Y' -> True, Else -> False | 影像是否反相。 |
| Def_BoardClear | SCAN_BOARDCLEAR | 'Y' -> True, Else -> False | 是否清除影像黑邊。 |
| Def_ScanDpi | SCAN_DPI | StrToInt (若空則 300) | 掃描解析度。 |
| Def_ScanDuplex | SCAN_DUPLEX | 'Y' -> True, Else -> False | 是否啟用雙面掃描。 |
| Def_ScanRotate | SCAN_ROTATE_MODE | '0'->0, '1'->270, '2'->180, '3'->90 | 掃描旋轉角度映射。 |
| Def_ScanDeskew | SCAN_DESKEW | 'Y' -> True, Else -> False | 是否自動矯正傾斜。 |
| Def_ScanImgSetUse | SCAN_IMGSET_USE | 'Y' -> True, Else -> False | 是否使用亮度/對比設定。 |
| Def_ScanBright | SCAN_BRIGHT | StrToInt (限制 -255~255) | 亮度數值。 |
| Def_ScanContrast | SCAN_CONTRAST | StrToInt (限制 -255~255) | 對比數值。 |
| Def_ScanImgShowMode | SCAN_SHOW_MODE | '0','1','2' 對應模式 | 影像顯示/縮放模式。 |
| ScanDenialTime | CASE_IN_TIME | 直接存為 String | 進件截止時間限制。 |
| ScanDenialHint | SCAN_HINT | 直接存為 String | 掃描畫面提示字串。 |
| NoSaveBarCodeList | NO_SAVE_FORM_ID | CommaText := Value | 不存檔之表單代號清單。 |
| ImagePath | LOCAL_PATH | 直接存為 String | 本機端暫存路徑。 |
| GuideFormIDList | GUIDEFORMID | CommaText := Value | 導引頁表單 ID 清單。 |
| DivPageFormIDList | DIVPAGEFORMID | CommaText := Value | 分案頁表單 ID 清單。 |
| FJpgCompression | FILE_COMPRESSION | StrToInt | JPG 轉 TIF 壓縮比。 |
| FMaxUploadSize | MAX_UPLOAD_SIZE | 直接存為 String | 上傳大小限制 (MB)。 |
以下條列專案中直接涉及記憶體操作的程式區段:
| 記憶體操作對象 | 所屬 Function / Procedure | 關鍵操作關鍵字 / 代碼 | 記憶體特性說明 | 註記 |
|---|---|---|---|---|
| HInstance | GetCurrentVersionNo | GetModuleFileName(HInstance, ...) | 模組載入位址。 | 增API版本號 |
| 資源緩衝區 | GetCurrentVersionNo | VerQueryValue, GetFileVersionInfo | 透過 Pointer 進行二進位搜尋。 | 增API版本號 |
| DibHandle | onAcquire | MyGraphic.Handle := DibHandle; | Windows 全域記憶體句柄轉移。 | 改套件實作/Rust |
| TMemoryStream | onAcquire | MemoryStream.Write, .Read | Heap Memory 內部二進位操作。 |
你提到在原始碼中找不到 _DelTree 和 Scanner 的實作,這是因為它們屬於以下兩種情況: