😁

T04_VBAプロシージャ一覧シリーズ 今から使える業務改善用VBA4|各エクセルファイルのシートの飛び地セルを一括更新|

に公開

この記事について

A05で集約した飛び地セル値(Valueシート)を一括編集して、元のエクエルファイルのシートへ一括更新 VBAシートモジュールのコードです。
シートモジュールに貼り付けるだけで動作します。環境構築は不要です。

機能の概要:

  • 【A14】2段階ワークフローで「集約 → 編集 → 元のシートを更新」を完結
    • Phase1(Set):MappingシートとValueシートを掛け合わせて ReWriteSheetValue 雛形を生成(アドレス行/値行の交互配置)
    • 手動編集:ユーザーが値行のセルを直接編集
    • Phase2(Execute):編集後の値を元エクセルファイルの飛び地セルを一括更新
  • ハイパーリンクから元エクセルファイルパスを自動取得 → ファイルごと開いて該当セルへ書込
  • 書込失敗ファイルは赤字マーカーで可視化
    ―――――――――――――――――――――――――――――――――――
     処理フロー
    ―――――――――――――――――――――――――――――――――――
     [A05] CollectExcelSheet
       ↓ Mappingシート(シート名・セル番地)
       ↓ Valueシート(集約された飛び地値)
     [A14 Phase1] sA14_SetReWriteSheetValue
       ↓ ReWriteSheetValue雛形(アドレス行/値行の交互配置)
     [手動編集] ユーザーが値行を編集
       ↓
     [A14 Phase2] sA14_ExecuteReWriteSheetValue
       ↓ 元のエクセルファイルのシートを一括更新
     [完了] 元ファイルが編集後の値で更新される
    ―――――――――――――――――――――――――――――――――――

※前提:事前に A05_CollectExcelSheet(記事T02) でMapping/Valueシートが整備されている必要があります。
※逐次、コードの改良を行っていきます。詳しい使い方は別の記事で紹介していきます。

収録プロシージャ

【Run系】ボタンに割り当てて実行するプロシージャ
 Run_A14_ReWriteSheetValue              Phase選択InputBoxで Set/Execute を分岐実行
 Run_sA14_SetReWriteSheetValue          Phase1雛形作成のみ単独実行
 Run_sA14_ExecuteReWriteSheetValue      Phase2書込実行のみ単独実行

【A14】飛び地セル一括更新
 A14_ReWriteSheetValue                  本体(Phaseディスパッチャ)
 sA14_SetReWriteSheetValue              Phase1:Mapping×Value→ReWriteSheetValue雛形作成
 sA14_ExecuteReWriteSheetValue          Phase2:編集後値を元エクセルへ書戻し
 sA14_EnsureSheet                       指定名のシートを取得(無ければ作成)
 sA14_CopyHyperlink                     セルのハイパーリンクを別セルへ複製
 sA14_GetHyperlinkAddress                セルのハイパーリンクからファイルパスを取得
 lngWriteCountForFile                   1ファイルあたりの書込件数をカウント
 sA14_MarkFailedFile                    書込失敗ファイル行に赤字マーカーを付与

【Set系】独立ファンクション(複数プロシージャから共通利用)
 Set_DesktopPath                        デスクトップパス取得
 Set_FolderName                         パスからフォルダ名抽出
 Set_FileDialogFolderPicker             フォルダを1つ選択
 Set_FileDialogFolderPickers            複数フォルダを選択
 Set_FileDialogFoldersFilesPicker       フォルダ+ファイル複数選択
 Set_SheetDefaultFormat                 シート共通書式(フォント・配置)を一括適用
 Set_ColorPalette                       ★全A系プロシージャ共通カラーパレット一括設定
 Set_DefaultFormatVars                  シート共通デフォルト書式変数の値設定

命名規則及び用語の定義

Run_    : ボタンに割り当てるプロシージャ(初期設定+本体呼び出し)
Axx_    : A系統のメインプロシージャ(2桁番号)
sAxx_   : 各メインのサブプロシージャ
Set_    : 複数プロシージャから共通利用する独立ファンクション
m_      : モジュールレベルPrivate変数
CST_    : ローカルConst定数
ProcXX  : プロシージャ内のコード番地(修正・査読の共通言語)
str/lng/bln/obj/ws/dbl : 変数の型を示す接頭辞

正統処理:
 正統処理(Orthodox Processing)とは、メインプロシージャの目的を達成するために順序通りに実行される省略不可能な一連のサブプロシージャのこと。
 各ステップが成功(True)すれば次のステップへ進み、本流が一直線に貫かれる。
分岐処理:
 分岐処理(Branch Processing)とは、正統処理の本流から枝分かれして実行される条件付き・選択的なサブプロシージャのこと。
 ユーザーの選択(InputBox/MsgBox)、正統処理が失敗(False)した際のエラーフォールバック、または設定フラグの真偽値によって発動の可否が決まり、該当条件に当てはまらなければスキップされる。実行されなくてもメインプロシージャの主目的は達成可能であり、副次機能・補助機能・回復処理として本流に付随する。

【A14の2段階ワークフロー】
Phase1:sA14_SetReWriteSheetValue   雛形作成(Mapping × Value → ReWriteSheetValue)
      交互配置:アドレス行(青系)/値行(黄系)
Phase2:sA14_ExecuteReWriteSheetValue  書込実行(編集値→元エクセル)
      失敗ファイルは赤字マーカーで可視化

【データ構造の比喩】
麺(Value)        : Cells.Value 配列でCOM一括取得・書込
スープ(NumberFormat): 個別取得・書込(書式情報)
 → 値と書式を別配列で扱う「ダブル配列パターン」
 → A05からの一貫した設計思想

使い方

■ 前提(事前に実行済みであること)
 STEP0 A05_CollectExcelSheet(記事T02)を実行
     → Mappingシート整備(シート名・セル番地登録)
     → Valueシート整備(飛び地値が集約済み)

■ A14 一括書戻しを使う場合
 STEP1 ExcelのVBAエディタ(Alt+F11)を開く
 STEP2 シートモジュール(Sheet1等)にコードを貼り付ける
 STEP3 Run_A14_ReWriteSheetValue を実行
     → Phase選択InputBox表示
     → "1" 入力:Phase1(雛形作成)

 STEP4 ReWriteSheetValueシートが自動生成される
     (アドレス行/値行の交互配置・色分け済み)

 STEP5 ユーザーが値行のセルを直接編集
     → 編集したい値だけ書き換え

 STEP6 もう一度 Run_A14_ReWriteSheetValue を実行
     → "2" 入力:Phase2(書込実行)
     → 元エクセルファイルへ一括書戻し
     → 失敗ファイルは赤字マーカー表示

■ 単独実行(上級者向け)
 Run_sA14_SetReWriteSheetValue       Phase1のみ実行
 Run_sA14_ExecuteReWriteSheetValue   Phase2のみ実行

コード全文

Option Explicit
' ===========================================================================
' |  ZENNブログ記事 その3 - 飛び地セル一括書戻し(A14: ReWriteSheetValue)
' |  ファイル: ZENN記事_その3_VBA0+A14_一括書戻し.cls
' |  作成日: 20260506
' |  Ver.0105 [20260506] 機能番号01・更新番号05
' |  内容: VBA0(共通) + A14: 飛び地セル一括書戻し(A05のValue→元エクセル)
' |  使い方: シートモジュールにそのまま貼り付ければ動作
' |  前提: A05_CollectExcelSheet で Mapping/Value シート整備済み
' ===========================================================================

' === A14 Ver.変更履歴 ======================================================
'   Ver.0100 [20260506] 初版(Mapping × Value → ReWriteSheetValue 生成)
'   Ver.0101 [20260506] レイアウト改訂(アドレス行+入力行 交互配置)
'   Ver.0102 [20260506] 入力行Value既存値プリセット(A05ダブル配列パターン)
'   Ver.0103 [20260506] Proc06再実行時merge残留対策(Cells.UnMerge追加)
'   Ver.0104 [20260506] Proc08-4 C+空欄症状対策(per-cell書込みに変更)
'   Ver.0105 [20260506] Debug.Print デバッグコード削除(クリーンアップ)
' ===========================================================================

