# 通知設計書 1-Ticker.Elapsed

## 概要

本ドキュメントは、VBCorLibライブラリにおけるTicker.Elapsedイベント通知の設計を定義する。Tickerクラスは定期的なタイマーイベントを提供し、指定した時間間隔でElapsedイベントを発火させる機能を持つ。

### 本通知の処理概要

Ticker.Elapsedは、VB6/VBA環境において定期的なタイマーイベントを発火させる通知機能である。.NET FrameworkのSystem.Timers.Timerに類似した機能を提供し、指定されたミリ秒間隔でイベントを繰り返し発生させることができる。

**業務上の目的・背景**：VB6/VBA環境ではネイティブのタイマー機能が限定的であり、特にフォームに依存しないタイマー処理が困難であった。Ticker.Elapsedイベントは、フォームに依存せず、任意のクラスモジュールから定期的なタイマー処理を実行できる仕組みを提供する。これにより、バックグラウンド処理やポーリング処理、定期的なデータ更新などの業務要件に対応できる。

**通知の送信タイミング**：StartTickerメソッドが呼び出され、Intervalプロパティで設定されたミリ秒間隔が経過した時点でイベントが発火する。AutoResetプロパティがTrueの場合は繰り返し発火し、Falseの場合は1回のみ発火する。

**通知の受信者**：WithEventsキーワードを使用してTicker変数を宣言したクラスまたはフォームモジュールがイベントを受信する。または、NewDelegateによるコールバック関数を指定した場合は、指定された関数がコールバックとして呼び出される。

**通知内容の概要**：Elapsedイベントは、Tickerに関連付けられたユーザー定義データ（Data）をByRef引数として渡す。受信側はこのデータを参照・変更できる。

**期待されるアクション**：受信者は、定期的に実行すべき処理（データ更新、状態監視、UI更新など）をイベントハンドラ内で実装する。AutoResetがFalseの場合、継続してイベントを受信したい場合は再度StartTickerを呼び出す必要がある。

## 通知種別

イベント通知 / コールバック通知（ハイブリッド方式）

- VB6 WithEventsによるイベント通知
- AddressOfによるコールバック関数通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（Windows Timerコールバック経由） |
| 優先度 | 中（Windows Timerの優先度に依存） |
| リトライ | 無（AutoResetによる自動繰り返しあり） |

### 送信先決定ロジック

1. **WithEventsによるイベント受信**
   - Ticker変数をWithEventsで宣言したモジュールのPrivate Sub mTicker_Elapsed(ByRef Data As Variant)プロシージャ

2. **コールバック関数による受信**
   - NewTickerコンストラクタのAddressOfCallbackパラメータで指定された関数
   - シグネチャ: Sub TickerCallback(ByRef Ticker As Ticker, ByRef Data As Variant)

## 通知テンプレート

### イベント通知の場合

| 項目 | 内容 |
|-----|------|
| イベント名 | Elapsed |
| 引数 | ByRef Data As Variant |
| 発生元クラス | Ticker |

### イベントハンドラテンプレート

```vb
Private WithEvents mTicker As Ticker

Private Sub Class_Initialize()
    Set mTicker = NewTicker(2000)  ' 2000ミリ秒間隔
    mTicker.StartTicker
End Sub

Private Sub mTicker_Elapsed(ByRef Data As Variant)
    ' タイマーイベント処理
    Debug.Print "Timer elapsed at " & Now
End Sub
```

### コールバック関数テンプレート

```vb
Private mTicker As Ticker

Private Sub Main()
    Set mTicker = NewTicker(2000, , , AddressOf TimerCallback)
    mTicker.StartTicker
End Sub

Private Sub TimerCallback(ByRef Ticker As Ticker, ByRef Data As Variant)
    ' コールバック処理
    Debug.Print "Callback invoked at " & Now
End Sub
```

### 添付ファイル

該当なし（プログラム内部イベント）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Data | ユーザー定義データ | Ticker.Data プロパティ | No |
| Ticker | タイマーオブジェクト参照（コールバック時） | 呼び出し元Tickerインスタンス | Yes（コールバックのみ） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| タイマー | Windows Timer WM_TIMER | Interval > 0 かつ StartTicker実行済み | SetTimer APIによるタイマーコールバック |
| メソッド呼び出し | StartTicker() | Intervalが0より大きい | タイマーを開始する |
| プロパティ設定 | Enabled = True | Intervalが0より大きい | Enabledプロパティでの開始 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| Interval = 0 | 間隔が0の場合はタイマーが開始されない |
| Enabled = False | タイマーが無効化されている |
| StopTicker実行後 | タイマーが停止されている |
| AutoReset = False かつ 1回発火済み | 単発タイマーの場合、2回目以降は発火しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[StartTicker呼び出し] --> B{Interval > 0?}
    B -->|Yes| C[SetTimer API呼び出し]
    B -->|No| Z[終了]
    C --> D[TimerIdをHashtableに登録]
    D --> E[Windows Timerカウント開始]
    E --> F{Interval経過?}
    F -->|No| E
    F -->|Yes| G[TickerCallback呼び出し]
    G --> H{WM_TIMER メッセージ?}
    H -->|No| Z
    H -->|Yes| I[Tickerオブジェクト取得]
    I --> J[OnElapsed呼び出し]
    J --> K{AutoReset?}
    K -->|No| L[StopTicker実行]
    K -->|Yes| M[継続]
    L --> N[RaiseEvent Elapsed]
    M --> N
    N --> O{Callback設定あり?}
    O -->|Yes| P[mCallback.Invoke実行]
    O -->|No| Q[終了]
    P --> Q
    Q --> R{AutoReset?}
    R -->|Yes| E
    R -->|No| Z
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（メモリ内処理のみ）

