# 通知設計書 5-Delegation.NewDelegate

## 概要

本ドキュメントは、VBCorLibライブラリにおけるDelegation.NewDelegateコールバック通知機構の設計を定義する。NewDelegate関数は軽量COMオブジェクトを作成し、AddressOf演算子で指定された関数を呼び出し可能にする委譲パターンを実現する。

### 本通知の処理概要

Delegation.NewDelegateは、VB6のAddressOf演算子で取得した関数ポインタを軽量COMオブジェクトとしてラップし、Invokeメソッドによる関数呼び出しを可能にする通知機構である。Matt Curlandのデリゲーションコード技術を使用し、VB6で関数委譲パターンを実現する。

**業務上の目的・背景**：VB6ではAddressOfで取得した関数ポインタを直接呼び出すことができず、コールバックパターンの実装が困難であった。NewDelegateは、関数ポインタを軽量COMオブジェクトとしてラップすることで、型安全なコールバック呼び出しを可能にする。これにより、Timer、Sorter、非同期処理などでのコールバックパターンを実現できる。

**通知の送信タイミング**：NewDelegateで作成されたデリゲートオブジェクトに対してInvokeメソッドが呼び出された時点で、登録された関数が実行される。

**通知の受信者**：NewDelegate関数のpfn引数（AddressOfで指定）で登録された関数。標準モジュール内のPublic関数として定義する必要がある。

**通知内容の概要**：デリゲートの型（Action_T_T、Func_T_T_Long等）に応じた引数が関数に渡される。戻り値がある型の場合は関数の戻り値がInvokeの戻り値となる。

**期待されるアクション**：登録された関数が引数を受け取り、必要な処理を実行し、戻り値がある場合は適切な値を返す。

## 通知種別

コールバック通知（軽量COMオブジェクトによる関数委譲）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（Invoke呼び出し時に即時実行） |
| 優先度 | 呼び出し元の処理優先度に依存 |
| リトライ | 無 |

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

1. NewDelegate(pfn)で関数ポインタを登録
2. 戻り値をデリゲート型（IUnknown派生）として保持
3. デリゲート.Invoke(args...)で関数呼び出し

## 通知テンプレート

### NewDelegate関数シグネチャ

| 項目 | 内容 |
|-----|------|
| 関数名 | NewDelegate |
| 引数 | ByVal pfn As Long（関数ポインタ） |
| 戻り値 | IUnknown（軽量COMオブジェクト） |

### 使用例

```vb
' 標準モジュール内
Private mDelegate As Func_T_T_Long

Sub Main()
    ' デリゲート作成
    Set mDelegate = NewDelegate(AddressOf MyCompare)

    ' デリゲート経由で関数呼び出し
    Dim result As Long
    result = mDelegate.Invoke(10, 20)
    ' result = -10 (10 - 20)
End Sub

' コールバック関数
Public Function MyCompare(ByVal x As Long, ByVal y As Long) As Long
    MyCompare = x - y
End Function
```

### デリゲート型一覧

| 型名 | 引数 | 戻り値 | 用途 |
|-----|------|--------|-----|
| Action_T_T | (ByRef T, ByRef T) | なし | Tickerコールバック等 |
| Func_T_T_Long | (ByVal T, ByVal T) | Long | 比較関数等 |
| Func_T_T_T_String | (ByVal T, ByVal T, ByVal T) | String | 書式設定関数等 |

### 添付ファイル

該当なし（プログラム内部機能）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| pfn | 関数ポインタ | AddressOf演算子 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| メソッド呼び出し | delegate.Invoke() | pfn <> vbNullPtr | デリゲートのInvokeメソッド呼び出し |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| pfn = vbNullPtr | 無効な関数ポインタ |
| デリゲートが解放済み | Nothing設定後は呼び出し不可 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[NewDelegate pfn 呼び出し] --> B[Init でVTable初期化]
    B --> C[CoTaskMemAlloc でメモリ確保]
    C --> D{メモリ確保成功?}
    D -->|No| E[OutOfMemoryException]
    D -->|Yes| F[LocalDelegate構造体を設定]
    F --> G[pfn = 関数ポインタ]
    G --> H[pVTable = mLocalVTablePtr]
    H --> I[cRefs = 1]
    I --> J[ObjectPtr で IUnknown として返却]
    J --> K[呼び出し側で型キャスト]
    K --> L[delegate.Invoke args 呼び出し]
    L --> M[DelegationCode 経由で関数実行]
    M --> N[登録関数実行]
    N --> O[戻り値を返却]
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

#### 内部データ構造

| 構造体/変数 | 用途 |
|------------|------|
| LocalDelegate | デリゲートインスタンス（pVTable, pfn, cRefs） |
| LocalDelegateVTable | IUnknown VTable + Invoke関数ポインタ |
| DelegationCode | Matt Curlandのデリゲーションコード（Currency型、8バイト） |
| mLocalVTablePtr | VTableへのポインタ |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| OutOfMemoryException | CoTaskMemAlloc失敗 | メモリを解放して再試行 |
| 不正アクセス | 無効な関数ポインタ | AddressOfで有効な関数を指定 |
| シグネチャ不一致 | デリゲート型と関数シグネチャの不一致 | 適切なシグネチャの関数を定義 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし |

### 配信時間帯

制限なし

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

- VirtualProtectでDelegationCodeをPAGE_EXECUTE_READWRITEに設定（実行可能コードとして扱う）
- AddressOf演算子はコンパイル時検証されるため不正アドレスリスク低
- アプリケーション終了時、ObjectPtrでデリゲート参照を解除しReleaseメソッド呼び出しを回避する必要あり

## 備考

- Matt Curlandのデリゲーションコード技術を使用
- 長時間稼働するオブジェクトでは、Class_TerminateでObjectPtrを使用して参照解除が推奨
- DelegationモジュールがアンロードされるとReleaseメソッドがクラッシュする可能性あり

---

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

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

### 推奨読解順序

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

デリゲートの内部構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Delegation.bas | `Source/CorLib/System/Delegation.bas` | LocalDelegate型（38-42行目）、Delegate型（44-47行目） |
| 1-2 | Delegation.bas | `Source/CorLib/System/Delegation.bas` | LocalDelegateVTable型（30-32行目） |
| 1-3 | Delegation.bas | `Source/CorLib/System/Delegation.bas` | DelegationCode定数（27行目）- Matt Curlandのコード |

**読解のコツ**: LocalDelegateはIUnknown互換の構造体。pVTableはVTableへのポインタ、pfnは関数ポインタ、cRefsは参照カウント。

#### Step 2: 初期化処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Delegation.bas | `Source/CorLib/System/Delegation.bas` | Init Sub（146-178行目） |

**主要処理フロー**:
- **148-149行目**: DelegationCodeをPAGE_EXECUTE_READWRITEに設定
- **151-156行目**: LocalDelegateVTableの設定（QueryInterface, AddRef, Release, Invoke）
- **158行目**: mLocalVTablePtrにVTableアドレスを設定

#### Step 3: NewDelegate関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Delegation.bas | `Source/CorLib/System/Delegation.bas` | NewDelegate関数（72-85行目） |

**主要処理フロー**:
- **75行目**: Init()で初期化（初回のみ）
- **76行目**: CoTaskMemAllocでメモリ確保
- **78-79行目**: メモリ不足チェック
- **81行目**: mDelegateTemplate.pfn = pfn（関数ポインタ設定）
- **82行目**: mDelegateTemplate.pVTable = mLocalVTablePtr（VTable設定）
- **83行目**: CopyMemoryでデリゲート構造体をコピー
- **84行目**: ObjectPtrでIUnknownとして返却

#### Step 4: VTableメソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Delegation.bas | `Source/CorLib/System/Delegation.bas` | LocalDelegate_AddRef（189-192行目） |
| 4-2 | Delegation.bas | `Source/CorLib/System/Delegation.bas` | LocalDelegate_Release（194-202行目） |

**主要処理フロー**:
- **195行目**: 参照カウントをデクリメント
- **197-198行目**: cRefs = 0ならCoTaskMemFreeでメモリ解放

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

```
[ユーザーコード]
    │
    └─ NewDelegate(AddressOf MyFunc)
           │
           ├─ Init() ... 初回のみVTable初期化
           │      │
           │      ├─ VirtualProtect(DelegationCode)
           │      │
           │      └─ LocalDelegateVTable設定
           │             ├─ Func(0) = QueryInterface
           │             ├─ Func(1) = AddRef
           │             ├─ Func(2) = Release
           │             └─ Func(3) = DelegationCode
           │
           ├─ CoTaskMemAlloc(SizeOfLocalDelegate)
           │
           ├─ LocalDelegate構造体設定
           │      ├─ pVTable = mLocalVTablePtr
           │      ├─ pfn = 関数ポインタ
           │      └─ cRefs = 1
           │
           └─ ObjectPtr() で IUnknown 返却
                  │
                  ▼
           [呼び出し側]
                  │
                  └─ delegate.Invoke(args)
                         │
                         └─ DelegationCode経由
                                │
                                └─ MyFunc(args) 実行
```

### データフロー図

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

AddressOf           ───▶ NewDelegate           ───▶ IUnknown
MyFunc                    (Delegation.bas)           (軽量COMオブジェクト)
(関数ポインタ)

delegate.Invoke     ───▶ DelegationCode        ───▶ MyFunc実行
(args)                    (マシンコード)              │
                                                      ▼
                                                  戻り値
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Delegation.bas | `Source/CorLib/System/Delegation.bas` | ソース | デリゲート作成・管理機能 |
| Action_T_T.cls | `Source/CorLib/System/Action_T_T.cls` | ソース | 2引数Actionデリゲート型定義 |
| Func_T_T_Long.cls | `Source/CorLib/System/Func_T_T_Long.cls` | ソース | 2引数Long戻りFuncデリゲート型定義 |
