# Double Buffer Architecture Research v5
## Focus: WM_PAINT 重入分析

---

## 重入路徑

```
WM_PAINT #1 (UsrFontWndProc)
  ├─ s_bInsidePaint = 1
  ├─ g_bSharedPaint = 1
  ├─ CallWindowProcW → PaintText
  │   ├─ BeginPaint
  │   ├─ TextOut (loop)
  │   │   └─ 某些 GDI 操作可能觸發 ProcessMessages?
  │   │       └─ WM_PAINT #2 dispatched?
  │   │           ├─ s_bInsidePaint = 1 → 跳過 hook (line 74)
  │   │           └─ CallWindowProcW → PaintText #2
  │   │               ├─ BeginPaint #2 (新的 update region)
  │   │               ├─ g_bSharedPaint 仍 = 1
  │   │               ├─ TextOut → s_hdcPaintBuf
  │   │               ├─ 跳過 BitBlt (g_bSharedPaint=1)
  │   │               ├─ g_hPaintBuf = s_hdcPaintBuf ← 正確
  │   │               └─ EndPaint #2
  │   │           （沒有 ScanAndDrawUda #2 — 因為 s_bInsidePaint 跳過了 hook）
  │   │           
  │   ├─ EndPaint #1
  │   └─ return
  │
  ├─ ScanAndDrawUda #1
  │   ├─ 使用 g_hPaintBuf → 正確（包含 #1 + #2 的 ASCII）
  │   ├─ 繪製 UDA → g_hPaintBuf
  │   ├─ BitBlt g_hPaintBuf → screen ← 正確（一次寫入）
  │   └─ return
  │
  ├─ g_bSharedPaint = 0
  └─ s_bInsidePaint = 0
```

## 關鍵問題

### Q1: PaintText 內部會觸發 ProcessMessages 嗎?
- PaintText 本身不呼叫 ProcessMessages
- TextOut/ExtTextOut/BitBlt 是同步 GDI 操作，不觸發訊息派發
- **結論：PaintText 不會重入** → 重入只在 ScanAndDrawUda 之後

### Q2: ScanAndDrawUda 內部會觸發 ProcessMessages 嗎?
- ScanAndDrawUda 呼叫 DrawDynUnicodeGlyph → CreateFontW → 可能觸發字型載入
- 字型載入可能涉及 I/O → 但不觸發 message dispatch
- **結論：ScanAndDrawUda 也不會重入**

### Q3: 重入何時發生?
- 在 InKey() 等待期間的 ProcessMessages
- 在 DispEnd() 觸發的 Refresh → ProcessMessages
- 此時 s_bInsidePaint = 0，g_bSharedPaint = 0
- 重入時走完整路徑（包括 hook），不是部分路徑

### Q4: g_bSharedPaint 的 boolean vs counter 問題
- 由於 PaintText 和 ScanAndDrawUda 都不重入
- g_bSharedPaint 在 WM_PAINT #1 期間始終 = 1
- s_bInsidePaint 阻止了 nested WM_PAINT 進入 hook
- **結論：boolean 足夠，不需要 counter**

### Q5: s_bInsidePaint 跳過 hook 的 nested WM_PAINT
- Nested WM_PAINT 走 line 180: CallWindowProcW 直接
- PaintText 仍看到 g_bSharedPaint=1 → 跳過 BitBlt，設 g_hPaintBuf
- 但沒有 ScanAndDrawUda → UDA 不會被繪製
- **問題**：nested WM_PAINT 的 UDA 在 #1 的 ScanAndDrawUda 補回？
- **答案**：是的。#1 的 ScanAndDrawUda 掃描所有 dirty rows 的 UDA 字元
  - s_rcLastPaint 在 ghost detection 時已擴展
  - #2 的 dirty rows 如果在 #1 的範圍內 → 會被處理
  - 如果不在 → 下次 WM_PAINT 處理

## 結論

**重入安全性：高。** PaintText 和 ScanAndDrawUda 都不會主動觸發訊息派發。s_bInsidePaint 有效防止 nested WM_PAINT 進入 hook。g_bSharedPaint boolean 足夠。
