# 列印系統全面修正 + WebView2 離線安裝 + P77 印表機設定

**日期**：2026-04-27  
**範圍**：STK32 列印流程、PrnAsk 列印輸出、造字區列印、WebView2 離線安裝、P77 設定對話框

---

## 一、訴求與現象

### 1.1 S001 新電腦部署問題
- 部署 STK32 到 S001（新電腦）後，多項功能異常
- PrnAsk 印表機選擇框延遲 30-60 秒才出現
- 造字區（PUA E000-EE1A）在預覽可見，列印輸出空白
- 沒有 WebView2 時無提示，使用者以為當機

### 1.2 列印系統缺陷
- `win_printerList()` 列舉網路印表機逾時 5 分鐘
- `printer.cfg` 儲存不存在的印表機名稱，靜默失敗
- `dospntgo.exe` 路徑不存在，靜默失敗
- `PrnAsk.exe` 缺失時靜默 fallback，使用者不知情

### 1.3 印表機設定需求
- 列印設定分散在系統選單三個獨立項目，操作不便
- 需要一個統一的設定對話框

---

## 二、踩坑與陷阱

### 2.1 PrnAsk 延遲的真正原因（不是印表機列舉！）
- **初始假設**：`AGetPrinters()` 列舉網路印表機造成延遲
- **實際根因**：`FwCheckWebView2()` 的 `hb_run(PowerShell)` 同步下載 WebView2
- **證據**：RESULT.TXT 時間差（16:07:20 → 16:08:18 = 58 秒卡在下載）
- **教訓**：先看 LOG 時間差，不要憑經驗猜測

### 2.2 WebView2 安裝的坑
- Bootstrapper（1.7MB）需要連線網路，非離線安裝
- Standalone Installer（173MB）才是真正的離線安裝包
- `hb_DirExists()` 在某些環境偵測不到已安裝目錄 → 改用 Registry
- Registry GUID `{F3017226-FE2A-4295-8BEB-235B4A6B2C9E}` 不一定存在 → 改用 Uninstall key
- `hb_processRun()` 阻塞 + `/silent` → 使用者看不到任何東西以為當機
- MessageBox 被 STK32 視窗擋住 → `MB_TOPMOST | MB_SETFOREGROUND`
- FiveWin MsgInfo 中文亂碼 → 自製 `MsgBoxW()`（BIG5→Unicode→MessageBoxW）
- 安裝提示與安裝程式互相遮掩 → `MsgRun()` 解決

### 2.3 造字區列印的坑
- `GdiFlushText()` 完全沒有 PUA 檢測 → BIG5 FA-FE 直送 TextOut → 空白
- `DrawUsrGlyph` Priority 3 的 `nCPFb < 0xE000` 排除了所有 PUA
- `RenderUnicodeGlyph` 用 `CP_ACP` 而非 `950` → 非繁中系統字型名解碼錯誤
- 開發機有華康字型（系統字型）所以能渲染，S001 沒有 → 必須載入 USRFONT.TTF
- FontDirect=3 禁止 BCACHE 保存，但列印路徑依賴 BCACHE → 改走 TTF 路線

### 2.4 P77 印表機設定的坑
- `Chr(196)` 分隔線在造字模式下變亂碼 → 用 `aFrame[4]` 的 `cHorzChar`
- PickList 自動計算高度，項目多（30+紙張）往上擴展超出對話框 → `lChangeHigh` 屬性
- `Inkey(0)` 收滑鼠移動事件造成畫面閃爍 → 只在 `nSelRow` 變化時重繪
- PRNMETHOD 切換時忘記更新對面的 AUTOFMT → PRNMETHOD=0 + AUTOFMT=4 會異常
- DelSpTmp.bat 的 `del *.ini` 會刪掉 stk.ini 和 System.ini（列印觸發）

### 2.5 stk.ini 消失之謎
- OpenSpool() 呼叫 `RunCMD("start /B DelSpTmp.bat")`
- DelSpTmp.bat 內含 `del *.ini` → 刪除目錄下所有 .ini
- 開發機不受影響：STK_EXTRACT_RES 會從 EXE 資源重建（路徑剛好正確）
- S001 重建出來的是開發機路徑 → 路徑錯誤 → 需要手動修正

---

## 三、解決方法

### 3.1 Stk32 列印修正（print_spool.prg）
| FIX | 內容 |
|-----|------|
| 1 | `win_printerList()` → `STK_PRINTERLIST()`（只列本機） |
| 2 | `InitPrintSpool()` 加 `STK_PRINTEREXISTS()` 驗證 |
| 3 | `CallDosPntGo()` 檢查 dospntgo.exe 存在 |
| 4 | PrnAsk.exe 缺失顯示 MessageBox 警告（3處） |

