Selection.Collapseメソッドの挙動に注意(Word)

Selection.Collapseメソッドの挙動に注意

前回

akashi-keirin.hatenablog.com

紹介した、次のハイライト箇所を取得するgetNextHighLightメソッド。

検索箇所を取得した後、Selection.Collapseメソッドを用いて、選択箇所を後方に向けて潰すようにしている。

こうしないと、同じところを取得し続けてしまうからだ。

しかし、カーソルの位置によっては、Selection.Collapseメソッドはちょっと困った動きをする。

カーソルが最後尾にあるとき

たとえば、

f:id:akashi_keirin:20191229154836j:plain

こんなふうに、テキストボックスに「ダボ」というテキストが入力されていて、全体がハイライトされているとする。

このとき、テキストボックスの先頭にカーソルを置いて、次のコードを実行してみる。

リスト1
Private Sub test02()
  Dim tmp As Range
  Set tmp = getNextHighLight(Selection.Range)
  Debug.Print tmp.Text
End Sub

当然、結果は、

f:id:akashi_keirin:20191229154839j:plain

こうなって、カーソル位置は

f:id:akashi_keirin:20191229154843j:plain

こうなる。

問題はこの次。

カーソルは、テキストボックスの末尾にある。

この状態で、

Call Selection.Find.Execute

を実行するとどうなるか。

f:id:akashi_keirin:20191229154845j:plain

なんと、こうなるのである。

で、この状態で、

Call Selection.Collapse(wdCollapseEnd)

を実行するとどうなるのか。

悲しいことに、

f:id:akashi_keirin:20191229154848j:plain

こうなってしまうのである。

最末尾であるがゆえに、引数にwdCollapseStartを指定したのと同じ結果になってしまうのである。

これは実にまずい。

なぜなら、この状態で再び

Call Selection.Find.Execute

を実行すると、

f:id:akashi_keirin:20191229154850j:plain

またしてもこうなってしまうからである。

つまり、たとえば

スト2
Private Sub test03()
  Dim tmp As Range
  Do
    Set tmp = getNextHighLight(Selection.Range)
    If tmp Is Nothing Then Exit Do
    Call someCollection.Add(tmp)
  Loop
End Sub

このようなコードで、終了判定にgetNextHighLightNothingを返すかどうかを用いてDo ~ Loopを使おうとすると、無限ループになってしまうのだ。

しかも、恐ろしいことに、この形で無限ループになってしまった場合、派手にWordがクラッシュしてしまう。(←経験者。)

どういう理屈でそうなるのかはわからないが、たとえば私が経験したパターンだと、

  • 無限ループに陥る
  • 「応答なし」になる
  • 画面をクリックすると画面が白っぽくなる
  • ウインドウの×をクリックするとWordが終了する
  • 再び同じドキュメントを開こうとすると、「セーフモード」で起動することを勧められる
  • 言われた通りにセーフモードで開くと、中身のないWordだけが開く
  • 仕方がないのでWordを終了する
  • もう一度ドキュメントを開こうと試みる
  • 別のユーザが開いているので開けない旨通知がある
  • タスク マネージャーを開くと、確かにMicrosoft Wordが実行中で、しかもすっげーメモリを食っている
  • タスクを終了させる
  • 再度ドキュメントを開こうと試みる
  • 「セーフモード」起動を促されるが、拒否して普通に開く
  • 開くには開くが、クラスモジュールとか標準モジュールが消え去っている

長くなってしまったが、ざっとこれぐらいのわけのわからないことが起こった。

おわりに

気をつけましょう。