Private m_lngColorDepth1    As Long     ' メインフォルダを示す(深さ1)背景色
Private m_lngColorDepth2    As Long     ' サブフォルダを示す(深さ2)背景色
Private m_lngColorDepth3    As Long     ' サブサブフォルダを示す(深さ3)背景色
Private m_lngColorDepth4    As Long     ' サブサブサブ以下(深さ4+)背景色
Private m_blnShowScreen     As Boolean  ' VBA実行画面表示(True=表示/False=抑制)
Private m_strPrefixCode     As String   ' A04_コピー時のファイル名先頭文字
Private m_lngColorHeader    As Long     ' ヘッダー背景色
Private m_blnAdvancedPicker As Boolean  ' 上級者向け複数のフォルダおよびファイル選択(False=単一選択/True=複数可)
        'A01_ListFilesの初期設定で使用。False(初期値)ならフォルダ単位で1回選択、Trueなら複数のフォルダとファイルを選択可能にする。
'--------------------------------------------
Private m_lngInteriorColorDeduplication1 As Long  ' 重複判定_背景色:重複無しの場合のセル背景色
Private m_lngInteriorColorDeduplication2 As Long  ' 重複判定_背景色:2個の場合のセル背景色
Private m_lngInteriorColorDeduplication3 As Long  ' 重複判定_背景色:3~5個の場合のセル背景色
Private m_lngInteriorColorDeduplication4 As Long  ' 重複判定_背景色:6個以上の場合のセル背景色
Private m_lngFontColorDeduplication1     As Long  ' 重複判定_文字色:重複無しの場合の文字色
Private m_lngFontColorDeduplication2     As Long  ' 重複判定_文字色:2個の場合の文字色
Private m_lngFontColorDeduplication3     As Long  ' 重複判定_文字色:3~5個の場合の文字色
Private m_lngFontColorDeduplication4     As Long  ' 重複判定_文字色:6個以上の場合の文字色
'--------------------------------------------
Private m_lngA05ColorMappingHeader       As Long  ' A05 Mapping雛形_ヘッダー背景色(薄黄色)
Private m_lngA05ColorMappingSample       As Long  ' A05 Mapping雛形_サンプル行背景色(薄青)
Private m_lngA05ColorMappingSheetName    As Long  ' A05 Mapping雛形_シート名列文字色(赤字)
Private m_lngA05ColorMappingBorder       As Long  ' A05 Mapping雛形_罫線色(灰色)
Private m_lngA05ColorMappingHelp         As Long  ' A05 Mapping雛形_使い方解説背景色(薄ベージュ)
Private m_lngA05ColorValueHeader         As Long  ' A05 Valueシート_ヘッダー背景色(薄黄色)
'--------------------------------------------
Private m_lngA07ColorFileRow             As Long  ' A07 シート管理_Row1ファイル名行の背景色(薄青)
Private m_lngA07ColorLabel               As Long  ' A07 シート管理_A列ラベル(現在名/変更後)の背景色(薄黄)
Private m_lngA07ColorAfterCell           As Long  ' A07 シート管理_Row3「変更後」入力欄の背景色(薄ベージュ)
Private m_lngA07ColorChanged             As Long  ' A08 リネーム成功セルの背景色(淡緑)
Private m_lngA07ColorError               As Long  ' A08 開けない/重複等のエラー表示色(薄赤)
'--------------------------------------------
' === A01 H列「MD有無」の対象外(ファイル行)書式 ===
' [追加:20260429] フォルダ以外(ファイル行)の対象外表示用
Private m_strA01MdCheckOutOfScope        As String  ' 対象外表示文字("―" 全角ダッシュ)
Private m_lngA01MdCheckOutOfScopeFontColor As Long  ' 対象外文字色(灰色25% RGB(191,191,191))
Private m_lngA01MdCheckOutOfScopeAlign   As Long    ' 対象外配置(xlRight)
'--------------------------------------------
' === シート共通デフォルト書式 ============================================
' どの A系プロシージャからも参照される共通の見た目設定
' Set_SheetDefaultFormat(ws) でシート全体に一括適用する
Private m_strDefaultFontName             As String ' シート共通:フォント名(例 "Century")
Private m_lngDefaultFontSize             As Long   ' シート共通:フォントサイズ(例 14)
Private m_lngDefaultVAlign               As Long   ' シート共通:縦方向配置(xlCenter等)
Private m_lngDefaultHAlign               As Long   ' シート共通:横方向配置(xlCenter等)
'--------------------------------------------
' === シート共通カラーパレット(連番プリセット) ============================
' Run_系プロシージャで番号ごとに用途を割り当てる
'   例:m_FontColor01 = 入力欄文字色、m_BgColor01 = ヘッダー背景色 など
' 4色プリセット(必要に応じて拡張可)
Private m_FontColor01                    As Long   ' フォント色01
Private m_FontColor02                    As Long   ' フォント色02
Private m_FontColor03                    As Long   ' フォント色03
Private m_FontColor04                    As Long   ' フォント色04
Private m_BgColor01                      As Long   ' 背景色01
Private m_BgColor02                      As Long   ' 背景色02
Private m_BgColor03                      As Long   ' 背景色03
Private m_BgColor04                      As Long   ' 背景色04
'--------------------------------------------
' === シート管理5モード専用カラー+プルダウン文言 [追加:20260503] ===========
' HTMLプロトタイプ(シート管理_5モード_prototype.html)と完全同期
'   操作1-1: シート名変更   緑系(安全な書換)
'   操作1-2: シート名削除   赤系(危険操作)
'   操作1-3: シート名集約   橙系(抽出)
'   操作2-1: 値と値の書式   紫系(変換固定)
'   操作2-2: シート書式リセット 青緑系(構造変更、4処理統合)
Private m_strMode1_1_Placeholder         As String ' "/変更後シート名入力/" 操作1-1初期プリフィル
Private m_strMode1_2_YesText             As String ' "はい(削除)"
Private m_strMode1_3_YesText             As String ' "はい(集約対象)"
Private m_strMode2_1_YesText             As String ' "はい(値固定)"
Private m_strMode2_2_YesText             As String ' "はい(書式リセット)" [仕様変更:20260503]
Private m_lngMode1_1_Bg                  As Long   ' 1-1 背景色(緑系)
Private m_lngMode1_1_Font                As Long   ' 1-1 文字色
Private m_lngMode1_2_Bg                  As Long   ' 1-2 背景色(赤系)
Private m_lngMode1_2_Font                As Long   ' 1-2 文字色
Private m_lngMode1_3_Bg                  As Long   ' 1-3 背景色(橙系)
Private m_lngMode1_3_Font                As Long   ' 1-3 文字色
Private m_lngMode2_1_Bg                  As Long   ' 2-1 背景色(紫系)
Private m_lngMode2_1_Font                As Long   ' 2-1 文字色
Private m_lngMode2_2_Bg                  As Long   ' 2-2 背景色(青緑系)
Private m_lngMode2_2_Font                As Long   ' 2-2 文字色
'--------------------------------------------
' === A12 シート書式リセット 4フラグ [追加:20260503] [Const化:20260503] ===
' モジュールレベル定数として宣言+初期値を一行完結で固定化(動的変更なし)
' ★この True/False を直接書き換えれば挙動が切替わる★
' Run_A12_ResetSheetFormat 初期化不要、A12_ResetSheetFormat 本体で直接参照
Private Const CST_blnA12_Unmerge         As Boolean = True  ' ①結合解除(Cells.UnMerge)
Private Const CST_blnA12_ClearBgColor    As Boolean = True  ' ②セル背景色無し(ColorIndex=xlNone)
Private Const CST_blnA12_ResetFontColor  As Boolean = True  ' ③セル文字色黒(Font.Color=RGB(0,0,0))
Private Const CST_blnA12_UnfreezePanes   As Boolean = True  ' ④ウィンドウ枠の固定解除(FreezePanes=False)
'--------------------------------------------
' === A05 Valueシート空欄行削除 必須入力個数 [追加:20260503] ===
' モジュールレベル定数として宣言+初期値を一行完結で固定化
' Valueシート各行のC列以降(CntColNum個)について、
' 入力済みセル数 < CST_lngA05_KeepRowNum なら、その行を削除する
' ★この数値を直接書き換えれば判定基準が切替わる★
Private Const CST_lngA05_KeepRowNum      As Long = 2          ' 必須入力個数(既定2個、これ未満は空欄行扱いで削除)
'--------------------------------------------
' === A06 等差展開 組ごと交互背景色 [追加:20260503] ===
' モジュールレベル定数として宣言+初期値を一行完結で固定化
' 1組目(奇数組)= 背景色なし(xlNone)/ 2組目(偶数組)= CST_lngA06_AlternateBg(薄黄)
' 視認性向上のため組ごとの境界をストライプで強調する
Private Const CST_lngA06_AlternateBg     As Long = 14809343    ' RGB(255, 248, 225) 薄黄(偶数組の背景色)
'--------------------------------------------



' =============================================================
' |  A14のプロシージャ群: Mapping × Value 一括書戻し
' =============================================================

' ────────────────────────────────────────────────────────────
' ■ 実行プロシージャRun系(A14メイン + Phase別単独実行)
' ────────────────────────────────────────────────────────────

' ===================================
' Run_A14_ReWriteSheetValue
' A14_ReWriteSheetValue の実行用プロシージャ
' Phase選択InputBoxで Set or Execute を選ぶ
' ===================================
' [更新日:20260506]
Public Sub Run_A14_ReWriteSheetValue()

    'Proc01_カラーパレット一括設定(全A系統で共通)
    Call Set_ColorPalette

    'Proc02_本体プロシージャを呼び出し
    Me.A14_ReWriteSheetValue

End Sub


' ===================================
' Run_sA14_SetReWriteSheetValue
' sA14_SetReWriteSheetValue の単独実行用 実行プロシージャRun系
' Mapping × Value → ReWriteSheetValue 雛形作成
' ===================================
' [更新日:20260506]
Public Sub Run_sA14_SetReWriteSheetValue()

    'Proc01_カラーパレット一括設定
    Call Set_ColorPalette

    'Proc02_本体プロシージャを呼び出し
    Me.sA14_SetReWriteSheetValue

End Sub


' ===================================
' Run_sA14_ExecuteReWriteSheetValue
' sA14_ExecuteReWriteSheetValue の単独実行用 実行プロシージャRun系
' ReWriteSheetValue の編集値を元のエクセルファイルのシートへ一括更新
' ===================================
' [更新日:20260506]
Public Sub Run_sA14_ExecuteReWriteSheetValue()

    'Proc01_カラーパレット一括設定
    Call Set_ColorPalette

    'Proc02_本体プロシージャを呼び出し
    Me.sA14_ExecuteReWriteSheetValue

End Sub


' ────────────────────────────────────────────────────────────
' ■ A系メイン(A14本体プロシージャ+直下にsA系サブを正統処理順で配置)
' ────────────────────────────────────────────────────────────

' ===================================
' A14_ReWriteSheetValue(Ver.0105)(メインプロシージャ)
' Phase選択dispatcher
'   Ver.変更履歴はファイル冒頭の === Ver.変更履歴 === ブロックを参照
' ===================================
' [更新日:20260506]
Sub A14_ReWriteSheetValue()
'2段階ワークフロー:
'  Phase1=雛形作成(Set) / Phase2手動編集 / Phase3=書込実行(Execute)
'本メインは Phase1/3 を InputBox で選択して該当sAを呼ぶdispatcher

    Dim strPhase As String

    'Proc01_Phase選択InputBox
    strPhase = InputBox( _
        "A14 ReWriteSheetValue 一括書戻し" & vbCrLf & vbCrLf & _
        "[1] ReWriteSheetValue 雛形作成(Mapping × Value → 編集用雛形)" & vbCrLf & _
        "[2] 元エクセルへ書込実行(編集後の値を一括書戻し)" & vbCrLf & vbCrLf & _
        "事前に A05_CollectExcelSheet で Mapping/Value 整備済が前提です。" & vbCrLf & _
        "1 または 2 を入力してください(キャンセルで終了)", _
        "A14 Phase選択", "1")

    'Proc02_Phase別dispatch
    Select Case Trim(strPhase)
        Case "1"
            Call sA14_SetReWriteSheetValue
        Case "2"
            Call sA14_ExecuteReWriteSheetValue
        Case ""
            Exit Sub  ' キャンセル
        Case Else
            MsgBox "1 または 2 を入力してください。", vbExclamation, "A14 Phase選択"
    End Select

End Sub


' ────────────────────────────────────────────────────────────
' ■ 正統処理: Phase1 雛形作成(Mapping × Value → ReWriteSheetValue)
' ────────────────────────────────────────────────────────────

' ===================================
' sA14_SetReWriteSheetValue
' Mapping シートと Value シートを掛け合わせて
' ReWriteSheetValue シートの雛形を作成
'   - Value 各行に対し、対応する Mapping 行(セルアドレス)を直前に挿入
'   - 結果: アドレス行 / 値行 / アドレス行 / 値行 … の交互配置
' ===================================
' [更新日:20260506]
Sub sA14_SetReWriteSheetValue()

    ' ローカル定数
    Const CST_SHEET_MAPPING    As String = "Mapping"
    Const CST_SHEET_VALUE      As String = "Value"
    Const CST_SHEET_REWRITE    As String = "ReWriteSheetValue"
    ' [削除:20260506] CST_ADDR_ROW_MARKER ─ アドレス行はファイル名(リンク)で識別する方式に変更

    Dim wsMapping       As Worksheet
    Dim wsValue         As Worksheet
    Dim wsReWrite       As Worksheet
    Dim dictMap         As Object       ' {sheetName: Collection of {RowIndex, Addresses}}
    Dim dictCounter     As Object       ' {fileName|sheetName: 現在のスロットIndex}
    Dim lngLastColM     As Long
    Dim lngLastRowM     As Long
    Dim lngLastRowV     As Long
    Dim arrHeaders      As Variant
    Dim r               As Long
    Dim j               As Long
    Dim strSheetName    As String
    Dim strFileName     As String
    Dim strKey          As String
    Dim colSlots        As Collection
    Dim dictSlot        As Object
    Dim arrAddresses    As Variant
    Dim lngOutRow       As Long
    Dim lngSlotIndex    As Long
    Dim lngOldCalc      As Long
    Dim varVal          As Variant
    Dim arrRowValues    As Variant     ' [追加:20260506] 麺=Value配列(COM一括取得)
    Dim arrRowFormats() As String      ' [追加:20260506] スープ=NumberFormat配列(個別取得)
    Dim lngRowWidth     As Long        ' [追加:20260506] 1行の列数

    'Proc00_パフォーマンス設定
    On Error GoTo ErrHandler
    lngOldCalc = Application.Calculation
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False
    Application.DisplayAlerts = False

    'Proc01_Mappingシート存在確認
    On Error Resume Next
    Set wsMapping = Nothing
    Set wsMapping = ThisWorkbook.Worksheets(CST_SHEET_MAPPING)
    On Error GoTo ErrHandler
    If wsMapping Is Nothing Then
        MsgBox "Mapping シートが見つかりません。" & vbCrLf & _
               "先に A05_CollectExcelSheet を実行してください。", _
               vbExclamation, "A14 Set Phase1"
        GoTo Cleanup
    End If

    'Proc02_Valueシート存在確認
    On Error Resume Next
    Set wsValue = Nothing
    Set wsValue = ThisWorkbook.Worksheets(CST_SHEET_VALUE)
    On Error GoTo ErrHandler
    If wsValue Is Nothing Then
        MsgBox "Value シートが見つかりません。" & vbCrLf & _
               "先に A05_CollectExcelSheet を実行してください。", _
               vbExclamation, "A14 Set Phase1"
        GoTo Cleanup
    End If

    'Proc03_Mapping最終列・行
    lngLastColM = wsMapping.Cells(1, wsMapping.Columns.Count).End(xlToLeft).Column
    lngLastRowM = wsMapping.Cells(wsMapping.Rows.Count, 1).End(xlUp).Row
    If lngLastRowM < 2 Or lngLastColM < 2 Then
        MsgBox "Mapping にデータがありません(2行目以降のシート名+セル位置が必須)。", _
               vbExclamation, "A14 Set Phase1"
        GoTo Cleanup
    End If

    'Proc04_Value最終行
    lngLastRowV = wsValue.Cells(wsValue.Rows.Count, 1).End(xlUp).Row
    If lngLastRowV < 2 Then
        MsgBox "Value にデータがありません。先に A05_CollectExcelSheet を実行してください。", _
               vbExclamation, "A14 Set Phase1"
        GoTo Cleanup
    End If

    'Proc05_Mapping辞書化(SheetName → Collection of {RowIndex, Addresses})
    Set dictMap = CreateObject("Scripting.Dictionary")
    For r = 2 To lngLastRowM
        strSheetName = CStr(wsMapping.Cells(r, 1).Value)
        If strSheetName = "" Then GoTo NextMapRow

        ' アドレス配列構築(B列以降)
        ReDim arrAddresses(1 To lngLastColM - 1)
        For j = 2 To lngLastColM
            arrAddresses(j - 1) = CStr(wsMapping.Cells(r, j).Value)
        Next j

        ' SheetName ごとに Collection を持たせる
        If Not dictMap.Exists(strSheetName) Then
            Set colSlots = New Collection
            dictMap.Add strSheetName, colSlots
        Else
            Set colSlots = dictMap(strSheetName)
        End If

        Set dictSlot = CreateObject("Scripting.Dictionary")
        dictSlot("RowIndex") = r
        dictSlot("Addresses") = arrAddresses
        colSlots.Add dictSlot

NextMapRow:
    Next r

    'Proc06_ReWriteSheetValue 確保とクリア
    '   ★[修正:20260506-3] 既存merge状態を確実に解除してから値・書式書込
    '       前回実行で残ったmergeがあるとProc08-4の A+B結合が誤動作するため、
    '       UnMerge → Clear の順で完全初期化する
    Set wsReWrite = sA14_EnsureSheet(CST_SHEET_REWRITE)
    On Error Resume Next
    wsReWrite.Cells.UnMerge
    On Error GoTo ErrHandler
    wsReWrite.Cells.Clear

    'Proc07_ヘッダー行コピー(Valueのヘッダーをそのまま使用)
    arrHeaders = wsValue.Range(wsValue.Cells(1, 1), _
                               wsValue.Cells(1, lngLastColM + 1)).Value
    wsReWrite.Range(wsReWrite.Cells(1, 1), _
                    wsReWrite.Cells(1, lngLastColM + 1)).Value = arrHeaders
    With wsReWrite.Rows(1)
        .Font.Bold = True
        .Interior.Color = m_lngA05ColorValueHeader
    End With

    'Proc08_Value各行を走査して交互配置
    Set dictCounter = CreateObject("Scripting.Dictionary")
    lngOutRow = 2
    For r = 2 To lngLastRowV
        strFileName = CStr(wsValue.Cells(r, 1).Value)
        strSheetName = CStr(wsValue.Cells(r, 2).Value)
        If strFileName = "" Or strSheetName = "" Then GoTo NextValRow

        'Proc08-1_(file,sheet) 単位のスロットIndex取得
        strKey = strFileName & "|" & strSheetName
        If dictCounter.Exists(strKey) Then
            dictCounter(strKey) = dictCounter(strKey) + 1
        Else
            dictCounter.Add strKey, 1
        End If
        lngSlotIndex = dictCounter(strKey)

        'Proc08-2_対応するMappingスロット取得
        If Not dictMap.Exists(strSheetName) Then GoTo NextValRow
        Set colSlots = dictMap(strSheetName)
        If lngSlotIndex < 1 Or lngSlotIndex > colSlots.Count Then
            ' Mapping行数を超えた → スロット無し(ファイル切替などで起き得る)
            ' 既存スロット数で循環させる(modulo)
            lngSlotIndex = ((lngSlotIndex - 1) Mod colSlots.Count) + 1
            dictCounter(strKey) = lngSlotIndex
        End If
        Set dictSlot = colSlots(lngSlotIndex)
        arrAddresses = dictSlot("Addresses")

        'Proc08-3_アドレス行を出力(A05パターン: 配列1=値一括書込・配列2=書式個別書込)
        '   ★[仕様変更:20260506] アドレス行=緑系背景、ファイル名のリンクをCol Aに配置
        '   ★[A05整合:20260506] 配列1(値)= [ファイル名, シート名, addr1, addr2…] を一括書込
        '                       配列2(書式)= 全セル "@"(文字列固定)を個別書込
        lngRowWidth = lngLastColM + 1

        '   配列1(麺=値)構築
        ReDim arrRowValues(1 To lngRowWidth)
        arrRowValues(1) = strFileName
        arrRowValues(2) = strSheetName
        For j = LBound(arrAddresses) To UBound(arrAddresses)
            arrRowValues(2 + j) = arrAddresses(j)
        Next j
        '   配列2(スープ=書式)構築: アドレス行は全セル文字列固定
        ReDim arrRowFormats(1 To lngRowWidth)
        For j = 1 To lngRowWidth
            arrRowFormats(j) = "@"
        Next j

        '   配列1(値)を Range一括書込(COM 1回)
        wsReWrite.Range(wsReWrite.Cells(lngOutRow, 1), _
                        wsReWrite.Cells(lngOutRow, lngRowWidth)).Value = arrRowValues
        '   配列2(書式)をセル毎に個別セット(NumberFormatは配列代入不可)
        For j = 1 To lngRowWidth
            wsReWrite.Cells(lngOutRow, j).NumberFormat = arrRowFormats(j)
        Next j

        ' Col A をハイパーリンク化(Valueのファイル名リンクを再現)
        Call sA14_CopyHyperlink(wsValue, r, wsReWrite, lngOutRow)
        With wsReWrite.Range(wsReWrite.Cells(lngOutRow, 1), _
                             wsReWrite.Cells(lngOutRow, lngRowWidth))
            .Interior.Color = m_BgColor04      ' 淡緑: アドレス行(編集対象外)
            .Font.Italic = False
            .Font.Color = RGB(0, 0, 0)         ' 黒
        End With
        ' Col C+(セルアドレス部分)はやや薄い文字色+イタリックで「編集対象外」を視覚化
        With wsReWrite.Range(wsReWrite.Cells(lngOutRow, 3), _
                             wsReWrite.Cells(lngOutRow, lngRowWidth))
            .Font.Italic = True
            .Font.Color = RGB(80, 80, 80)
        End With

        lngOutRow = lngOutRow + 1

        'Proc08-4_更新後の値入力行(A05パターン: 配列1=Value既存値・配列2=Value由来書式)
        '   ★[仕様変更:20260506-2] Value既存値をC+に予め入力(ユーザーが上書き更新する方式)
        '   ★[A05整合:20260506] 配列1(値)= ValueのC+を一括書込
        '                       配列2(書式)= ValueのNumberFormatを個別書込
        '   - A+B を横方向に結合し「上書き更新後の値」を中央揃えで表示
        '   - C列以降はValueシートの該当行の値を予め入力済み
        '   - ユーザーは必要なセルのみ上書き編集 → Phase3で元エクセルへ反映
        '   - 背景色なし(白)でどんどん編集できる視認性

        '   A+B 結合してラベル表示
        With wsReWrite.Range(wsReWrite.Cells(lngOutRow, 1), _
                             wsReWrite.Cells(lngOutRow, 2))
            .Merge
            .Value = "上書き更新後の値"
            .HorizontalAlignment = xlCenter
            .VerticalAlignment = xlCenter
            .Font.Italic = False
            .Font.Color = RGB(120, 120, 120)   ' 灰色: ラベル感
            .Interior.ColorIndex = xlNone      ' 背景色なし
        End With

        '   配列1(麺=値)構築: ValueシートのC+の値を取得(C列開始のサイズ)
        '   配列2(スープ=書式)構築: ValueシートのC+のNumberFormat
        '   ※C+の列数 = lngRowWidth - 2(Col A,B分を除く)
        Dim lngColCInputCount As Long
        lngColCInputCount = lngRowWidth - 2
        ReDim arrRowValues(1 To lngColCInputCount)
        ReDim arrRowFormats(1 To lngColCInputCount)
        For j = 1 To lngColCInputCount
            arrRowValues(j) = wsValue.Cells(r, j + 2).Value
            arrRowFormats(j) = wsValue.Cells(r, j + 2).NumberFormat
        Next j

        '   ★[修正:Ver.0104:20260506] バルク書込みが効かないケースに対応するため
        '       per-cell ループ書込みに変更(A05のスープと同じ個別書込)
        '       ※C+の値が空欄になる症状の根本対策(動作確認済 Ver.0105:20260506)
        '       Range.Resize.Value 一括書込が A:B merge 直後の同じ行で機能しない事象あり
        '   ★[Ver.0105:20260506] Debug.Print デバッグコード削除(動作確認完了)
        For j = 1 To lngColCInputCount
            wsReWrite.Cells(lngOutRow, j + 2).Value = arrRowValues(j)
            wsReWrite.Cells(lngOutRow, j + 2).NumberFormat = arrRowFormats(j)
        Next j

        ' Col C+ 背景色なし(白)で入力エリアを視覚化
        With wsReWrite.Range(wsReWrite.Cells(lngOutRow, 3), _
                             wsReWrite.Cells(lngOutRow, lngRowWidth))
            .Interior.ColorIndex = xlNone
        End With

        lngOutRow = lngOutRow + 1
