Option Explicit

'===========================================================
' ■部品_範囲設定_固定 / SetRange_Fixed
'   ・開始行・開始列・終了行・終了列を、すべて数字で指定して、1つの範囲（Range）を返す
'     → Returns one Range specified entirely by start row, start column, end row and end column numbers.
'
'   ・最終行の取得は行わない（最終行を使いたいときは、GetLastRow の結果を終了行に渡す）
'     → It does not look up the last row (pass the result of GetLastRow as the end row if needed).
'
'   ・列が1列だけの範囲も、複数列の範囲も、この部品で作る（開始列と終了列に同じ値を渡すと1列になる）
'     → Both single-column and multi-column ranges are made here (pass the same value for start and end column).
'
'   ★ この部品は Sub（プロシージャ）ではなく「Function（関数）」で、Range を返す
'     → ★ This component is a Function (not a Sub) that returns a Range.
'===========================================================

'===========================================================
' ■区分 / Classification
'   ・基礎区分：土台 ／ 用途区分：取得 ／ 操作対象区分：範囲
'     → Base: foundation / Purpose: get / Target: range
'
' ■バージョン / Version
'   ・Version 1.0（2026-10-27）
'===========================================================

'===========================================================
' ■URL（WordPress部品ページ）
'   https://feelcodelab.com/vba_parts/setrange_fixed/
'===========================================================

'===========================================================
' ■前提条件（AI誤動作防止の最重要項目） / Preconditions
'   ★【最重要】ブック（vWb）とシート名（vSheetName）は、必ず引数で指定する（省略できない）
'     → ThisWorkbook ＝ このマクロが入っているブック ／ ActiveWorkbook ＝ いまアクティブなブック
'     → ファイルを開く部品の後は、ActiveWorkbook が、開いたファイルに切り替わる。
'       開いた直後に、ActiveWorkbook を変数へ控えて、その変数を渡す
'     → ★ [MOST IMPORTANT] The workbook (vWb) and the sheet name (vSheetName) must always be specified
'        (they cannot be omitted). After the "open file" component runs, ActiveWorkbook switches to the opened
'        file, so keep it in a variable right after opening and pass that variable.
'
'   ★【最重要】戻り値は Range（オブジェクト）なので、受け取るときは必ず Set を使う
'     → ★ [MOST IMPORTANT] The return value is an object, so the caller must receive it with Set.
'
'   ・開始行・開始列・終了行・終了列は、すべて 1 以上の整数で、
'     終了行は開始行以上、終了列は開始列以上であること
'     → 設定の誤りは、Nothing や False ではなく、原因を示すエラーで止まる（Err.Raise）
'     → All four numbers must be integers of 1 or more, and the end must not be before the start.
'        A setting mistake stops with an error naming the cause (Err.Raise).
'
'   ・GetLastRow の結果を終了行に渡すときは、「データがない場合は 1 が返る」点に注意する
'     → 見出しの行より下にデータがあるかは、呼び出し側で先に確認する
'     → When passing the result of GetLastRow as the end row, note that it returns 1 when there is no data;
'        the caller checks beforehand that data exists below the header.
'
'   ・Offset / Find / Resize / With は禁止
'     → Offset, Find, Resize, and With statements are prohibited.
'===========================================================

'===========================================================
' ■依存関係（部品同士） / Component Dependencies
'   ・なし（土台の部品。他の部品を参照しない。単独で使用可能）
'     → No required dependencies; this is a foundation component and is standalone.
'
'   ・組み合わせ：f_GetLastRow → f_SetRange_Fixed
'     （最終行を取得してから、その行を終了行として範囲を作る）
'     → Typical combination: [GetLastRow] -> [SetRange_Fixed].
'===========================================================

'===========================================================
' ■依存関係（シート・表） / Sheet Dependencies
'   ・特になし（マッピング表等は不要）
'     → No sheet-level dependencies (no mapping table etc. required).
'===========================================================

