Deep dive into the mechanisms that let the yoAnime VSTO Add‑in and the WPF app work together: safe launch/attach, handshake, PanesReady, AppFrame discovery, parenting state machine, integrity monitor, and elevation/UIPI protections.
This describes the optional integrated experience; the standalone Studio runs independently.
1) Quick Overview (What “Integrated” actually does)
When a real PowerPoint document window becomes active, the add‑in runs a deferred startup pipeline on the UI thread, initializes interop, and orchestrates the WPF companion app. The two processes establish a named‑pipe connection (authority/epoch‑gated) and optionally a WebSocket for high‑frequency UI updates. Once add‑in task panes are up and the WPF side acknowledges them, the WPF window is parented into PowerPoint’s AppFrame and monitored continuously for integrity.
2) Safe PowerPoint Launch / Attach (WPF‑side authority)
Attach‑first policy. On WPF startup, the app first tries to attach to an existing PowerPoint instance/window; only if none is discovered will it resolve the path and launch PowerPoint with retry/back‑off. All steps are logged and user‑visible fallbacks exist (e.g., a “PowerPoint Missing” window that lets the user browse to POWERPNT.EXE). Foreground activation is best‑effort and DPI/handle verification is performed.
Highlights
- Attach via window probe + PID verification; else resolve
ExecutablePathand safe‑launch with Polly policy and bounded waits. - Time‑boxed handle polling and timeout error path (gracefully shuts down if PPT window never materializes).
- WebView2 fallback UX when runtime is missing (retry or continue with limited functionality).
3) Deferred Startup (Add‑in side)
Trigger: The add‑in listens for the first real DocumentWindow activation (has a caption) and runs a two‑phase pipeline:
- UI phase (on PPT UI thread):
Creates the marshalling control, injectsIWindowStateMonitorServiceintoIPowerPointInterop, and callsInitializePowerPoint()—then immediately marks Ready[UI] so UI (panes/HTML) can proceed. It also requests a deferred COM drain and primes UIA for the first geometry epoch quietly. - Background phase:
Optionally executesStartupManager.InitializeAsync()(WebView2 env, interop sanity), exitsUiThreadInvokerstartup mode, then runs a WPF launch + pipe fast‑path with a 30‑second bound, honoring WPF authority (do not launch if an external authoritative WPF already exists).
The add‑in’s central orchestrator (EnsureWpfLaunchOrchestratedAsync) enforces monotonic nonce/epoch, single‑task publication, 30s timeout, and graceful recovery paths; it also races launch vs. “pipe already connected” and respects authority from the WPF side.
4) Handshake → PanesReady → Stand‑Down (who becomes “Ready,” and when)
The connection lifecycle revolves around epochs and a strict authority gate:
- Pipe connects → Add‑in sends Handshake Initiation and mirrors the connection epoch.
On Handshake ACK (for current epoch only), the add‑in reseeds initial context for all panes (deduped per(connEpoch, hwnd, paneId)). - Panes restore & announce readiness → Each pane calls AnnounceReadinessToWpf; the add‑in tracks a server ACK for each pane (TaskPaneReadyAck). A readiness monitor loop waits for all real panes to be ACKed for the current epoch.
- Stand‑Down + InitComplete: When all panes are ACKed, the add‑in sends stand‑down to the WPF app and then AddinInitializationComplete (with
ReadyTaskPaneCount), finally starting the client heartbeat. This finalization is epoch‑aware and occurs only after handshake authority is established. - WPF Parenting gate (server side): Separately, the WPF app flips a PanesReady flag upon receiving its internal panes‑ready event; only then will it attempt SetParent of
MainWindowinto PowerPoint’s AppFrame—guarded by state machine checks (see next sections).
5) AppFrame Discovery (the “right” host window)
WPF maintains a permanent parenting anchor (PermanentAppFrameHwnd) chosen from a configuration‑controlled allow‑list of class names (e.g., PPTFrameClass, mdiClass, NetUIHWNDHost), with a fallback option (telemetry helps discover new classes during Office UI transitions). It periodically revalidates the class/handle and can rediscover the AppFrame by walking the PPT window hierarchy (accommodating Mica/tabbed UI). DPI of the host monitor is published to subscribers.
6) Parenting State Machine (WPF → PowerPoint)
Parenting is executed by a state machine with clear transitions:
States: NotReady → WaitingMainWindow → WaitingPowerPoint → Attempting → ParentSucceeded → ParentFailed
Gates:
- PanesReady must be true (from integrated pipeline).
- Valid
MainWindowand validPermanentAppFrameHwnd. - UIPI elevation parity must pass (details below).
- Attempt ceilings and exponential backoff + jitter apply.
On success, the machine resets attempt counters, records the last parent, and logs structured telemetry. On failure/exceeded attempts, it lands in ParentFailed and waits for a new signal or rediscovery.
7) Parent Integrity Monitor (repair if anything drifts)
A timer‑driven integrity monitor (configurable interval) verifies that the WPF MainWindow remains a child of the same AppFrame; if not, it repairs window styles/ex‑styles (e.g., WS_CHILD, WS_CLIPCHILDREN, remove WS_POPUP, adjust WS_EX_CONTROLPARENT, etc.), reapplies SetParent, and stabilizes z‑order with SetWindowPos. The monitor is automatically restarted if settings reload at runtime.
8) Elevation / UIPI: Blocking conditions & user guidance
If PowerPoint is running elevated while the WPF app is not (or vice‑versa), Windows UIPI will block SetParent. The WPF app detects elevation mismatch early, posts a sticky status + warning dialog, marks parenting as failed, and suppresses retries until parity is restored (run both at the same elevation level). The add‑in and WPF logs call this out explicitly.
9) Visibility & Pane Lifecycle (Add‑in hygiene)
The add‑in persists pane visibility per presentation using a versioned store under %LOCALAPPDATA%\\yoAnime\\config, migrating old keys (Caption) to canonical full path keys (or UNSAVED_ keys before first save), pruning stale entries periodically while PowerPoint is idle. Pane (re)binds are idempotent and hard‑invalidate readiness epochs before moving a pane to another window. Sentinel panes are excluded from readiness gates.
10) Sequence (Text Diagram)
PowerPoint starts → VSTO add‑in loads
→ (User opens/activates a real document window)
→ DeferredStartupCoordinator: UI Phase (create marshalling, inject WSM, InitializePowerPoint)
→ Mark Ready[UI]
→ Background: StartupManager.InitializeAsync (WebView2 env + interop), WPF launch fast‑path (authority-aware)
→ Named pipe connects → Handshake Initiation → Handshake ACK (current epoch)
→ Add‑in reseeds InitialSlideContextRequested (deduped by connEpoch, hwnd, paneId)
→ Add‑in restores task panes for open windows and each pane announces readiness
→ Server ACKs each pane → All panes ACKed (epoch)
→ Add‑in sends Stand‑Down, then InitComplete (ReadyPaneCount), starts heartbeat
→ WPF receives PanesReady internally → Parenting state machine attempts SetParent
→ Parent Integrity Monitor keeps relationship healthy over time
11) Troubleshooting (Field Notes)
- WebView2 missing: WPF shows a fallback window with a one‑click retry after installing the runtime; you can continue in limited mode if needed.
- No PPT window discovered: The attach+launch policy logs whether a PID was found but no AppFrame yet; WPF keeps waiting and will parent after handshake supplies the AppFrame HWND.
- Parenting never happens: Check PanesReady (server side), elevation parity (UIPI), and allowed anchor classes under
PowerPointParenting. - Pane ready but no context: The add‑in only publishes InitialSlideContext after handshake ACK for the current epoch and when it can resolve an authoritative TaskPane_ id* for the HWND.