Skip to content

fix(app): 起動が成り立つ前の例外は握り潰さない - #78

Merged
limit7412 merged 1 commit into
masterfrom
claude/remaining-issues-priority-m7daxq
Aug 31, 2026
Merged

fix(app): 起動が成り立つ前の例外は握り潰さない#78
limit7412 merged 1 commit into
masterfrom
claude/remaining-issues-priority-m7daxq

Conversation

@limit7412

Copy link
Copy Markdown
Owner

issue #77 の対応。案 B(起動の途中で投げた場合は落とす)を採った。

何が起きていたか

UnhandledException は常に e.Handled = true にしていた。常駐中の例外でアプリごと落とさないための扱いだが、起動の途中で投げた場合まで同じにすると割に合わない。

OnLaunched がウィンドウを組み立てる前に投げると、ウィンドウの無いプロセスがメッセージループと多重起動の抑止を掴んだまま残る。利用者から見るとこうなる。

  • 画面が出ない
  • もう一度起動しても、抑止に当たって何も出てこない(先に居るプロセスにウィンドウが無いので、復帰要求を送っても何も現れない)
  • タスクマネージャで止めるまで抜けられない

OnLaunched の中の各段は個別に try / catch してあるが、DispatcherQueue の取得と new MainWindow()Window.Activate() は包んでいない。ここが投げると外側の catch が再送出し、そのまま上のハンドラへ届く。new MainWindow()MainPage を作り、その構築子が MainPageViewModel を作るので、投げうる余地は広い。

これは更新とは独立に起こる。設定ファイルが壊れている場合なども同じ形になる。

変更内容

起動が成り立ったかを表す印 (_startupCompleted) を置き、ハンドラで分けた。

  • 成り立った後: これまでどおり握り潰してアプリを生かす。常駐中の例外でいちいち落ちては、同期の途中で画面ごと消えることになる
  • 成り立つ前: 握り潰さず、そのまま落とす

印を立てるのは、ウィンドウを組み立て、出す(またはトレイ常駐の指定 #54 に従って出さないと決める)ところまで進んだ時点である。

誤って落とさないか

印を立てるのは OnLaunched の中であり、そこまでは UI スレッドの同期の処理しか走らない。ディスパッチャへ積んだ処理(ShowMainWindowOnUi 経由の反映)が動き出すのは、UI スレッドが OnLaunched を抜けてメッセージループへ戻ってからである。つまりそれらは必ず印が立った後に走るので、誤って落とされることはない。

Tray.Initialize / Coordinator / UpdateManager / 後始末 / SessionEnding の各段は個別に catch してあるので、そもそもハンドラへ届かない。届くのは、届いた時点で画面を出せないと分かっている失敗だけである。

更新機構との関係

落ちれば抑止は OS が手放すので、原因を取り除いて起動し直せる。更新の直後であれば、#53 で入れた更新ヘルパの観察がこれを拾い、退避しておいた一式へ戻す。これまではプロセスが残るため、観察が「立ち上がった」と読んでいた。

PR #75 の本文に書いた「落ちずに止まる形は捕まらない」は、起動の途中の失敗については当てはまらなくなる。docs/update.md をその線で直した。

検証

  • WinUI の起動経路であり、Core.Tests では動かせないため、テストは追加していない
  • 実機で確かめたいのは次の 2 点
    • MainPage の構築子で意図的に投げると、プロセスが落ち、もう一度起動すると普通に立ち上がること(残ったプロセスに抑止を掴まれない)
    • 立ち上がった後に投げる例外(同期の途中など)では、これまでどおり落ちないこと

残るもの

ウィンドウを出した後の描画で投げるような、OnLaunched を抜けてから起こる失敗はこの印では区別できない。#77 の案 A(起動完了を App から知らせ、ヘルパはそれを待つ)はそこまで見られるが、合図を置く場所と待ちの上限を決める必要がある。この PR で塞ぐのは「起動の途中で投げた場合」に絞ってある。

Refs #77, #53, #54


Generated by Claude Code

UnhandledException は常に e.Handled = true にしていた。常駐中の例外でアプリごと
落とさないための扱いだが、起動の途中で投げた場合まで同じにすると割に合わない。

OnLaunched がウィンドウを組み立てる前に投げると、ウィンドウの無いプロセスが
メッセージループと多重起動の抑止を掴んだまま残る。利用者から見ると、画面が
出ないうえに、もう一度起動しても抑止に当たって何も出てこない。タスクマネージャ
で止めるまで抜けられない。

起動が成り立ったかを見て分けることにした。ウィンドウを組み立て、出す (または
トレイ常駐の指定に従って出さないと決める) ところまで進んでいれば、これまでどおり
握り潰す。そこへ届く前なら握り潰さず、そのまま落とす。

落ちれば抑止は OS が手放すので、原因を取り除いて起動し直せる。更新の直後で
あれば、更新ヘルパの観察 (issue #53) が拾って退避した一式へ戻す。これまでは
プロセスが残るため、観察が「立ち上がった」と読んでいた。

印を立てるのは OnLaunched の中であり、そこまでは UI スレッドの同期の処理しか
走らない。ディスパッチャへ積んだ処理が動き出すのは OnLaunched を抜けた後なので、
それらが誤って落とされることはない。

WinUI はここでプロセスを終わらせるため、Program.Main の finally は通らない。
ログの書き出しだけ先に済ませる。

Refs #77
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants