# 通知設計書 2-SafeHandle.ReleaseHandle

## 概要

本ドキュメントは、VBCorLibライブラリにおけるSafeHandle.ReleaseHandleイベント通知の設計を定義する。SafeHandleクラスはOSハンドルのラッパークラスであり、ReleaseHandleイベントはハンドル解放時の通知機構を提供する。

### 本通知の処理概要

SafeHandle.ReleaseHandleは、OSハンドル（ファイルハンドル、ウィンドウハンドル等）のライフサイクル管理において、ハンドル解放時に発火されるイベントである。.NET FrameworkのSafeHandleパターンをVB6で実装しており、リソースの確実な解放を保証する。

**業務上の目的・背景**：Windows APIを使用するアプリケーションでは、ファイル、ソケット、GDIオブジェクトなどのOSリソースを適切に解放する必要がある。解放漏れはリソースリーク、システム不安定化の原因となる。ReleaseHandleイベントは、SafeHandleの派生クラス（SafeFileHandleなど）がハンドル固有の解放処理を実装できる仕組みを提供し、確実なリソース管理を実現する。

**通知の送信タイミング**：CloseHandleメソッドが呼び出された時点でイベントが発火する。ただし、OwnsHandleがTrueかつIsClosedがFalseの場合のみ発火する。

**通知の受信者**：SafeHandleをWithEventsで宣言した派生クラス（SafeFileHandle等）がイベントを受信する。SafeHandleは直接インスタンス化されず、常に派生クラスを通じて使用される。

**通知内容の概要**：ReleaseHandleイベントは引数を持たない。受信者はイベントハンドラ内でDangerousGetHandleメソッドを使用して現在のハンドル値を取得し、適切なAPI（CloseHandle, DeleteObject等）を呼び出してリソースを解放する。

**期待されるアクション**：受信者は、保持しているハンドルの種類に応じた解放処理を実装する。ファイルハンドルならCloseHandle API、GDIオブジェクトならDeleteObject APIなど、ハンドル固有の解放関数を呼び出す。

## 通知種別

イベント通知（VB6 WithEventsによる通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高（リソース解放のため即時処理） |
| リトライ | 無（1回のみ発火） |

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

WithEventsキーワードを使用してSafeHandle型のメンバ変数を宣言した派生クラスがイベントを受信する。

```vb
Private WithEvents mBase As SafeHandle

Private Sub mBase_ReleaseHandle()
    ' ハンドル解放処理
End Sub
```

## 通知テンプレート

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

| 項目 | 内容 |
|-----|------|
| イベント名 | ReleaseHandle |
| 引数 | なし |
| 発生元クラス | SafeHandle |

### イベントハンドラテンプレート（SafeFileHandle実装例）

```vb
' SafeFileHandle.cls
Private WithEvents mBase As SafeHandle

Private Sub Class_Initialize()
    Set mBase = New SafeHandle
    mBase.Init INVALID_HANDLE_VALUE, True, True
End Sub

Private Sub mBase_ReleaseHandle()
    ' ファイルハンドル固有の解放処理
    CloseHandle mBase.DangerousGetHandle
End Sub

Public Sub CloseHandle()
    mBase.CloseHandle
End Sub
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| Handle | 解放対象のハンドル値 | DangerousGetHandle()メソッド | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| メソッド呼び出し | CloseHandle() | OwnsHandle=True かつ IsClosed=False | 明示的なハンドル解放要求 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| OwnsHandle = False | ハンドルの所有権がない場合は解放しない |
| IsClosed = True | 既に解放済みの場合は再度イベントを発火しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[CloseHandle呼び出し] --> B{OwnsHandle = True?}
    B -->|No| Z[終了]
    B -->|Yes| C{IsClosed = True?}
    C -->|Yes| Z
    C -->|No| D[RaiseEvent ReleaseHandle]
    D --> E[派生クラスのイベントハンドラ実行]
    E --> F[mHandle = INVALID_HANDLE]
    F --> G[mIsClosed = True]
    G --> Z
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

#### 内部データ構造

| メンバ変数 | 型 | 用途 |
|-----------|---|------|
| mHandle | Long | OSハンドル値 |
| mIsClosed | Boolean | 解放済みフラグ |
| mOwnsHandle | Boolean | ハンドル所有権フラグ |
| mZeroIsInvalid | Boolean | 0を無効ハンドルとして扱うフラグ |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ハンドル解放失敗 | 派生クラスでの解放API失敗 | 派生クラス側でエラー処理を実装 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし（インスタンスごとに1回のみ発火） |

### 配信時間帯

制限なし

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

- DangerousGetHandleメソッドは危険なハンドル操作を意味する命名で、ハンドルの不正使用を抑止
- OwnsHandleフラグにより、所有権のないハンドルの誤解放を防止
- IsClosed二重チェックにより、二重解放（double-free）を防止

## 備考

- .NET FrameworkのSystem.Runtime.InteropServices.SafeHandleに相当する機能を提供
- SafeFileHandle、SafeMemoryMappedViewHandleなどの派生クラスが存在
- INVALID_HANDLE（-1）および0（ZeroIsInvalid=Trueの場合）が無効なハンドルとして扱われる

---

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

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

### 推奨読解順序

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

まず、SafeHandleクラスのメンバ変数とプロパティを理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SafeHandle.cls | `Source/CorLib/Microsoft.Win32.SafeHandles/SafeHandle.cls` | メンバ変数宣言（48-51行目）、Public Event ReleaseHandle宣言（53行目） |

**読解のコツ**: mOwnsHandleとmIsClosedの2つのフラグがイベント発火条件を制御している点に注目。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SafeHandle.cls | `Source/CorLib/Microsoft.Win32.SafeHandles/SafeHandle.cls` | CloseHandleメソッド（88-94行目）がエントリーポイント |

**主要処理フロー**:
1. **89行目**: OwnsHandleとIsClosedの条件チェック
2. **90行目**: RaiseEvent ReleaseHandle発火
3. **91行目**: mHandle = INVALID_HANDLEで無効化
4. **92行目**: mIsClosed = Trueで解放済みマーク

#### Step 3: プロパティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SafeHandle.cls | `Source/CorLib/Microsoft.Win32.SafeHandles/SafeHandle.cls` | IsInvalidプロパティ（77-79行目）で無効ハンドル判定ロジック |
| 3-2 | SafeHandle.cls | `Source/CorLib/Microsoft.Win32.SafeHandles/SafeHandle.cls` | DangerousGetHandle（59-62行目）でハンドル値取得 |

**主要処理フロー**:
- **78行目**: INVALID_HANDLE(-1)または0（ZeroIsInvalid時）を無効と判定

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | SafeHandle.cls | `Source/CorLib/Microsoft.Win32.SafeHandles/SafeHandle.cls` | Init Sub（100-104行目）で初期化パラメータ設定 |

**主要処理フロー**:
- **101行目**: mHandle = PreexistingHandle
- **102行目**: mOwnsHandle = OwnsHandle（所有権設定）
- **103行目**: mZeroIsInvalid = ZeroIsInvalid

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

```
[派生クラス（例：SafeFileHandle）]
    │
    ├─ Class_Initialize
    │      └─ Set mBase = New SafeHandle
    │             └─ mBase.Init(Handle, OwnsHandle, ZeroIsInvalid)
    │
    └─ CloseHandle() 呼び出し
           │
           └─ mBase.CloseHandle()
                  │
                  ├─ 条件チェック: OwnsHandle AND NOT IsClosed
                  │
                  ├─ RaiseEvent ReleaseHandle
                  │      │
                  │      └─ [派生クラス] mBase_ReleaseHandle()
                  │             └─ Windows API解放関数呼び出し
                  │
                  ├─ mHandle = INVALID_HANDLE
                  │
                  └─ mIsClosed = True
```

### データフロー図

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

PreexistingHandle ───▶ Init()           ───▶ mHandle設定
(Long)                 (SafeHandle)

OwnsHandle       ───▶ Init()           ───▶ mOwnsHandle設定
(Boolean)

CloseHandle()    ───▶ 条件チェック     ───▶ RaiseEvent発火
呼び出し               (OwnsHandle,          │
                       IsClosed)              ▼
                                         派生クラスの
                                         イベントハンドラ
                                              │
                                              ▼
                                         Windows API
                                         解放関数呼び出し
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SafeHandle.cls | `Source/CorLib/Microsoft.Win32.SafeHandles/SafeHandle.cls` | ソース | 基底ハンドルラッパークラス、イベント宣言 |
| SafeFileHandle.cls | `Source/CorLib/Microsoft.Win32.SafeHandles/SafeFileHandle.cls` | ソース | ファイルハンドル用派生クラス |
| SafeMemoryMappedViewHandle.cls | `Source/CorLib/Microsoft.Win32.SafeHandles/SafeMemoryMappedViewHandle.cls` | ソース | メモリマップドファイル用派生クラス |