NextValRow:
    Next r

    'Proc09_罫線
    If lngOutRow > 2 Then
        With wsReWrite.Range(wsReWrite.Cells(1, 1), _
                             wsReWrite.Cells(lngOutRow - 1, lngLastColM + 1))
            .Borders.LineStyle = xlContinuous
        End With
    End If

    'Proc10_列幅自動調整
    wsReWrite.Columns("A:Z").AutoFit

    'Proc11_完了通知
    MsgBox "ReWriteSheetValue 雛形を作成しました。" & vbCrLf & vbCrLf & _
           "出力行数: " & (lngOutRow - 1) & " 行" & vbCrLf & _
           "(アドレス行(淡緑) + 上書き更新後の値入力行(白) の交互配置)" & vbCrLf & vbCrLf & _
           "次の手順:" & vbCrLf & _
           "  1. 入力行(白)C列以降には Valueシートの既存値が予め入力されている" & vbCrLf & _
           "     必要なセルだけ上書きで編集(書式は元のまま継承済)" & vbCrLf & _
           "     ★空欄にしたセルは書戻しスキップ=元エクセル維持" & vbCrLf & _
           "  2. 編集完了後、Run_sA14_ExecuteReWriteSheetValue を実行" & vbCrLf & _
           "  3. 元エクセルファイルへ一括書戻し", _
           vbInformation, "A14 Phase1 完了"
    GoTo Cleanup

ErrHandler:
    MsgBox "エラー: " & Err.Number & " - " & Err.Description, vbCritical, "A14 Set Phase1"

Cleanup:
    Application.ScreenUpdating = True
    Application.Calculation = lngOldCalc
    Application.EnableEvents = True
    Application.DisplayAlerts = True

End Sub


' ────────────────────────────────────────────────────────────
' ■ 正統処理: Phase3 書込実行(ReWriteSheetValue → 元エクセル)
' ────────────────────────────────────────────────────────────

' ===================================
' sA14_ExecuteReWriteSheetValue
' ReWriteSheetValue の編集値を対応する元エクセルファイルのシートへ一括更新
'   - 値行のCol Aハイパーリンクからファイルパスを取得
'   - 直前のアドレス行から書込先セルアドレスを取得
'   - シート名はCol B
'   - 各エクセルを開き、指定セルに書込→保存→閉じる
' ===================================
' [更新日:20260506]
Sub sA14_ExecuteReWriteSheetValue()

    ' ローカル定数
    Const CST_SHEET_REWRITE    As String = "ReWriteSheetValue"
    ' [削除:20260506] CST_ADDR_ROW_MARKER ─ アドレス行はファイル名(リンク)で識別する方式に変更

    Dim wsReWrite       As Worksheet
    Dim lngLastRow      As Long
    Dim lngLastCol      As Long
    Dim r               As Long
    Dim j               As Long
    Dim strSheetName    As String
    Dim strFilePath     As String
    Dim arrAddresses()  As String
    Dim arrNewValues()  As Variant
    Dim wbSrc           As Workbook
    Dim wsSrc           As Worksheet
    Dim rngTarget       As Range
    Dim lngOldCalc      As Long
    Dim lngTotalFiles   As Long
    Dim lngFileIndex    As Long
    Dim dictByFile      As Object       ' {filePath: Collection of {SheetName, Addr, Value}}
    Dim varKey          As Variant
    Dim colWrites       As Collection
    Dim dictWrite       As Object
    Dim varW            As Variant
    Dim lngAnswer       As Long
    Dim lngWriteCount   As Long
    Dim lngFailCount    As Long
    Dim lngOpenFailed   As Long
    Dim strReport       As String
    Dim dblStartTime    As Double
    Dim dblElapsed      As Double

    'Proc00_開始時刻
    dblStartTime = Timer

    'Proc00-1_パフォーマンス設定
    On Error GoTo ErrHandler
    lngOldCalc = Application.Calculation
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False
    Application.DisplayAlerts = False

    'Proc01_ReWriteSheetValueシート確認
    On Error Resume Next
    Set wsReWrite = Nothing
    Set wsReWrite = ThisWorkbook.Worksheets(CST_SHEET_REWRITE)
    On Error GoTo ErrHandler
    If wsReWrite Is Nothing Then
        MsgBox "ReWriteSheetValue シートがありません。" & vbCrLf & _
               "先に Run_sA14_SetReWriteSheetValue を実行してください。", _
               vbExclamation, "A14 Execute Phase3"
        GoTo Cleanup
    End If

    lngLastRow = wsReWrite.Cells(wsReWrite.Rows.Count, 2).End(xlUp).Row
    lngLastCol = wsReWrite.Cells(1, wsReWrite.Columns.Count).End(xlToLeft).Column
    If lngLastRow < 3 Or lngLastCol < 3 Then
        MsgBox "ReWriteSheetValue にデータがありません。", _
               vbExclamation, "A14 Execute Phase3"
        GoTo Cleanup
    End If

    'Proc02_実行確認MsgBox
    lngAnswer = MsgBox( _
        "ReWriteSheetValue の編集値を元エクセルに一括書戻します。" & vbCrLf & vbCrLf & _
        "実行行数: 約 " & ((lngLastRow - 1) \ 2) & " 件(値行)" & vbCrLf & vbCrLf & _
        "★この操作は元ファイルを変更します。事前にバックアップを推奨。" & vbCrLf & vbCrLf & _
        "実行しますか?", _
        vbYesNo + vbExclamation, "A14 Execute 実行確認")
    If lngAnswer <> vbYes Then GoTo Cleanup

    'Proc03_書込タスクをファイル別Dictionaryに集約(ファイルを1回だけ開いて全書込)
    '   ★[仕様変更:20260506] 新レイアウト対応
    '     - アドレス行: Col A にハイパーリンク(=ファイルパス)、Col B=Sheet、Col C+=セルアドレス
    '     - 入力行: A+B結合「上書き更新後の値」、Col C+=ユーザー入力新値
    '     - 入力行のC列以降が空欄の場合は元エクセルを上書きせずスキップ
    Set dictByFile = CreateObject("Scripting.Dictionary")
    r = 2
    Do While r <= lngLastRow
        ' アドレス行か判定(Col A にハイパーリンクあり)
        strFilePath = sA14_GetHyperlinkAddress(wsReWrite.Cells(r, 1))
        If strFilePath = "" Then
            ' ハイパーリンク無 → アドレス行ではない(入力行 or 空行)→ 次行へ
            r = r + 1
            GoTo NextScanRow
        End If

        ' アドレス行: SheetName と セルアドレス配列を取得
        strSheetName = CStr(wsReWrite.Cells(r, 2).Value)
        ReDim arrAddresses(3 To lngLastCol)
        For j = 3 To lngLastCol
            arrAddresses(j) = CStr(wsReWrite.Cells(r, j).Value)
        Next j

        ' 直後の入力行: 新値配列を取得(C列以降)
        If r + 1 > lngLastRow Then Exit Do
        ReDim arrNewValues(3 To lngLastCol)
        For j = 3 To lngLastCol
            arrNewValues(j) = wsReWrite.Cells(r + 1, j).Value
        Next j

        ' 書込タスク = (SheetName, Addr, NewValue) を file毎に集約
        If Not dictByFile.Exists(strFilePath) Then
            Set colWrites = New Collection
            dictByFile.Add strFilePath, colWrites
        Else
            Set colWrites = dictByFile(strFilePath)
        End If

        For j = 3 To lngLastCol
            If arrAddresses(j) <> "" Then
                ' ★入力値が空欄なら書込スキップ(元エクセルを上書きしない)
                If IsEmpty(arrNewValues(j)) Or Trim(CStr(arrNewValues(j))) = "" Then
                    ' Skip: ユーザーが入力していない箇所は元値維持
                Else
                    Set dictWrite = CreateObject("Scripting.Dictionary")
                    dictWrite("SheetName") = strSheetName
                    dictWrite("Address") = arrAddresses(j)
                    dictWrite("Value") = arrNewValues(j)
                    dictWrite("RowInRW") = r + 1   ' ReWriteSheetValueでの行(フィードバック表示用)
                    dictWrite("ColInRW") = j
                    colWrites.Add dictWrite
                End If
            End If
        Next j

        r = r + 2