'===========================================================
' ■技術解説 / Technical Notes
'
'   ・ブックとシート名を、必ず引数で受け取る理由
'       → シート名だけでは、どのブックのシートか決まらず、Worksheets("名前") は、そのときの
'          ActiveWorkbook のシートを指してしまう。ファイルを開くと ActiveWorkbook が切り替わるため、
'          取り違えが起きやすい。ブックを必ず引数で渡す形にすると、呼び出しの行に
'          「どのブックの、どのシートか」が書かれ、読むだけで意図が分かる。
'       → A sheet name alone does not identify the workbook, and Worksheets("name") would refer to the current
'          ActiveWorkbook, which switches when a file is opened. Always passing the workbook makes the call
'          itself say "which sheet of which workbook".
'
'   ・シートの存在確認を、部品の中に直接書いている理由
'       → 土台の部品は、他の部品（シート存在チェック）を参照しない決まりのため。
'          数行が他の土台と重複するが、1つの部品だけをコピーして使えることを優先している。
'       → A foundation component does not reference other components (SheetExists). The few duplicated lines
'          let this one component be copied and used on its own.
'
'   ・範囲を作る部品を、数字だけで受け取る形にしている理由
'       → 最終行の取得（どの列で取るか）と、範囲を作ることを、別の部品に分けるため。
'          これにより、最終行を自動で取る場合も、手動で決めた行を使う場合も、同じ部品で範囲を作れる。
'       → Last-row lookup (which column) and range creation are separate components, so the same component
'          serves both an automatic last row and a manually chosen row.
'
'   ・設定の誤りを、Nothing ではなく Err.Raise で止める理由
'       → 数字の誤り（0 や逆順など）を Nothing で返すと、呼び出し側で Nothing の確認を忘れたときに、
'          別の場所で原因の分かりにくいエラーになる。原因を示すエラーで、その場で止める。
'       → Returning Nothing for a wrong number would cause an obscure error elsewhere if the caller forgets to
'          check; stopping with a named cause is clearer.
'
'   ・Range("A1:B7") の直書きを使わず、Cells で作る理由
'       → 行番号・列番号を、他の部品（最終行取得など）の結果から、そのまま渡せるようにするため。
'       → It lets results of other components (e.g., last row) be passed in directly as numbers.
'
'   ・Offset / Find / Resize / With を禁止する理由
'       → 生成AIが誤って不正な範囲操作を行う可能性が高く、行数可変の処理で誤動作を引き起こしやすいため。
'       → These statements often cause misaligned or ambiguous range operations when generated by AI.
'
'   ・本部品が「土台」である理由
'       → 範囲を使う多くの部品（コピー・転記・検索）が範囲設定を必要とし、
'          しかも他の部品を参照せずに単独で動くため。
'       → Many components that use ranges need this, and it works on its own without referencing other components.
'===========================================================

'---------------------------------------------
' ■引数（型＋意味） / Arguments
'   vWb        : 対象のブック（Workbook）※必須（省略できない）
'                → Target workbook (Workbook); required.
'
'   vSheetName : 範囲を作るシートのシート名（String）
'                → Name of the sheet in which the range is made (String).
'
'   vStartRow  : 開始行の行番号（Long）
'                → Start row number (Long).
'
'   vStartCol  : 開始列の列番号（Long）
'                → Start column number (Long).
'
'   vEndRow    : 終了行の行番号（Long）
'                → End row number (Long).
'
'   vEndCol    : 終了列の列番号（Long）
'                → End column number (Long).
'---------------------------------------------

'---------------------------------------------
' ■戻り値（型＋意味） / Return Value
'   Range : 指定した範囲（開始行・開始列から、終了行・終了列まで）
'           → The specified range (from the start cell to the end cell).
'---------------------------------------------

'---------------------------------------------
' ■エラー / Errors (Err.Raise)
'   ・vbObjectError + 1010：ブック（vWb）が Nothing
'   ・vbObjectError + 1011：シート（vSheetName）が、ブックに存在しない
'   ・vbObjectError + 1007：開始行・開始列・終了行・終了列のどれかが 1 未満
'   ・vbObjectError + 1008：終了行が開始行より小さい、または終了列が開始列より小さい
'   ・vbObjectError + 1009：終了行または終了列が、シートの上限（行数・列数）を超えている
'---------------------------------------------

'===========================================================
' ■禁止事項（AI向け） / Prohibitions
'   ・ブックとシート名を省略することの禁止（必ず引数で指定する）
'     → Do not omit the workbook and the sheet name; always specify them.
'
'   ・戻り値を Set なしで受け取ることの禁止
'     → Do not receive the return value without Set.
'
'   ・GetLastRow の結果を、データの有無を確認せずに終了行へ渡すことの禁止
'     → Do not pass the GetLastRow result as the end row without checking that data exists.
'
'   ・セル参照の直書き禁止（Range("A1") など）
'     → Hard-coded cell references are prohibited; use Cells with row/column numbers.
'
'   ・Offset禁止
'     → Offset may cause misaligned row calculations.
'
'   ・Find禁止
'     → Find leads to unpredictable search behavior.
'
'   ・Resize禁止
'     → Resize may unintentionally expand ranges.
'
'   ・With禁止
'     → With blocks cause ambiguous object references.
'===========================================================

