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→更新→Protect | UserInterfaceOnlyは再起動で戻るため毎回設定する運用が安全 |
シート保護の基礎:「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:=True | UIからの編集のみ禁止し、プログラム操作は許可 | 解除せずに更新できる(同一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特有の速度問題は「まとめ書き」で解決できることが多いので、最初から一括投入の形で組むと手戻りが減ります。

コメント