# STK 列印系統技術文件

> 建立日期: 2026-04-11
> 適用: HBSTK (Harbour GTWVT Console Mode)

---

## 1. 系統概述

將原始 Clipper DOS 列印（LPT/網路印表機）轉換為 Windows 環境下的列印方案：
- 所有列印輸出攔截到文字檔 `output.prn`
- 文字檔轉換為 PDF 並自動開啟檢視
- 同時呼叫 `DosPntGo.exe` 送到實體印表機

---

## 2. 列印流程

```
程式觸發列印 (例: PrintOrder, PrintForm)
        |
        v
+------------------+
| OpenSpool()      |  PRINT.PRG:750
| → SpoolOpenToFile()  print_spool.prg:168
|   - 刪除舊 output.prn
|   - SET PRINTFILE TO output.prn
|   - SET PRINTER ON
|   - SET CONSOLE OFF
+------------------+
        |
        v
+------------------+
| 程式正常輸出     |
| @ SAY, ?, ??     |
| (全部導向到      |
|  output.prn)     |
+------------------+
        |
        v
+------------------+
| CloseSpool()     |  PRINT.PRG:785 / xCloseSpool():770
| → SpoolCloseAndPrint()  print_spool.prg:197
|   - SET CONSOLE ON
|   - SET PRINTER OFF
|   - SET PRINTFILE TO ""
|   |
|   +---> PrnToPdf()          prn_to_pdf.prg:34
|   |     - 讀取 output.prn
|   |     - hbhpdf/MingLiU 產生 output.pdf
|   |     - wapi_ShellExecute 開啟 PDF
|   |
|   +---> CallDosPntGo()      print_spool.prg:137
|         - dospntgo.exe output.PRN /Caller=HDOS4
|         - hb_processOpen (不等待)
+------------------+
```

---

## 3. 檔案清單

### 3.1 核心模組

| 檔案 | 說明 |
|------|------|
| `compat/print_spool.prg` | 列印攔截主模組：SpoolOpenToFile、SpoolCloseAndPrint、CallDosPntGo、SelectPrinter |
| `compat/prn_to_pdf.prg` | PRN 文字轉 PDF：PrnToPdf（使用 hbhpdf/libharu） |
| `source/PRINT.PRG` | 原始列印模組：OpenSpool、CloseSpool、xCloseSpool 改為呼叫新模組 |
| `source/main.prg` | 程式進入點：啟動時呼叫 InitPrintSpool() |

### 3.2 組態檔

| 檔案 | 說明 |
|------|------|
| `build/printer.cfg` | 儲存使用者上次選擇的印表機名稱 |
| `build/output.prn` | 列印輸出暫存檔（文字格式） |
| `build/output.pdf` | PDF 轉換結果 |

### 3.3 Build 設定

| 項目 | 內容 |
|------|------|
| `stk32.hbp` 新增 | `hbhpdf.hbc` (libharu PDF 庫) |
| `stk32.hbp` 新增 | `..\compat\prn_to_pdf.prg` |
| `stk32.hbp` 既有 | `..\compat\print_spool.prg` |

---

## 4. 函式說明

### 4.1 print_spool.prg

#### InitPrintSpool()
- **用途**: 初始化列印模組，載入上次選擇的印表機
- **呼叫時機**: main.prg 啟動時
- **動作**: 讀取 `printer.cfg` → 設定 `s_cLastPrinter`

#### SpoolOpenToFile( cFileName )
- **用途**: 取代原始 OpenSpool 的 LPT/檔案設定
- **參數**: cFileName - 原始列印檔名（保留相容性）
- **動作**:
  1. 刪除舊 `output.prn`
  2. `SET PRINTFILE TO output.prn`
  3. `SET PRINTER ON` / `SET CONSOLE OFF`
- **回傳**: .T.

#### SpoolCloseAndPrint()
- **用途**: 取代原始 CloseSpool 的 LPT/網路印表邏輯
- **動作**:
  1. `SET CONSOLE ON` / `SET PRINTER OFF` / `SET PRINTFILE TO ""`
  2. 呼叫 `PrnToPdf()` 轉 PDF 並開啟
  3. 呼叫 `CallDosPntGo()` 送印