### 3.2 造字區列印修正（prn_to_pdf.prg + gdi_print.prg）
- **GdiFlushText()**：加 PUA 檢測（nAsc >= 0xFA）→ 走 `GdiDrawUsrGlyph` 點陣圖路線
- **GdiDrawUsrGlyph()**（新增）：Priority 1/2/3 跟 DrawUsrGlyph 相同邏輯，用 `GdiDrawBitmap` 輸出
- **DrawUsrGlyph Priority 3**：移除 `< 0xE000` 限制，PUA 用華康楷書W5A 渲染
- **LoadUsrFontData()**：加載 USRFONT.TTF（`GdiLoadFontFile`）
- **RenderUnicodeGlyph**：`CP_ACP` → `950`（修正非繁中系統）
- **四條路徑全覆蓋**：螢幕 ✓ / PDF預覽 ✓ / GDI列印 ✓ / PDF轉印表機 ✓

### 3.3 WebView2 離線安裝（PrnAsk main.prg + gdi_print.prg）
- 離線安裝包 `MicrosoftEdgeWebView2RuntimeInstallerX86.exe`（173MB）放 EXE 同目錄
- `FwCheckWebView2()` 流程：
  1. `CheckWebView2Reg()` 檢查 Uninstall Registry
  2. 已安裝 → 跳過
  3. 未安裝 + 有安裝包 → `MsgRun()` 顯示進度 + `ShellRunWait()` 執行安裝
  4. 安裝完 → `CheckWebView2Reg()` 驗證 → `MsgBoxW()` 顯示結果
  5. 未安裝 + 無安裝包 → `MsgBoxW()` 提示
- 新增 C 函式：
  - `CheckWebView2Reg()` — Uninstall Registry 驗證
  - `MsgBoxW()` — BIG5→Unicode→MessageBoxW（解決亂碼）
  - `MsgBoxWTimeout()` — 自動關閉的 MessageBox
  - `ShellRunWait()` — ShellExecuteExW 前景啟動 + 等待完成
  - `GdiLoadFontFile()` — AddFontResourceExW(FR_PRIVATE)

### 3.4 P77.PRG 印表機設定對話框（新增）
- **UI**：Console popup + aFrame[4] + 表頭分隔線 + 底部提示列
- **5 項設定**：印表機、紙張、列印方式、列印詢問、輸出格式
- **印表機清單**：PickList（滑鼠、捲軸、右鍵=ESC）
- **紙張清單**：`STK_PAPERLIST()` 動態取得 + PickList（lChangeHigh 固定高度）
- **即時生效**：每次修改立即寫入 System.ini + 更新系統選單
- **PRNMETHOD/AUTOFMT 同步**：
  - 切換列印方式 → 兩邊 AUTOFMT 都重設為 1
  - 外部改格式 → 同步 PRN_AUTOFMT（1↔1, 2↔4）
  - 內部改格式 → 同步 PNTGO_AUTOFMT（4↔2, 其他↔1）

---

## 四、使用技術與用法

### 4.1 造字區列印架構
```
PRN 檔案（BIG5 FA-FE）
  │
  ├── PDF 路徑：FlushText → DrawUsrGlyph → HPDF 圖片嵌入
  │     Priority 1: USRFONT.BCACHE（灰階快取）
  │     Priority 2: USRFONT.24M（24×24 點陣）
  │     Priority 3: UMAP → Unicode → 華康楷書W5A → GDI渲染 → 圖片
  │
  └── GDI 列印路徑：GdiFlushText → GdiDrawUsrGlyph → GdiDrawBitmap
        （同上 Priority 1/2/3，用 StretchDIBits 輸出到印表機 DC）
```

### 4.2 WebView2 偵測方式
```
Registry: HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\
          Uninstall\Microsoft EdgeWebView
```

### 4.3 PRNMETHOD / AUTOFMT 對應關係
```
PRNMETHOD=0（外部）→ PNTGO_AUTOFMT: 1=列印, 2=預覽
PRNMETHOD=1（內部）→ PRN_AUTOFMT:   1=列印, 2=PDF, 3=Excel, 4=預覽

同步映射：
  PNTGO=1 ↔ PRN=1（列印）
  PNTGO=2 ↔ PRN=4（預覽）
```

### 4.4 P77 呼叫方式
```prg
P77()   // 從系統選單或功能鍵呼叫
```

### 4.5 System.ini PRNMETHOD / AUTOFMT 同步邏輯

**切換列印方式時（P77 或系統選單）：**