'===========================================================
' ■使用例（サンプルコード） / Example
'   ＜例1：見出し（2行目）から、最終行までの A列〜B列 / Example 1: from header row 2 to the last row, columns A-B＞
'   Dim lastRow As Long
'   Dim rng As Range
'
'   lastRow = 部品_最終行取得(ThisWorkbook, "転記元", 1)   '1列目で最終行を取得 / get the last row by column 1
'   If lastRow < 3 Then
'       MsgBox "データがありません"                       '見出し（2行目）の下にデータがない / no data below the header
'       Exit Sub
'   End If
'   Set rng = 部品_範囲設定_固定(ThisWorkbook, "転記元", 2, 1, lastRow, 2)
'
'   ＜例2：行を手動で決める / Example 2: a manually chosen row＞
'   Set rng = 部品_範囲設定_固定(ThisWorkbook, "転記元", 3, 1, 20, 2)   'A3〜B20
'
'   ＜例3：1列だけの範囲 / Example 3: a single column＞
'   Set rng = 部品_範囲設定_固定(ThisWorkbook, "転記元", 3, 4, 8, 4)    'D3〜D8
'===========================================================

'===========================================================
' ■ラッパー関数（日本語名） / Wrapper Function
'   ・辞書の日本語名で呼び出すための窓口
'     → Entry point callable by the Japanese dictionary name.
'
'   ・内部では英語名の本体処理を呼び出し、結果（Range）をそのまま返す
'     → Internally calls the English-named core function and returns its result (Range) as it is.
'===========================================================
Function 部品_範囲設定_固定( _
        ByVal vWb As Workbook, _
        ByVal vSheetName As String, _
        ByVal vStartRow As Long, _
        ByVal vStartCol As Long, _
        ByVal vEndRow As Long, _
        ByVal vEndCol As Long) As Range

    '本体処理（英語名）を呼び出し、結果をそのまま返す / Call core function and return its result
    Set 部品_範囲設定_固定 = f_SetRange_Fixed(vWb, vSheetName, vStartRow, vStartCol, vEndRow, vEndCol)

End Function

'===========================================================
' ■本体処理（英語名） / Core Function
'   ・開始行・開始列・終了行・終了列の数字から、範囲（Range）を作って返す
'     → Makes and returns a Range from the start/end row and column numbers.
'===========================================================
Function f_SetRange_Fixed( _
        ByVal vWb As Workbook, _
        ByVal vSheetName As String, _
        ByVal vStartRow As Long, _
        ByVal vStartCol As Long, _
        ByVal vEndRow As Long, _
        ByVal vEndCol As Long) As Range

    Dim ws As Worksheet

    Set f_SetRange_Fixed = Nothing

    '---------------------------------------------
    ' ■ブックが設定されているかを確認（Nothing の場合はエラーで止める）
    '   / Check that the workbook is set (stop with an error if Nothing)
    '---------------------------------------------
    If vWb Is Nothing Then
        Err.Raise vbObjectError + 1010, "f_SetRange_Fixed", _
                  "ブック（vWb）が設定されていません（Nothing）。"
    End If

    '---------------------------------------------
    ' ■シートの存在を確認（存在しない場合は、シート名とブック名を示すエラーで止める）
    '   / Check that the sheet exists (stop with an error naming the sheet and workbook)
    '---------------------------------------------
    On Error Resume Next
    Set ws = vWb.Worksheets(vSheetName)
    On Error GoTo 0

    If ws Is Nothing Then
        Err.Raise vbObjectError + 1011, "f_SetRange_Fixed", _
                  "シート「" & vSheetName & "」が、ブック「" & vWb.Name & "」に存在しません。"
    End If

    '---------------------------------------------
    ' ■行番号・列番号を確認（誤りは、原因を示すエラーで止める）
    '   / Check the row and column numbers (stop with an error naming the cause)
    '---------------------------------------------
    If vStartRow < 1 Or vStartCol < 1 Or vEndRow < 1 Or vEndCol < 1 Then
        Err.Raise vbObjectError + 1007, "f_SetRange_Fixed", _
                  "行番号・列番号は 1 以上を指定してください" & _
                  "（開始行=" & vStartRow & "、開始列=" & vStartCol & _
                  "、終了行=" & vEndRow & "、終了列=" & vEndCol & "）。"
    End If

    If vEndRow < vStartRow Or vEndCol < vStartCol Then
        Err.Raise vbObjectError + 1008, "f_SetRange_Fixed", _
                  "終了が開始より前になっています" & _
                  "（開始行=" & vStartRow & "、終了行=" & vEndRow & _
                  "、開始列=" & vStartCol & "、終了列=" & vEndCol & "）。"
    End If

    If vEndRow > ws.Rows.Count Or vEndCol > ws.Columns.Count Then
        Err.Raise vbObjectError + 1009, "f_SetRange_Fixed", _
                  "シートの上限（" & ws.Rows.Count & "行・" & ws.Columns.Count & "列）を超えています" & _
                  "（終了行=" & vEndRow & "、終了列=" & vEndCol & "）。"
    End If

    '---------------------------------------------
    ' ■範囲を作る / Make the range
    '---------------------------------------------
    Set f_SetRange_Fixed = ws.Range( _
        ws.Cells(vStartRow, vStartCol), _
        ws.Cells(vEndRow, vEndCol))

End Function
