アーキテクチャ
モジュール構成
src/Launcher/
├── Core/ ドメインモデル・ビジネスロジック
├── Infrastructure/ 基盤ユーティリティ
├── UI/ WinFormsフォーム群
├── Win32/ Win32 API連携
└── Updater/ 自動更新機能モジュール分割の設計意図
- Core — UIフレームワーク(WinForms)に依存しない純粋なドメインモデルとロジックを置く。 テスト容易性と関心の分離が目的である
- Infrastructure — アプリケーション基盤。シリアライズ・パス操作・ファイル操作など、 ドメインやUIに属さない横断的関心事を集約する。PathHelperはパス文字列操作のみ、 FileHelperはファイル・ディレクトリ操作と役割を分離している
- UI — WinFormsに依存するフォーム群。ロジックはPresenterに委譲し、フォーム自体は表示と入力の橋渡しに徹する
- Win32 — P/Invoke呼び出しを隔離するモジュール。 Win32 APIの複雑さ(マーシャリング、リソース管理)をアプリケーション本体から遮断する。 Shell API呼び出し(プロセス起動・アイコン取得・ショートカット操作・Shellコンテキストメニュー表示等)をここへ集約する
- Updater — 自動更新機能。GitHub Releases APIとの通信、ZIPの展開、バッチスクリプトによる自己置換など、 更新特有の処理を分離する
主要な設計パターン
Presenterパターン
CommandLauncherPresenter / ButtonLauncherPresenter / SchedulerPresenter / MemoPresenterがUIロジックを担当する。 WinFormsのフォームクラスはイベントハンドラとコントロール操作のみを持ち、判断ロジックはPresenterに委譲する。 UIロジックをWinFormsから分離してテスト可能にする設計である。
ConfigStore継承による永続化
ConfigStoreを継承するクラスはXMLシリアライズで永続化される。 対象はConfig・CommandList・ButtonLauncherData・SchedulerData・Data・MemoDataである。 ConfigStoreは原子的なファイル保存(一時ファイルに書き込み後File.Moveで置換)を提供し、 保存中のクラッシュによるデータ破損を防止する。
ApplicationHostFormによるIPCハブ
ApplicationHostFormは不可視の常駐フォームで、アプリケーション全体のハブとして機能する。 WM_APPMSGによるプロセス間通信(/close、/restart等のコマンドライン引数の処理)を受け付ける。 加えて、子フォーム(CommandLauncherForm、ButtonLauncherForm、MemoForm)のライフサイクルを管理する。 WinFormsのメッセージループを維持するために常駐フォームが必要であり、 CommandLauncherFormは表示/非表示を繰り返すため、この役割を分離している。 また、スケジューラーのタイマー(30秒間隔)を管理し、スケジュール条件に合致したタスクの自動実行も制御する。
スケジューラータスクの種類
スケジューラーはファイル実行に加え、メッセージ表示タスクをサポートする。
| 種類 | 説明 |
|---|---|
| Execute | ShellExecuteExでプログラムを起動する |
| BalloonTip | タスクトレイのバルーン通知でメッセージを表示する (自動消去) |
| MessageBox | NotificationFormをモーダル表示する (OKボタンで手動消去) |
Core層 (SchedulerPresenter) はUI依存を持たない。 BalloonTip/MessageBoxの表示はデリゲート経由でUI層 (ApplicationHostForm) に委譲する。 MessageBoxはInvoke(同期呼び出し)でダイアログが閉じるまで後続タスクをブロックする。 BalloonTipはBeginInvoke(非同期)で実行する。
通知ダイアログの追跡とowner選定
実装上の不変条件は.claude/skills/notification-dialog/に記載している。
フック管理
HookManagerがグローバルキーボード/マウスフックの状態管理を一元的に担当する。 マウスフックはボタン押下状態(lbuttonDown/rbuttonDown)を追跡し、 設定されたトリガー(左右同時押し等)を検知する。
コールバック内で守るべき実装上の不変条件(即時return・UP抑制フラグ更新など)は .claude/rules/win32-interop.mdに記載している。
環境変数の自動リロード
EnvironmentRefresher(Win32/)がレジストリから環境変数を再読込し、現プロセスの環境ブロックを差分更新する。 ApplicationHostForm.WndProcがWM_SETTINGCHANGE(lParam == "Environment")を受信する。 500msのデバウンスを経てEnvironmentRefresher.Refresh()を呼び、 その後ReplaceEnvListをCommandListとSchedulerDataに背景スレッドで再適用する。 ReplaceEnvListに関する挙動上の注意は.claude/skills/persistence/に記載している。
マージ規則はExplorer互換(HKLM+HKCU統合、Path系のみ;連結、それ以外はユーザー変数優先)とする。
子プロセスへの伝搬は追加実装不要である。 ShellExecuteExは呼び出し元プロセスの環境ブロックを継承するため、 Environment.SetEnvironmentVariableで更新すれば以降の起動プロセスへ新値が反映される。