| 動作 | PRN_AUTOFMT | PNTGO_AUTOFMT | 選單更新 |
|------|-------------|---------------|---------|
| 切到外部(0) | → 1 | → 1 | 直接列印 |
| 切到內部(1) | → 1 | → 1 | 直接列印 |

**外部模式(PRNMETHOD=0)修改輸出格式時：**

| 選擇 | PNTGO_AUTOFMT | PRN_AUTOFMT（同步） | 選單 |
|------|---------------|-------------------|------|
| 列印 | 1 | 1 | 直接列印 |
| 預覽 | 2 | 4 | 預覽列印 |

**內部模式(PRNMETHOD=1)修改輸出格式時：**

| 選擇 | PRN_AUTOFMT | PNTGO_AUTOFMT（同步） | 選單 |
|------|-------------|---------------------|------|
| 列印 | 1 | 1 | 直接列印 |
| PDF | 2 | 1 | 直接列印 |
| Excel | 3 | 1 | 直接列印 |
| 預覽 | 4 | 2 | 預覽列印 |

**陷阱防護**：切換列印方式時，兩邊的 AUTOFMT 都重設為 1。避免 PRNMETHOD=0 時 AUTOFMT 停在 3 或 4（外部模式不支援）造成系統異常。

---

## 五、客戶端部署所需檔案

部署到新電腦時，EXE 同目錄需要以下檔案：

| 檔案 | 大小 | 用途 | 必要性 |
|------|------|------|--------|
| Stk32.exe | ~32MB | 主程式 | 必要 |
| PrnAsk.exe | ~8MB | 列印輸出選擇工具 | 必要 |
| stk.ini | ~4KB | 系統路徑設定（需依客戶端路徑修正） | 必要 |
| System.ini | ~5KB | 列印/字型/功能設定 | 必要 |
| USRFONT.TTF | ~25MB | 全形造字向量字型（FontDirect=3） | 必要 |
| ASCFONT.TTF | ~16KB | 半形控制字元向量字型 | 必要 |
| USRFONT.24M | ~7KB | 24×24 造字點陣（備用） | 必要 |
| USRFONT.UMAP | ~2KB | 造字 Unicode 映射表 | 必要 |
| ASCFONT.15 | ~101KB | ASCFONT 點陣資料 | 必要 |
| ASCFONT.UMAP | ~1KB | ASCFONT 映射表 | 必要 |
| MicrosoftEdgeWebView2RuntimeInstallerX86.exe | ~173MB | WebView2 離線安裝包 | 建議（無此檔預覽功能不可用） |
| GO.BAT | ~1KB | 原始 DOS 環境設定（go2ini 用） | 視環境 |
| printer.cfg | ~0KB | 上次選擇的印表機（自動產生） | 自動 |

**注意事項**：
1. stk.ini 的路徑（LOC_SYS、LOC_DBF 等）必須修改為客戶端的本機路徑
2. STK_EXTRACT_RES 會從 EXE 資源解壓 stk.ini/System.ini（overwrite=0：只在不存在時建立）
3. 解壓出的 stk.ini 是開發機路徑 → 客戶端必須用 go2ini 或手動修正
4. WebView2 離線安裝包放在 EXE 同目錄，PrnAsk 啟動時自動偵測安裝
5. USRFONT.TTF/ASCFONT.TTF 由 STK_EXTRACT_RES 從 EXE 解壓（overwrite=1：每次更新）

---

## 六、修改檔案清單

| 檔案 | 修改內容 |
|------|---------|
| `compat/print_spool.prg` | 4 項列印修正 |
| `compat/prn_to_pdf.prg` | GdiDrawUsrGlyph、PUA 檢測、Priority 3、LoadUsrFontData、CP_ACP→950 |
| `compat/gdi_print.prg` | GdiLoadFontFile、MsgBoxW、MsgBoxWTimeout、ShellRunWait、CheckWebView2Reg |
| `compat/picklist.prg` | lChangeHigh 屬性 |
| `c_code/printer_c.c` | STK_PRINTERLIST、STK_PRINTEREXISTS、STK_CHECKSPOOLER、STK_PAPERLIST |
| `source/main.prg` | EXTERNAL 宣告 |
| `source/P77.PRG` | 新增：印表機設定對話框 |
| `build/stk32.hbp` | 加 printer_c.c、P77.PRG |
| `PRNASK/source/main.prg` | FwCheckWebView2 離線安裝 + MsgRun |
| `PRNASK/source/fw_prnout.prg` | AGetPrinters→STK_PRINTERLIST |
| `PRNASK/source/dospntask.prg` | AGetPrinters→STK_PRINTERLIST |
| `PRNASK/build/prnask.hbp` | 加 printer_c.c + winspool |
