知らずに落ちると抜け出せなくなるVBAの落とし穴です。
Protectメソッドによるシートの保護をすでに保護されたシートへ実行した際に、稀に保護が外れてしまう不具合がVBAには存在します。
- 保護をかけたはずなのにセルが編集できてしまう
- シートの保護がかかっているのに操作が制限されていない
あたりにお悩みの方は、この罠にかかっていないかご確認ください。
不具合の内容と解決策
不具合の発生条件と内容をまず記載します。
保護がかかっているシートに対してさらにProtectメソッドを実行する際、
引数DrawingObjectsまたはScenariosを指定したときだけ、
なぜかシートの保護が外れてしまう不具合が起きます。
より詳しく書くと、
「シートの保護は有効になっているのに、
セルの編集や、禁止したはずの操作がすべて実行出来てしまう」
状態になります。
取り急ぎ解決策だけ書きますと、
- 保護されたシートにProtectを実行しないよう、必ずUnprotectを挟む
- Protectメソッドの引数「Contents」にTrueを明示して渡す
のいずれかの方法をとることで、この罠は回避できます。
' シートに保護をかける(または手作業ですでに保護がかかっている) 対象シート.Protect ' このコードは大丈夫 対象シート.Protect AllowFormattingCells:=True ' !!このコードではバグが起きる!! 対象シート.Protect DrawingObjects:=True ' 解決策① 一旦保護を解除してから保護 対象シート.Unprotect 対象シート.Protect DrawingObjects:=True ' 解決策② Contents:=True を書く 対象シート.Protect DrawingObjects:=True, Contents:=True
詳細(を説明しきれるわけではないですが・・・)
まずProtectの基本的な仕様ですが、
対象シート.Unprotect 対象シート.Protect
と書いたときは、「すべての操作が禁止された保護」がかかります。
Unprotectで解除したときの設定のまま、
再度保護がかかるわけではありません。
これも罠と言えば罠なので、まずはこの仕様を把握しておいてください。
さて、今回の不具合で起きる、
「シートの保護は有効になっているのに、
セルの編集や、禁止したはずの操作がすべて出来てしまう」
状態ですが、実はこれは意図的に発生させることができます。
Protectメソッドの引数Contentsに、Falseを渡すとこの状態になります。
' これで「保護が有効なのに全操作可能」状態になる 対象シート.Protect Contents:=False
この引数「Contents」というのは、シートの保護ダイアログにおける、
このチェックに該当しています。
画像をよく見るとわかりますが、シートの保護をかけるときは、
このチェックを外すとOKボタンがグレーアウトするため、
手作業でこの状態を作ることはできません。
ということでこれは無意味な引数であり、
省略時の「True」しか使わないはずなのですが、
Protectメソッドを保護されたシートの重ね掛けすると、
ContentsにFalseが渡ったことになってしまいます。
しかもなぜかDrawingObjectsかScenariosを指定したときにだけ。
結構謎の仕様で、遭遇したときは再現に苦労しました
わかってしまえば対策は簡単で、
上記の通りUnprotectか、Contents:=Trueを書いて終わりです。
バグの様に見えてちゃんとした仕様というのがたくさんあるので、
あまりユーザー側で「これはバグだ!」というのは良くない気がしますが、
これは流石に不具合と言っていい気がします。
にしても不思議な挙動ですよね。
太古の昔はProtectメソッドがトグル仕様だったとかあるんでしょうか。
知らずにかかると何が起きたかわからないと思いますので、
心の片隅にでも、置いておいてください。