NextScanRow:
    Loop

    lngTotalFiles = dictByFile.Count
    If lngTotalFiles = 0 Then
        MsgBox "書込対象が見つかりませんでした。", vbInformation, "A14 Execute Phase3"
        GoTo Cleanup
    End If

    'Proc04_ファイル毎にループして書込
    lngFileIndex = 0
    lngWriteCount = 0
    lngFailCount = 0
    lngOpenFailed = 0
    For Each varKey In dictByFile.Keys
        lngFileIndex = lngFileIndex + 1
        strFilePath = CStr(varKey)
        Set colWrites = dictByFile(strFilePath)

        ' ステータスバー更新
        Application.StatusBar = "A14書戻し中... [" & lngFileIndex & "/" & lngTotalFiles & "] " & _
                                 CreateObject("Scripting.FileSystemObject").GetFileName(strFilePath)
        DoEvents

        'Proc04-1_ファイルを開く(書込モード)
        On Error Resume Next
        Set wbSrc = Nothing
        Set wbSrc = Workbooks.Open(strFilePath, ReadOnly:=False, UpdateLinks:=0)
        If wbSrc Is Nothing Then
            Err.Clear
            On Error GoTo ErrHandler
            lngOpenFailed = lngOpenFailed + lngWriteCountForFile(colWrites)
            ' エラー記録
            Call sA14_MarkFailedFile(wsReWrite, colWrites, "### 開けない")
            GoTo NextFile
        End If
        Err.Clear
        On Error GoTo ErrHandler

        'Proc04-2_各書込タスクを実行
        For Each varW In colWrites
            Set dictWrite = varW
            On Error Resume Next
            Set wsSrc = Nothing
            Set wsSrc = wbSrc.Worksheets(CStr(dictWrite("SheetName")))
            If wsSrc Is Nothing Then
                Err.Clear
                wsReWrite.Cells(dictWrite("RowInRW"), dictWrite("ColInRW")).Interior.Color = RGB(255, 220, 220)
                wsReWrite.Cells(dictWrite("RowInRW"), dictWrite("ColInRW")).AddComment "シート無し: " & dictWrite("SheetName")
                lngFailCount = lngFailCount + 1
            Else
                Set rngTarget = Nothing
                Set rngTarget = wsSrc.Range(CStr(dictWrite("Address")))
                If rngTarget Is Nothing Then
                    Err.Clear
                    wsReWrite.Cells(dictWrite("RowInRW"), dictWrite("ColInRW")).Interior.Color = RGB(255, 220, 220)
                    lngFailCount = lngFailCount + 1
                Else
                    rngTarget.Value = dictWrite("Value")
                    If Err.Number = 0 Then
                        wsReWrite.Cells(dictWrite("RowInRW"), dictWrite("ColInRW")).Interior.Color = m_BgColor04   ' 成功: 淡緑維持
                        lngWriteCount = lngWriteCount + 1
                    Else
                        Err.Clear
                        wsReWrite.Cells(dictWrite("RowInRW"), dictWrite("ColInRW")).Interior.Color = RGB(255, 220, 220)
                        lngFailCount = lngFailCount + 1
                    End If
                End If
            End If
            On Error GoTo ErrHandler
        Next varW

        'Proc04-3_保存して閉じる
        On Error Resume Next
        wbSrc.Save
        wbSrc.Close SaveChanges:=False
        Err.Clear
        On Error GoTo ErrHandler
NextFile:
    Next varKey

    Application.StatusBar = False

    'Proc05_経過時間
    dblElapsed = Timer - dblStartTime
    If dblElapsed < 0 Then dblElapsed = dblElapsed + 86400

    'Proc06_完了通知
    strReport = "書戻し完了:" & vbCrLf & _
                "  対象ファイル: " & lngTotalFiles & " 件" & vbCrLf & _
                "  成功セル: " & lngWriteCount & " 件" & vbCrLf & _
                "  失敗セル: " & lngFailCount & " 件" & vbCrLf
    If lngOpenFailed > 0 Then
        strReport = strReport & "  開けないファイル由来失敗: " & lngOpenFailed & " 件" & vbCrLf
    End If
    strReport = strReport & "  処理時間: " & Format(dblElapsed, "0.000") & " 秒"

    MsgBox strReport, vbInformation, "A14 Phase3 完了"
    GoTo Cleanup

ErrHandler:
    Application.StatusBar = False
    MsgBox "エラー: " & Err.Number & " - " & Err.Description, vbCritical, "A14 Execute Phase3"

Cleanup:
    Application.StatusBar = False
    Application.CutCopyMode = False
    Application.ScreenUpdating = True
    Application.Calculation = lngOldCalc
    Application.EnableEvents = True
    Application.DisplayAlerts = True

End Sub


' ────────────────────────────────────────────────────────────
' ■ 共通サブプロシージャ(A14内部ヘルパー)
' ────────────────────────────────────────────────────────────