### 更新テーブル一覧

該当なし（メモリ内処理のみ）

#### 内部データ構造

| 構造 | 用途 | 説明 |
|------|------|------|
| mTickers (Hashtable) | タイマーID管理 | TimerIdとTickerオブジェクトポインタの対応を保持 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ArgumentOutOfRange | Intervalに負の値を設定 | 0以上の値を指定する |
| Win32Error | SetTimer API失敗 | システムリソースを確認する |
| OutOfMemory | デリゲート作成失敗 | メモリを解放する |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（自動リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 最小間隔 | 1ミリ秒（Intervalの最小値） |
| 最大間隔 | Long型の最大値（約24日） |

### 配信時間帯

制限なし（アプリケーション実行中いつでも発火可能）

## セキュリティ考慮事項

- Windows SetTimer APIを使用するため、アプリケーションのセキュリティコンテキストで実行される
- コールバック関数のアドレスはAddressOf演算子で取得するため、不正なアドレスの指定は防止される
- 弱参照を使用してメモリリークを防止している

## 備考

- VB6 IDEで実行中にコンソールを閉じるとクラッシュする可能性がある
- アプリケーション終了時、Tickerオブジェクトが先に解放されると、TickerSharedモジュールのRelease呼び出しでクラッシュする可能性があるため、ObjectPtrを使用して参照を解除する必要がある
- .NET FrameworkのSystem.Timers.Timerとは異なり、VB6の制約によりマルチスレッド対応ではない

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、Tickerクラスのプロパティとイベント宣言を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Ticker.cls | `Source/CorLib/System.Threading/Ticker.cls` | Public Event Elapsed宣言（82行目）、mCallback, mDelegateメンバ変数 |
| 1-2 | Delegation.bas | `Source/CorLib/System/Delegation.bas` | Delegate型構造体の定義（44-47行目） |

**読解のコツ**: VB6のWithEventsキーワードとPublic Event宣言の関係を理解すること。EventはRaiseEventで発火される。

#### Step 2: エントリーポイントを理解する

処理の起点となるファイル・関数を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Ticker.cls | `Source/CorLib/System.Threading/Ticker.cls` | StartTicker()メソッド（209-215行目）がエントリーポイント |

**主要処理フロー**:
1. **209行目**: StartTicker Subプロシージャ開始
2. **210行目**: 既存のタイマーを停止（StopTicker呼び出し）
3. **212-214行目**: Interval > 0 の場合、TickerShared.StartTicker呼び出し

#### Step 3: タイマー登録処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TickerShared.bas | `Source/CorLib/System.Threading/TickerShared.bas` | StartTicker関数（36-46行目）でSetTimer API呼び出し |

**主要処理フロー**:
- **39行目**: SetTimer API呼び出し、TickerCallbackをコールバックに設定
- **44行目**: mTickers Hashtableにタイマーとオブジェクトポインタを登録

#### Step 4: コールバック処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | TickerShared.bas | `Source/CorLib/System.Threading/TickerShared.bas` | TickerCallback Sub（58-90行目）でWM_TIMERメッセージ処理 |
| 4-2 | Ticker.cls | `Source/CorLib/System.Threading/Ticker.cls` | OnElapsed Sub（255-265行目）でイベント発火 |

**主要処理フロー**:
- **59行目**: WM_TIMERメッセージをチェック
- **72-77行目**: 弱参照からTickerオブジェクトを取得
- **83行目**: Ticker.OnElapsed呼び出し
- **256-258行目**: AutoResetがFalseならStopTicker
- **260行目**: RaiseEvent Elapsed(mData)でイベント発火
- **262-264行目**: コールバックが設定されていればmCallback.Invoke実行

### プログラム呼び出し階層図

```
[ユーザーコード]
    │
    ├─ NewTicker(Interval, Data, AutoReset, AddressOfCallback)
    │      └─ Ticker.Init() ... コールバック設定
    │
    └─ Ticker.StartTicker()
           │
           └─ TickerShared.StartTicker(Me)
                  │
                  ├─ SetTimer API ... Windowsタイマー登録
                  │
                  └─ mTickers.Add(TimerId, ObjPtr) ... 管理テーブル登録
                         │
                         ▼
                  [Windows Timer Callback]
                         │
                  TickerShared.TickerCallback()
                         │
                         └─ Ticker.OnElapsed()
                                │
                                ├─ StopTicker() ... AutoReset=Falseの場合
                                │
                                ├─ RaiseEvent Elapsed(mData) ... イベント発火
                                │
                                └─ mCallback.Invoke(Me, mData) ... コールバック呼び出し
```

### データフロー図

```
[入力]               [処理]                    [出力]

Interval     ───▶ SetTimer API      ───▶ TimerId
(ミリ秒)            (TickerShared)          (管理用ID)

Data         ───▶ Tickerオブジェクト ───▶ Elapsedイベント引数
(Variant)          に保持                  (ByRef Data)

AddressOf    ───▶ InitDelegate     ───▶ mCallback
Callback           (Delegation.bas)       (Action_T_T)

WM_TIMER     ───▶ TickerCallback   ───▶ OnElapsed呼び出し
メッセージ          (TickerShared)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Ticker.cls | `Source/CorLib/System.Threading/Ticker.cls` | ソース | タイマークラス本体、イベント宣言とプロパティ |
| TickerShared.bas | `Source/CorLib/System.Threading/TickerShared.bas` | ソース | Windows Timer APIラッパー、コールバック処理 |
| Delegation.bas | `Source/CorLib/System/Delegation.bas` | ソース | デリゲート（軽量COMオブジェクト）作成 |
| Constructors.cls | `Source/CorLib/System/Constructors.cls` | ソース | NewTicker関数の定義 |
