和風スパゲティのレシピ

日本語でコーディングするExcelVBA

Protectメソッドを連続実行すると保護が解除される

知らずに落ちると抜け出せなくなる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」というのは、シートの保護ダイアログにおける、

シートの保護ダイアログでContents:=Flaseを再現

このチェックに該当しています。


画像をよく見るとわかりますが、シートの保護をかけるときは、
このチェックを外すとOKボタンがグレーアウトするため、
手作業でこの状態を作ることはできません。


ということでこれは無意味な引数であり、
省略時の「True」しか使わないはずなのですが、
Protectメソッドを保護されたシートの重ね掛けすると、
ContentsにFalseが渡ったことになってしまいます。


しかもなぜかDrawingObjectsかScenariosを指定したときにだけ。

結構謎の仕様で、遭遇したときは再現に苦労しました


わかってしまえば対策は簡単で、
上記の通りUnprotectか、Contents:=Trueを書いて終わりです。



バグの様に見えてちゃんとした仕様というのがたくさんあるので、
あまりユーザー側で「これはバグだ!」というのは良くない気がしますが、
これは流石に不具合と言っていい気がします。


にしても不思議な挙動ですよね。

太古の昔はProtectメソッドがトグル仕様だったとかあるんでしょうか。


知らずにかかると何が起きたかわからないと思いますので、
心の片隅にでも、置いておいてください。