' ===================================
' sA14_EnsureSheet
' 指定名のシートを取得、無ければ末尾に作成
'   ※ A05のsA05_EnsureSheetと同じロジック(独立実装で凝集性確保)
' ===================================
' [更新日:20260506]
Private Function sA14_EnsureSheet(strName As String) As Worksheet

    Dim ws As Worksheet

    'Proc01_既存シート検索
    On Error Resume Next
    Set ws = ThisWorkbook.Worksheets(strName)
    On Error GoTo 0

    'Proc02_存在しなければ末尾に新規作成
    If ws Is Nothing Then
        Set ws = ThisWorkbook.Worksheets.Add( _
            After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
        ws.Name = strName
    End If

    'Proc03_戻り値設定
    Set sA14_EnsureSheet = ws

End Function


' ===================================
' sA14_CopyHyperlink
' Valueシートのファイル名セル(Col A)のハイパーリンクをReWriteへコピー
' ===================================
' [更新日:20260506]
Private Sub sA14_CopyHyperlink(wsSrc As Worksheet, _
                                lngSrcRow As Long, _
                                wsDst As Worksheet, _
                                lngDstRow As Long)

    Dim hl          As Hyperlink
    Dim strAddr     As String
    Dim strDisplay  As String

    'Proc01_ソースセルにハイパーリンクがあるか
    If wsSrc.Cells(lngSrcRow, 1).Hyperlinks.Count = 0 Then Exit Sub

    'Proc02_ハイパーリンク情報取得
    Set hl = wsSrc.Cells(lngSrcRow, 1).Hyperlinks(1)
    strAddr = hl.Address
    strDisplay = CStr(wsSrc.Cells(lngSrcRow, 1).Value)

    'Proc03_既存リンク削除&再作成
    On Error Resume Next
    wsDst.Cells(lngDstRow, 1).Hyperlinks.Delete
    wsDst.Hyperlinks.Add _
        Anchor:=wsDst.Cells(lngDstRow, 1), _
        Address:=strAddr, _
        TextToDisplay:=strDisplay
    Err.Clear
    On Error GoTo 0

End Sub


' ===================================
' sA14_GetHyperlinkAddress
' セルのハイパーリンクからアドレス(ファイルパス)を取得
'   なければ "" を返す
' ===================================
' [更新日:20260506]
Private Function sA14_GetHyperlinkAddress(rng As Range) As String

    'Proc01_ハイパーリンク有無チェック
    If rng.Hyperlinks.Count = 0 Then
        sA14_GetHyperlinkAddress = ""
        Exit Function
    End If

    'Proc02_アドレス取得
    sA14_GetHyperlinkAddress = rng.Hyperlinks(1).Address

End Function


' ===================================
' lngWriteCountForFile
' Collectionの要素数をLongで返す(簡易ヘルパー)
' ===================================
Private Function lngWriteCountForFile(col As Collection) As Long
    On Error Resume Next
    lngWriteCountForFile = col.Count
    If Err.Number <> 0 Then lngWriteCountForFile = 0
    Err.Clear
    On Error GoTo 0
End Function


' ===================================
' sA14_MarkFailedFile
' ファイルが開けなかった場合、その全書込タスクの値セルを薄赤化
' ===================================
' [更新日:20260506]
Private Sub sA14_MarkFailedFile(wsReWrite As Worksheet, _
                                  colWrites As Collection, _
                                  strReason As String)

    Dim varW    As Variant
    Dim dictW   As Object

    'Proc01_全タスクをエラー表示
    For Each varW In colWrites
        Set dictW = varW
        On Error Resume Next
        wsReWrite.Cells(dictW("RowInRW"), dictW("ColInRW")).Interior.Color = RGB(255, 220, 220)
        wsReWrite.Cells(dictW("RowInRW"), dictW("ColInRW")).AddComment strReason
        Err.Clear
        On Error GoTo 0
    Next varW

End Sub


' =============================================================
' |  SET グループ: 独立ファンクション(複数プロシージャから共通利用)
' =============================================================

' ===================================
' Set_DesktopPath
' Set_系プロシージャは、様々なプロシージャから呼び出せる独立ファンクション
' デスクトップのパスを返す独立ファンクション
' 戻り値:デスクトップの絶対パス
' ===================================
' [更新日:20260428]
Function Set_DesktopPath() As String

    'Proc01_WScript.Shellでデスクトップパス取得
    Dim objShell As Object
    Set objShell = CreateObject("WScript.Shell")
    Set_DesktopPath = objShell.SpecialFolders("Desktop")
    Set objShell = Nothing

End Function

' ===================================
' Set_FileDialogFolderPickers
' ダイアログボックスを開き、複数のフォルダ選択を行い、パス一覧を返す独立ファンクション
' 呼び出し元プロシージャから引数として、タイトルとボタンラベルを受け取り
' strTitle  ダイアログタイトル
' strPrompt ボタンラベル
' 戻り値:選択フォルダパスの配列(キャンセル時はEmpty)
' ===================================
' [更新日:20260428]
Function Set_FileDialogFolderPickers(strTitle As String, _
                                     strPrompt As String) As Variant

    Dim objDialog        As FileDialog
    Dim strPaths()       As String
    Dim lngCount         As Long
    Dim lngIndex         As Long

    'Proc01_ダイアログ初期化
    Set objDialog = Application.FileDialog(msoFileDialogFolderPicker)

    'Proc02_複数フォルダ選択
    With objDialog
        .Title = strTitle
        .ButtonName = strPrompt
        .AllowMultiSelect = True
        If .Show <> -1 Then
            Set_FileDialogFolderPickers = Empty
            Exit Function
        End If
        lngCount = .SelectedItems.Count
        ReDim strPaths(0 To lngCount - 1)
        For lngIndex = 1 To lngCount
            strPaths(lngIndex - 1) = .SelectedItems(lngIndex)
        Next lngIndex
    End With

    'Proc03_戻り値設定
    Set_FileDialogFolderPickers = strPaths
    Set objDialog = Nothing

End Function

' ===================================
' Set_FolderName
' フォルダパスからフォルダ名を取得する独立ファンクション
' 引数:strFolderPath フォルダのフルパス
' 戻り値:フォルダ名のみ
' ===================================
' [更新日:20260428]
Function Set_FolderName(strFolderPath As String) As String

    'Proc01_FSOでフォルダ名抽出
    Dim objFileSystemObject As Object
    Set objFileSystemObject = CreateObject("Scripting.FileSystemObject")
    Set_FolderName = objFileSystemObject.GetFolder(strFolderPath).Name
    Set objFileSystemObject = Nothing

End Function

' ===================================
' Set_SheetDefaultFormat
' シート共通のデフォルト書式(フォント名・サイズ・縦横配置)を一括適用
' Run_系で初期化済みのモジュール変数を参照する
'   m_strDefaultFontName / m_lngDefaultFontSize
'   m_lngDefaultVAlign   / m_lngDefaultHAlign
' [修正:20260503] 未初期化フォールバック追加(実行時エラー1004回避)
' 引数:ws 適用対象のWorksheet
' ===================================
' [更新日:20260503]
Sub Set_SheetDefaultFormat(ws As Worksheet)

    'Proc01_未初期化フォールバック [追加:20260503]
    ' Run_系を経由せずに本Subが呼ばれた場合、または初期化漏れの場合に
    ' ws.Cells.Font.Size = 0 で発生する 実行時エラー1004 を防ぐ
    If m_strDefaultFontName = "" Or m_lngDefaultFontSize <= 0 Then
        Call Set_DefaultFormatVars
    End If

    'Proc02_シート全セルに一括適用(エラーハンドラで安全化)
    On Error Resume Next
    With ws.Cells
        .Font.Name = m_strDefaultFontName
        .Font.Size = m_lngDefaultFontSize
        .VerticalAlignment   = m_lngDefaultVAlign
        .HorizontalAlignment = m_lngDefaultHAlign
    End With
    If Err.Number <> 0 Then Err.Clear
    On Error GoTo 0

End Sub

' ===================================
' Set_ColorPalette
' ★全A系プロシージャ共通のカラーパレットを一括設定する★
'   この1か所を編集すれば、A01/A05/A07/A08のすべての配色が同期して切り替わる。
'
' 構成:
'   ① 連番プリセット(共通プール)  m_FontColor01~04 / m_BgColor01~04
'   ② A系名前付き色(後方互換用、可能な限り連番プリセットへエイリアス化)
'      - A01 階層色 / 重複判定色
'      - A05 Mapping/Value 色
'      - A07/A08 シート管理色
'      - シート管理5モード(操作1-1~2-2)専用カラー [追加:20260503]
' ===================================
' [更新日:20260503]
Sub Set_ColorPalette()

    '===========================================================
    '【共通プール】カラーパレット連番プリセット
    '===========================================================
    'Proc01_フォント色01~04
    m_FontColor01 = RGB( 24,  92,  55)  ' 緑系:入力欄/編集中の文字色
    m_FontColor02 = RGB(  0,   0,   0)  ' 黒:通常文字色
    m_FontColor03 = RGB(192,   0,   0)  ' 濃赤:警告/エラー文字色
    m_FontColor04 = RGB(255, 255, 255)  ' 白:濃色背景上の反転文字色

    'Proc02_背景色01~04
    m_BgColor01 = RGB(217, 236, 255)    ' 薄青:ヘッダー/ファイル名行
    m_BgColor02 = RGB(255, 248, 225)    ' 薄黄:ラベル/見出し
    m_BgColor03 = RGB(255, 251, 229)    ' 薄ベージュ:入力欄/補助
    m_BgColor04 = RGB(212, 244, 221)    ' 淡緑:成功/正常

    '===========================================================
    '【A系名前付き色】既存コード後方互換 ─ 新パレットに揃える
    '===========================================================
    'Proc03_A01 階層色(黄色四分位)
    m_lngColorDepth1 = RGB(255, 192,   0)  ' 100% メイン
    m_lngColorDepth2 = RGB(255, 213,  64)  ' 75%  サブ
    m_lngColorDepth3 = RGB(255, 234, 128)  ' 50%  サブサブ
    m_lngColorDepth4 = RGB(255, 255, 192)  ' 25%  サブサブサブ以下
    m_lngColorHeader = RGB(255, 255, 153)  ' ヘッダー背景色

    'Proc04_A01 重複判定色(赤系四分位)
    m_lngInteriorColorDeduplication1 = RGB(255, 255, 255)  ' 重複無し 背景:白
    m_lngInteriorColorDeduplication2 = RGB(255, 220, 220)  ' 2個    背景:薄い赤
    m_lngInteriorColorDeduplication3 = RGB(255, 150, 150)  ' 3~5個 背景:中赤
    m_lngInteriorColorDeduplication4 = RGB(192,   0,   0)  ' 6個以上 背景:濃い赤
    m_lngFontColorDeduplication1     = m_FontColor02       ' 黒(連番プリセット由来)
    m_lngFontColorDeduplication2     = m_FontColor02       ' 黒(連番プリセット由来)
    m_lngFontColorDeduplication3     = m_FontColor02       ' 黒(連番プリセット由来)
    m_lngFontColorDeduplication4     = m_FontColor04       ' 白(連番プリセット由来)

    'Proc05_A05 Mapping/Value 色
    m_lngA05ColorMappingHeader    = RGB(255, 255, 153)  ' 薄黄色:Mapping雛形ヘッダー
    m_lngA05ColorMappingSample    = RGB(230, 243, 255)  ' 薄青:Mapping雛形サンプル行
    m_lngA05ColorMappingSheetName = RGB(211,  47,  47)  ' 赤字:シート名列文字色
    m_lngA05ColorMappingBorder    = RGB(150, 150, 150)  ' 灰色:罫線色
    m_lngA05ColorMappingHelp      = RGB(255, 243, 205)  ' 薄ベージュ:使い方解説背景
    m_lngA05ColorValueHeader      = RGB(255, 255, 153)  ' 薄黄色:Valueシートヘッダー

    'Proc06_A07/A08 シート管理色(連番プリセットへエイリアス化 ─ 統一性UP)
    m_lngA07ColorFileRow   = m_BgColor01                ' 薄青:Row1ファイル名行
    m_lngA07ColorLabel     = m_BgColor02                ' 薄黄:A列ラベル
    m_lngA07ColorAfterCell = m_BgColor03                ' 薄ベージュ:Row3変更後入力欄
    m_lngA07ColorChanged   = m_BgColor04                ' 淡緑:A08変更成功
    m_lngA07ColorError     = RGB(255, 220, 220)         ' 薄赤:エラー表示

    'Proc07_A01 H列「MD有無」の対象外(ファイル行)書式 [追加:20260429]
    m_strA01MdCheckOutOfScope          = "―"             ' 全角ダッシュ
    m_lngA01MdCheckOutOfScopeFontColor = RGB(191, 191, 191)  ' 灰色25%
    m_lngA01MdCheckOutOfScopeAlign     = xlRight              ' 右寄せ

    'Proc08_シート管理5モード専用カラー+プルダウン文言 [追加:20260503]
    ' HTMLプロトタイプ(シート管理_5モード_prototype.html)と完全同期
    ' プルダウン文言は誤認識防止のため操作内容をカッコ書きで明示

    'Proc08-1_プレースホルダー(操作1-1専用、Excel禁止文字"/"で誤実行二重防止)
    m_strMode1_1_Placeholder = "/変更後シート名入力/"

    'Proc08-2_5モードのプルダウン文言(誤認識防止)
    m_strMode1_2_YesText = "はい(削除)"
    m_strMode1_3_YesText = "はい(集約対象)"
    m_strMode2_1_YesText = "はい(値固定)"
    m_strMode2_2_YesText = "はい(書式リセット)"  ' [変更:20260503] 結合解除→書式リセット(4機能統合)

    'Proc08-3_5モードの専用カラー(HTMLと同色)
    m_lngMode1_1_Bg   = RGB(232, 245, 233)  ' 1-1 緑系(安全な書換)
    m_lngMode1_1_Font = RGB( 27,  94,  32)
    m_lngMode1_2_Bg   = RGB(255, 235, 238)  ' 1-2 赤系(危険操作)
    m_lngMode1_2_Font = RGB(183,  28,  28)
    m_lngMode1_3_Bg   = RGB(255, 243, 224)  ' 1-3 橙系(抽出)
    m_lngMode1_3_Font = RGB(230,  81,   0)
    m_lngMode2_1_Bg   = RGB(243, 229, 245)  ' 2-1 紫系(変換固定)
    m_lngMode2_1_Font = RGB( 74,  20, 140)
    m_lngMode2_2_Bg   = RGB(224, 242, 241)  ' 2-2 青緑系(構造変更)
    m_lngMode2_2_Font = RGB(  0,  77,  64)

End Sub

' ===================================
' Set_DefaultFormatVars
' ★全A系プロシージャ共通のデフォルト書式変数を一括設定する★
'   フォント名/サイズ/縦横配置をRun_系の頭で1回呼ぶだけで全シートに統一適用可能。
'   実際の適用は Set_SheetDefaultFormat(ws) で行う(こちらは値の設定のみ)。
' ===================================
' [更新日:20260428]
Sub Set_DefaultFormatVars()

    'Proc01_シート共通デフォルト書式の値を設定
    m_strDefaultFontName = "Century"
    m_lngDefaultFontSize = 14
    m_lngDefaultVAlign   = xlCenter
    m_lngDefaultHAlign   = xlCenter

End Sub


' ===================================
' [更新日:20260428]
Function Set_FileDialogFolderPicker(strTitle As String, _
                                    strPrompt As String) As String

    Dim strFolderPath As String

    'Proc01_フォルダ選択ダイアログ表示
    With Application.FileDialog(msoFileDialogFolderPicker)
        .Title = strTitle
        .ButtonName = strPrompt
        If .Show <> -1 Then
            Set_FileDialogFolderPicker = ""
            Exit Function
        End If
        strFolderPath = .SelectedItems(1)
    End With

    'Proc02_戻り値設定
    Set_FileDialogFolderPicker = strFolderPath

End Function

' ===================================
'Set系ファンクション:シートモジュール内にある各プロシージャから呼び出すファンクション
' ===================================
' [更新日:20260428]
Function Set_FileDialogFoldersFilesPicker(strFolderTitle As String, _
                                          strFolderPrompt As String, _
                                          strFileTitle As String, _
                                          strFilePrompt As String) As Variant

    Dim colPaths    As Collection  ' 収集用コレクション
    Dim lngAnswer   As Long        ' MsgBox戻り値
    Dim i           As Long        ' ループカウンター
    Dim j           As Long        ' ループカウンター(ソート用)
    Dim arrPaths()  As String      ' 戻り値用配列
    Dim strTemp     As String      ' ソート用一時変数
    Dim strNameI    As String      ' ソート比較用:名前i
    Dim strNameJ    As String      ' ソート比較用:名前j

    'Proc01_コレクション初期化
    Set colPaths = New Collection

    'Proc02_フォルダ選択ループ
    ' --- フォルダ選択(繰り返し) ---
    Do
        With Application.FileDialog(msoFileDialogFolderPicker)
            .Title = strFolderTitle
            .ButtonName = strFolderPrompt
            If .Show = -1 Then
                colPaths.Add .SelectedItems(1)
            Else
                Exit Do
            End If
        End With
        ' 上級者モードOFF時は1個選択で終了
        If Not m_blnAdvancedPicker Then Exit Do
        lngAnswer = MsgBox("続けて別のフォルダを選択しますか?", _
                           vbYesNo + vbQuestion, "フォルダ追加")
        If lngAnswer = vbNo Then Exit Do
    Loop

    'Proc03_ファイル選択(複数可・上級者モードON時のみ)
    If m_blnAdvancedPicker Then
        lngAnswer = MsgBox("個別ファイルも選択しますか?", _
                           vbYesNo + vbQuestion, "ファイル追加")
        If lngAnswer = vbYes Then
            With Application.FileDialog(msoFileDialogFilePicker)
                .Title = strFileTitle
                .ButtonName = strFilePrompt
                .AllowMultiSelect = True
                If .Show = -1 Then
                    For i = 1 To .SelectedItems.Count
                        colPaths.Add .SelectedItems(i)
                    Next i
                End If
            End With
        End If
    End If

    'Proc04_未選択時Empty返却
    ' --- 未選択 ---
    If colPaths.Count = 0 Then
        Set_FileDialogFoldersFilesPicker = Empty
        Exit Function
    End If

    'Proc05_コレクションを配列に変換
    ' --- 配列へ変換 ---
    ReDim arrPaths(1 To colPaths.Count)
    For i = 1 To colPaths.Count
        arrPaths(i) = colPaths(i)
    Next i

    'Proc06_名前順ソート(バブルソート)
    For i = LBound(arrPaths) To UBound(arrPaths) - 1
        For j = i + 1 To UBound(arrPaths)
            strNameI = Mid(arrPaths(i), InStrRev(arrPaths(i), "\") + 1)
            strNameJ = Mid(arrPaths(j), InStrRev(arrPaths(j), "\") + 1)
            If StrComp(strNameI, strNameJ, vbTextCompare) > 0 Then
                strTemp = arrPaths(i)
                arrPaths(i) = arrPaths(j)
                arrPaths(j) = strTemp
            End If
        Next j
    Next i

    'Proc07_戻り値設定
    Set_FileDialogFoldersFilesPicker = arrPaths

End Function

Discussion