VBScriptで特定のタイトルが付いているアプリを移動する

# 概要

VBScriptで特定のタイトルがついたウィンドウを移動します。

![move_window.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34777/79a3f730-1682-034b-1976-65fb6e15c160.gif)

小さいディスプレイだと起動時からはみ出してしまうアプリの操作に使える・・・という狭い範囲向けの情報です。

ただ、たいていのケース、キーボードで移動させればなんとかなります。

[ウインドウを移動させる - 富山大学総合情報基盤センター](https://www.itc.u-toyama.ac.jp/el/win7/window_move.html)

> **キーボードによるウィンドウの移動**
> 
> 1. 移動させたいウィンドウをアクティブな状態にします。
> 2. キーボードの[Alt]キーと[Space]キーを同時に押します。
> 3. キーボードの[M]キーを押します。（あるいは、マウスで「移動」を選択します。）
> 4. カーソルキーを押します。


# 要点

WordのTasks/Taskオブジェクトを利用します。

Tasksオブジェクトで特定のタイトルがついたアプリのTaskオブジェクトを得て、その[Top](https://docs.microsoft.com/ja-JP/office/vba/api/Word.Task.Top)と[Left](https://docs.microsoft.com/ja-JP/office/vba/api/Word.Task.Left)を操作します。

[Python(pywin32)でWordを操作する[6] - 特定のタイトルが付いているウィンドウの操作 - Qiita](https://qiita.com/int_main_void/items/6c3569dc242f843ca946)も参照


上方向の移動のみに限定した要点コードは以下です。見つけたいタイトルは`app_name`に設定しています。

1. Window_OnLoadで`CreateObject("Word.Application")`・・・裏でWordが起動するので若干重い
2. Upで`objWord.Tasks.Exists(app_name)`でアプリの存在確認をする
3. `Set tsk = objWord.Tasks(app_name)`でTaskオブジェクトを取得する
4. `tsk.Top`に値を入れて移動する
5. Window_OnUnloadで.htaクローズ時に起動したWordを終了する・・・これを忘れると裏にWordが残る。残ったらタスクマネージャなどで強制的に終了する

```html:up.hta
<!DOCTYPE html>
<html>
<head><title>ウィンドウ↑移動スクリプト</title></head>
<body><button type="button" onclick="Up()">↑</button></body>

<script language="vbscript">
Dim app_name : app_name = "メモ帳"
Dim objWord  : Set objWord = Nothing

Sub Window_OnLoad
    Window.ResizeTo 320,200
    Set objWord = CreateObject("Word.Application")
End Sub

Sub Window_OnUnload
    objWord.Quit()
    Set objWord = Nothing
End Sub

Sub Up
    If objWord.Tasks.Exists(app_name) Then
        Set tsk = objWord.Tasks(app_name)
        tsk.Top = tsk.Top - 10
    End If
End Sub
</script>
</html>
```


# 上下左右移動コード

上下左右操作用のボタン＋若干のエラーハンドリングのコードをつけています。

なお、`objWord.Tasks.Exists(app_name)`と`objWord.Tasks(app_name)`は「部分一致」です。
完全に一致させたい場合は、部分一致させたあとに[Name](https://docs.microsoft.com/ja-JP/office/vba/api/word.task.name)プロパティを使えば完全一致させることが可能です。

さらに、まったく同じタイトルのアプリが複数いるとNameプロパティでも区別できないので別の工夫が必要になります。

```html:move_window.hta
<!DOCTYPE html>
<html>
<head>
    <title>ウィンドウ移動スクリプト</title>
</head>

<body>
    <table>
    <tr>
      <td></td>
      <td><button type="button" onclick="Up()">↑</button></td>
      <td></td>
    </tr>
    <tr>
      <td><button type="button" onclick="Left()">←</button></td>
      <td></td>
      <td><button type="button" onclick="Right()">→</button></td>
    </tr>
    <tr>
      <td></td>
      <td><button type="button" onclick="Down()">↓</button></td>
      <td></td>
    </tr>
    </table>
    <div id="status"></div>
</body>

<script language="vbscript">
Dim app_name : app_name = "メモ帳"
Dim objWord  : Set objWord = Nothing

Sub Window_OnLoad
    Window.ResizeTo 320,200
    Set objWord = CreateObject("Word.Application")
End Sub

Sub Window_OnUnload
    objWord.Quit()
    Set objWord = Nothing
End Sub

Sub Up
    If objWord.Tasks.Exists(app_name) Then
        Set tsk = objWord.Tasks(app_name)
        tsk.Top = tsk.Top - 10
        document.GetElementById("status").innerText = tsk.Name & ": Y = " & tsk.Top
    Else
      document.GetElementById("status").innerText = app_name & " が見つかりませんでした"
    End If
End Sub

Sub Down
    If objWord.Tasks.Exists(app_name) Then
        Set tsk = objWord.Tasks(app_name)
        tsk.Top = tsk.Top + 10
        document.GetElementById("status").innerText = tsk.Name & ": Y = " & tsk.Top
    Else
      document.GetElementById("status").innerText = app_name & " が見つかりませんでした"
    End If
End Sub

Sub Left
    If objWord.Tasks.Exists(app_name) Then
        Set tsk = objWord.Tasks(app_name)
        tsk.Left = tsk.Left - 10
        document.GetElementById("status").innerText = tsk.Name & ": X = " & tsk.Left
    Else
      document.GetElementById("status").innerText = app_name & " が見つかりませんでした"
    End If
End Sub

Sub Right
    If objWord.Tasks.Exists(app_name) Then
        Set tsk = objWord.Tasks(app_name)
        tsk.Left = tsk.Left + 10
        document.GetElementById("status").innerText = tsk.Name & ": X = " & tsk.Left
    Else
      document.GetElementById("status").innerText = app_name & " が見つかりませんでした"
    End If
End Sub

</script>
</html>
```