VB.NETでExcelを自動編集しセル編集を禁止する方法(Excel Interop+シート保護)

VB.NETでExcelファイルを更新できても、ユーザーがExcelを開いてセルを直接上書きできてしまうと運用が崩れます。本記事ではExcel Interopで編集し、更新後にシート保護でUIからのセル編集を禁止する実装例と、速度・運用でハマりやすい点をまとめます。

目次

要件を整理:VB.NETで更新したいが、Excel上の手入力はさせたくない

業務でよくあるのが、次のような「Excelは表示・印刷のために使うが、編集はアプリ側で統制したい」という要件です。

  • マスタや計算結果をVB.NET側で確定し、Excelは帳票として配布したい
  • ユーザーにはExcelを開かせるが、セルの直接編集(上書き入力)は禁止したい
  • 編集は必ずアプリ(ボタン操作や入力フォーム)経由にしたい

この要件に対して、最短で現実的に効くのがExcel Interopで編集 → 仕上げに「シート保護」をかける方法です。

結論:Excel Interopで編集してから、シート保護でセル編集を禁止する

VB.NETでMicrosoft.Office.Interop.Excel(Excel Interop)を使い、Workbook/Worksheetを操作して必要なセルを書き換えます。最後にWorksheet.Protectでシート保護を有効化すると、ユーザーはExcel画面上でセルを編集できなくなります。

やりたいこと使う仕組みポイント
VB.NETでセル値を変更したいExcel Interop(Workbook/Worksheet/Range操作)ExcelがインストールされたPCでの自動化が基本
ユーザーのセル直接編集を止めたいシート保護(Worksheet.Protect)「ロック」だけでは効かず、保護を有効化して初めて編集不可になる
プログラム更新は許可しつつUI編集だけ止めたいProtectのUserInterfaceOnly、またはUnprotect→更新→ProtectUserInterfaceOnlyは再起動で戻るため毎回設定する運用が安全

シート保護の基礎:「Locked(ロック)」と「Protect(保護)」の関係

Excelの「セルの保護」は、次の2段構えです。

  • セルのLockedプロパティ:そのセルを保護対象にするかどうかのフラグ(多くのセルは既定でLocked=True)
  • シート保護(Protect):Lockedが有効になるスイッチ(これをONにしないと編集を止められない)

つまり「全セルを編集禁止」にしたいなら、基本は全セルLocked=True(既定のままでOK)→ Protectを有効化で成立します。逆に「一部だけ入力させたい」場合は、Protect前にその範囲だけLocked=Falseにします(本記事の主題は“編集させない”なので補足扱いにします)。

シート保護と似た機能の違い(混同しやすいポイント)

「保護」と言っても種類があります。目的に合うものを選ばないと、思ったほど効かなかったり、逆に使い勝手が悪くなったりします。

機能守れる対象主な用途注意点
シート保護セル編集、オブジェクト操作などユーザーのセル直接編集を止める強固なセキュリティではなく“抑止”寄り
ブック保護(構造保護)シート追加/削除/移動、表示/非表示などシート構成を崩されたくないセル編集の禁止には直接効かない
ファイルの暗号化(開くパスワード)ファイルを開ける/開けない閲覧権限の制御今回の「開けるが編集は不可」とは別の話
読み取り専用推奨編集の誘導(警告表示)誤編集の抑止ユーザーが編集で開けば書き換えられる

VB.NET(Excel Interop)で編集してからシート保護する最小構成

ここでは「VB.NETでセルを書き換え、保存し、最後にシート保護でUI編集を禁止する」という最小構成を示します。環境により参照設定や例外処理の粒度は変わりますが、骨格として押さえると実装が安定します。

参照設定の考え方

  • プロジェクト参照に Microsoft.Office.Interop.Excel を追加
  • 実行PCにExcel(デスクトップ版)がインストールされている前提
  • サーバー(Windowsサービス、IIS)での常時自動化は推奨されにくい(後述)

サンプル:更新 → Protect → 保存 → COM解放

以下は「既存のブックを開いて値を更新し、シート保護をかけ直す」例です。既に保護がかかっている可能性を考え、先にUnprotectしてから更新しています。