- **回傳**: .T. 成功 / .F. 失敗

#### CallDosPntGo( cPrnFile )
- **用途**: 呼叫外部 DosPntGo.exe 送印
- **命令**: `dospntgo.exe output.PRN /Caller=HDOS4`
- **特性**: `hb_processOpen()` 不等待，立即返回

#### SelectPrinter()
- **用途**: 顯示 Windows 印表機選擇清單（AChoice）
- **動作**: `win_printerList()` → AChoice 選單 → 儲存到 `printer.cfg`
- **回傳**: 印表機名稱字串，取消回傳空字串

#### GetLastPrinter()
- **用途**: 取得上次選擇的印表機名稱
- **回傳**: s_cLastPrinter

### 4.2 prn_to_pdf.prg

#### PrnToPdf( cPrnFile, cPdfFile, lOpen )
- **用途**: 將 PRN 文字檔轉換為 PDF
- **參數**:
  - cPrnFile: 輸入 PRN 檔路徑
  - cPdfFile: 輸出 PDF 檔路徑（空則自動產生）
  - lOpen: 轉換後是否自動開啟（預設 .T.）
- **技術**:
  - hbhpdf (libharu) 產生 PDF
  - `HPDF_UseCNTEncodings()` + `HPDF_UseCNTFonts()` 啟用繁體中文
  - MingLiU 字型 + ETen-B5-H 編碼
  - 處理 Form Feed (Chr(12)) 換頁
  - 頁尾自動換頁
- **PDF 版面**:
  - 紙張: A4 直式
  - 字型: MingLiU 10pt
  - 行高: 14pt
  - 邊距: 上下左右各 0.5 inch (36pt)
- **回傳**: .T. 成功 / .F. 失敗

---

## 5. 原始碼對照 (PRINT.PRG 修改)

### OpenSpool (PRINT.PRG:750)
```
原始: 設定 LPT 或網路印表機輸出
修改: 呼叫 SpoolOpenToFile( cFileName )
```

### CloseSpool (PRINT.PRG:785) / xCloseSpool (PRINT.PRG:770)
```
原始: COPY FILE TO PRN 或 LPT 埠輸出
修改: 呼叫 SpoolCloseAndPrint()
```

---

## 6. 依賴套件

| 套件 | 用途 | HBC |
|------|------|-----|
| hbwin | win_printerList(), wapi_ShellExecute() | hbwin.hbc |
| hbhpdf | HPDF_* PDF 產生函式 (libharu wrapper) | hbhpdf.hbc |

---

## 7. 呼叫點統計

全系統約 30+ 處呼叫 OpenSpool/CloseSpool，分布在:
- BUYSELL.PRG (PrintOrder 等)
- PRINT.PRG (PrintForm)
- REPORT.PRG
- LABEL.PRG
- P*.PRG (各業務模組報表)

所有呼叫點不需修改，透過 OpenSpool/CloseSpool 的轉接自動導向新模組。

---

## 8. Debug 追蹤

所有函式透過 `WriteDebugLog()` 寫入 `Debug_Type.txt`，搜尋關鍵字:
- `PRINT:` - print_spool.prg 的 log
- `PDF:` - prn_to_pdf.prg 的 log

範例 log:
```
INITPRINTSPOOL | PRINT: InitPrintSpool() done
SPOOLOPENTOFILE | PRINT: SpoolOpen -> E:\...\output.prn (orig: PrnFrm.Prn)
SPOOLCLOSEANDPRINT | PRINT: SpoolCloseAndPrint() enter
PRNTOPDF | PDF: PrnToPdf() enter, prn=... pdf=...
PRNTOPDF | PDF: 25 lines to convert
PRNTOPDF | PDF: saved to E:\...\output.pdf
CALLDOSPNTGO | PRINT: CMD=dospntgo.exe E:\...\output.prn /Caller=HDOS4
```