Option Strict On

Imports System.Runtime.InteropServices
Imports Excel = Microsoft.Office.Interop.Excel

Public Module ExcelUpdateSample

    Public Sub UpdateAndProtect(xlsxPath As String)
        Dim xlApp As Excel.Application = Nothing
        Dim wb As Excel.Workbook = Nothing
        Dim ws As Excel.Worksheet = Nothing

        Dim protectPassword As String = "YourPasswordHere" ' 運用では外部設定化を推奨

        Try
            xlApp = New Excel.Application()
            xlApp.Visible = False
            xlApp.DisplayAlerts = False

            wb = xlApp.Workbooks.Open(Filename:=xlsxPath, ReadOnly:=False)

            ws = CType(wb.Worksheets(1), Excel.Worksheet)

            ' 既に保護されている場合に備えて解除(パスワードが違うと例外になる)
            ws.Unprotect(Password:=protectPassword)

            ' 例:単発の更新
            ws.Range("B2").Value2 = "更新済み"
            ws.Range("C2").Value2 = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")

            ' 仕上げ:シート保護でUI編集を禁止
            ws.Protect(Password:=protectPassword,
                       DrawingObjects:=True,
                       Contents:=True,
                       Scenarios:=True)

            wb.Save()

        Finally
            ' 例外があってもExcelプロセスを残さないのが最重要
            If wb IsNot Nothing Then
                wb.Close(SaveChanges:=False)
            End If
            If xlApp IsNot Nothing Then
                xlApp.Quit()
            End If

            SafeFinalRelease(ws)
            SafeFinalRelease(wb)
            SafeFinalRelease(xlApp)

            ' COM解放のタイミングが絡むため、明示的GCを入れる運用もあります(状況次第)
            GC.Collect()
            GC.WaitForPendingFinalizers()
        End Try
    End Sub

    Private Sub SafeFinalRelease(obj As Object)
        If obj Is Nothing Then Return
        Try
            Marshal.FinalReleaseComObject(obj)
        Catch
            ' 解放失敗は握りつぶし(ログは環境に応じて)
        End Try
    End Sub

End Module

ポイントはProtectを最後に必ずかけること、そしてFinallyでClose/Quit/COM解放を徹底することです。Interopで一番多い事故は「Excel.exeが裏で残り続ける」パターンなので、まずここを外さない作りにします。

保護したままプログラム更新したい場合の2つの定番運用

「ユーザーには常に編集不可にしたい。でもVB.NETの処理では更新したい」という場合、実務でよく採られるのは次の2パターンです。

方式概要メリットデメリット/注意点
Unprotect → 更新 → Protect更新の直前に解除し、更新後に必ず再保護分かりやすい/確実に状態を統一できる解除・再保護の手間、例外時に保護を戻し忘れると事故
UserInterfaceOnly:=TrueUIからの編集のみ禁止し、プログラム操作は許可解除せずに更新できる(同一Excelセッション内)Excel再起動で設定が戻るため“毎回設定”が前提

方式A:Unprotect → 更新 → Protect(最も堅い)

最も堅いのは、更新のたびに確実に解除して、更新後に保護をかけ直す方法です。例外が起きても最後にProtectへ戻すよう設計し、事故を防ぎます。

Try
    ws.Unprotect(Password:=protectPassword)

    ' ここで更新(大量更新なら後述の一括投入を推奨)
    ws.Range("D5").Value2 = 123

Finally
    ' 更新成否に関わらず、最後に保護状態へ戻す
    ws.Protect(Password:=protectPassword,
               DrawingObjects:=True,
               Contents:=True,
               Scenarios:=True)
End Try

「更新途中で落ちたら保護が外れっぱなし」を避けるため、ProtectをFinally側に置くのが実務では効きます。

方式B:UserInterfaceOnly:=True(UI編集だけ禁止)

シート保護のオプションにUserInterfaceOnly:=Trueを指定すると、Excelの画面操作(ユーザーの手入力)を禁止しつつ、オブジェクトモデルからの変更は許可する、という発想ができます。

ws.Protect(Password:=protectPassword,
           DrawingObjects:=True,
           Contents:=True,
           Scenarios:=True,
           UserInterfaceOnly:=True)

ただし実運用での最大の注意は、UserInterfaceOnlyはブックを閉じて開き直すと元に戻ることです。つまり「一度設定したから永久に有効」ではありません。VB.NETアプリが毎回ブックを開くたびにProtectを設定し直すなら問題になりにくい一方、Excelを開きっぱなしで運用する(同一セッションで何度も更新する)場合は、いつ・誰が・どのExcelセッションで開いているかを揃えないとブレが出ます。

Protectの設定で「どこまで操作を許すか」を設計する

「セル編集禁止」だけならProtectの既定設定でも足りますが、現場では次のような追加要件が出がちです。

  • フィルターや並べ替えは使わせたい(閲覧性のため)
  • 列幅調整だけ許可したい(印刷調整のため)
  • セル選択そのものを制限したい(コピーや参照を抑えたい)

Excel InteropのProtectには多くのオプションがあります。代表的なものを表にまとめます。

ユーザーに許可したい操作Protectの引数例補足
並べ替え(Sort)AllowSorting:=True対象範囲やテーブルによっては追加設定が必要な場合あり
フィルター(AutoFilter)AllowFiltering:=Trueリスト/テーブル運用で便利
セル書式の変更AllowFormattingCells:=True見た目を変えられるため運用ルール次第
列/行の書式変更AllowFormattingColumns:=True / AllowFormattingRows:=True列幅や行高の調整を許可する方向性
行/列の挿入AllowInsertingRows:=True / AllowInsertingColumns:=True帳票では事故が起きやすいので慎重に
行/列の削除AllowDeletingRows:=True / AllowDeletingColumns:=True原則は許可しない方が安全

また、セル選択そのものを抑えたい場合は、Protectの引数ではなくWorksheetの設定も使えます。

' 選択できる範囲を制御(例:選択不可)
ws.EnableSelection = Excel.XlEnableSelection.xlNoSelection

ただし、選択不可にするとコピーや参照がやりづらくなり、問い合わせが増えることもあります。「編集禁止」だけで足りるなら、まずは編集だけ止める設計が現場では安定しやすいです。

大量セル更新が遅い問題:Interopは「まとめ書き」が必須

Excel Interopで一番ハマりやすいのが速度です。セルを1つずつ更新すると、COM呼び出しが大量に発生し、VBAより遅く感じるケースすらあります。対策はシンプルで、配列でまとめてRangeへ一括投入し、Excel側の余計な処理を一時停止します。

高速化の定番セット

設定狙い注意
ScreenUpdating=False画面描画を止めて高速化最後にTrueへ戻す
EnableEvents=Falseイベント発火を止める他のアドイン/イベント運用があるなら影響に注意
Calculation=Manual再計算を止める最後に元へ戻し、必要なら再計算
Range.Value2へ配列一括投入COM呼び出し回数を激減配列の次元(行列)とRangeサイズを合わせる

例:2次元配列をRangeに一括投入する

Dim prevCalc As Excel.XlCalculation = xlApp.Calculation

Try
xlApp.ScreenUpdating = False
xlApp.EnableEvents = False
xlApp.Calculation = Excel.XlCalculation.xlCalculationManual


Dim rows As Integer = 1000
Dim cols As Integer = 10

Dim data(rows - 1, cols - 1) As Object

For r As Integer = 0 To rows - 1
    For c As Integer = 0 To cols - 1
        data(r, c) = (r + 1).ToString() & "-" & (c + 1).ToString()
    Next
Next

Dim target As Excel.Range = ws.Range("A1").Resize(rows, cols)
target.Value2 = data


Finally
xlApp.Calculation = prevCalc
xlApp.EnableEvents = True
xlApp.ScreenUpdating = True
End Try

ここまでやると、「セル1つずつ書く」より体感で桁違いに速くなることが多いです。Interopでパフォーマンス問題が出たら、まずRangeへの一括投入を疑ってください。

Interop運用で事故を減らす:Excelプロセス残り・ダイアログ・ファイルロック

Excel.exeが残る問題を防ぐ

InteropはCOMオブジェクトなので、参照が残るとExcelプロセスが終了しません。次のルールが実務では効きます。

  • Excel.Application / Workbook / Worksheet / Rangeなどを変数に保持したら必ず解放する
  • Finallyで Close → Quit → FinalReleaseComObject を徹底する
  • RangeやCellsをループで都度取得しない(見えない参照が増えやすい)

保存確認などのダイアログを潰す

自動処理中にダイアログが出ると処理が止まります。基本は次の2つで抑えます。

  • DisplayAlerts=False(確認ダイアログ抑止)
  • 保存方針の明確化(Save/SaveAsの使い分け、上書き前提ならSaveAsで明示)

ユーザーが開いているファイルを更新できない(ロック)

Excelファイルは、誰かが編集モードで開いているとロックされることが多いです。要件が「ユーザーが開いて閲覧している最中でも裏で更新したい」なら、ファイル共有設計や、別ファイルへ出力して差し替える運用(生成物は常に新規ファイルにする)を検討した方がトラブルが減ります。

「シート保護はセキュリティか?」への現実的な回答

シート保護は「編集を抑止する」仕組みとして有効ですが、強固なセキュリティ用途(攻撃者から守る)とは別物です。業務での使い方としては次の整理が現実的です。

  • 同僚・現場ユーザーの誤操作や無断編集を防ぐ:シート保護は非常に有効
  • 悪意ある第三者から情報や改ざんを守る:シート保護だけでは不足(暗号化、権限、配布経路の管理が必要)

つまり「編集はプログラム経由のみ」という要件に対しては、シート保護は運用設計とセットで効く、という位置付けです。

Excelを起動せずに編集したい場合:Interop以外の選択肢

Interopは「Excelが入っているPCで、Excelを自動操作する」モデルです。一方で、次のような要件では別方式が現実的になります。

  • サーバーでバッチ処理したい(Windowsサービス、Webアプリなど)
  • Excelプロセスを起動させたくない
  • 配布ファイルをテンプレートから高速生成したい
方式Excelインストール特徴向いているケース
Excel Interop必要Excelの見た目や機能に忠実、ただし速度と安定性に注意クライアントPCのデスクトップアプリで確実にExcel操作したい
Open XML SDK不要xlsxを直接編集、純粋にファイル操作(学習コストは高め)サーバー/バッチで生成、Excelを起動したくない
ClosedXML等不要Open XMLを扱いやすくしたライブラリ、速度と実装性のバランステンプレから帳票生成、セル更新中心
EPPlus等不要機能豊富だがライセンス条件の確認が必要な場合がある要件とライセンスが合うなら強力

ただし今回のテーマは「VB.NETでExcelを編集し、ユーザーのセル編集を禁止したい」なので、まずはInterop+シート保護で要件を満たし、運用上の負荷や性能が限界に来たら代替方式へ移行、という段階的アプローチが取りやすいです。

実運用でのチェックリスト(そのまま設計に使える観点)

  • ユーザーに許可する操作(フィルター・並べ替え・列幅調整など)を先に決め、Protect引数へ落とし込む
  • 保護のかけ直しをFinallyで担保する(例外時に保護が外れっぱなしを防ぐ)
  • 大量更新は配列で一括投入し、Calculation/ScreenUpdating/EnableEventsを一時停止する
  • Excel.exe残り対策としてClose/Quit/COM解放を徹底する
  • パスワードの扱いは外部設定化し、ソース直書きを避ける(漏えい・変更対応のため)
  • 「閲覧だけでよい」なら、ExcelではなくPDF出力も検討する(改ざんリスクと問い合わせを減らせる)

まとめ:Interopで編集し、最後にProtectで“UI編集禁止”を確実にする

VB.NETでExcelを編集しつつ、ユーザーのセル直接編集を止めたいなら、Excel Interopで更新 → Worksheet.Protectでシート保護が最短で要件を満たします。保護したまま更新したい場合は、Unprotect→更新→Protectか、UserInterfaceOnlyを使った設計が定番です。加えて、Interop特有の速度問題は「まとめ書き」で解決できることが多いので、最初から一括投入の形で組むと手戻りが減ります。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次