エクセルから社内Webアプリにデータを転記する

今回が初めての投稿になります。
プログラミング＆アウトプットど素人の投稿です。

エクセル内データを社内Webアプリに転記し他部署に申請書類を作る操作を自動化しました。

必要な操作は、
Internet Explorerの起動
→Webアプリの申請書類作成ページにジャンプ
→ログインID, パスワードの入力(ログイン済みの場合は省略)
→必要な項目にデータを転記
です。

まず、普通にCreateObjectを使ってInternet Explorerを扱おうとしましたが早速ダメでした。


```VB
Dim username, password As String
Dim ie As Object
Dim submitElm As HTMLFormElement

username = Application.InputBox("ログインIDを入力", Type:=2)
password = Application.InputBox("パスワードを入力", Type:=2)

Set ie = CreateObject("InternetExplorer.Application")

'社内WebアプリのURL
ie.Navigate "http://***"

'ユーザーIDとパスワードのinput要素のそれぞれのname属性値を使って見つける
'それぞれにユーザーが入力した値を入れる
ie.document.getElementsByName("_Account")(0).Value = username
ie.document.getElementsByName("Password")(0).Value = password

'submitボタンの操作
'DocumentクラスのFormsプロパティにコントロール名(今回は"LoginForm")を指定
Set submitElm = ie.document.forms("LoginForm")
submitElm.submit

```

色々調べてみると社内で使うようなイントラネットの場合、セキュリティレベルの問題が起きてダメみたいです。
こちらのサイトを参考にさせていただきました。

[Default Integrity Level and Automation](https://blogs.msdn.microsoft.com/ieinternals/2011/08/03/default-integrity-level-and-automation/)
[UWSCでIE（オブジェクト）を保護モード整合性レベル中"Medium"で起動する方法](http://uwscblog.blog.fc2.com/blog-entry-14.html)

完全には理解できませんでしたが、ようはIEには複数のセキュリティレベル(LowとMediumと(Highも？))があって、オブジェクト生成時はLowだけどリンクの遷移などでページが切り替わった時に、イントラネットの場合はセキュリティレベルがMediumに切り替わる。このため新しいMediumのオブジェクトができているのに、VBA側のオブジェクトは古いLowのオブジェクトのままだから具合が悪い。
そんな感じでしょうか。

対策としては、初めからMediumでオブジェクトを作ってしまえ！ということのようです。そのためCreateObjectではなくGetObjectを使って以下のようにします。

```VB
Const IE_MEDIUM = "{D5E8041D-920F-45E9-B8FB-B1DEB82C6E5E}"

Dim ie As Object

Set ie = GetObject("new:" & IE_MEDIUM)

'社内アプリのURL
ie.navigate "http://***"
```

{D5E8041D-920F-45E9-B8FB-B1DEB82C6E5E}・・・？って感じですが、これは、レジストリに記載されている CLSID でIEのセキュリティレベルをMediumで扱うIDということらしい。

結局、以下のコードで無事に完成しました。

```VB
Dim inputValues(1 To 5) As String


Private Sub getValues()

Dim i As Integer

For i = 1 To 5
    inputValues(i) = Cells(1, i).Value
Next i
    
End Sub
```

```vb
Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)


Sub operateIe()

Const IE_MEDIUM = "{D5E8041D-920F-45E9-B8FB-B1DEB82C6E5E}"

'エクセルの必要なセルから転記するデータを集計
Call getValues

Dim username, password As String
Dim ie As Object

Set ie = GetObject("new:" & IE_MEDIUM)

ie.Visible = False
'社内WebアプリのURL
ie.navigate "http://***"

Do While ie.readyState <> 4
    Do While ie.Busy = True
    Loop
Loop

Sleep 2000

'IEを使ってすでにWebアプリにログインしている場合エラーが発生するので
'その場合はlogin_errに飛ばす
On Error GoTo login_err:
'既にログインしている場合、inputboxでユーザーに入力を促す前にエラーを生じさせ
'login_errに飛んだ方が良いので先にログインID欄にa(適当な文字)を入れようとすることでわざとエラーを生じさせる
ie.document.getElementsByName("_Account")(0).Value = "a"

username = Application.InputBox("ログインIDを入力", Type:=2)
password = Application.InputBox("パスワードを入力", Type:=2)

ie.document.getElementsByName("_Account")(0).Value = username
ie.document.getElementsByName("Password")(0).Value = password

Dim submitElm As HTMLFormElement
Set submitElm = ie.document.forms("LoginForm")
submitElm.submit

Do While ie.readyState <> 4
    Do While ie.Busy = True
    Loop
Loop

Sleep 2000

'ログインIDやパスワードを間違えた場合、エラーとなり
'タイトルがエラーページとなるので、これを利用してSubを抜ける
If ie.document.getElementsByTagName("title")(0).innerText = "エラーページ" Then
    MsgBox "IDまたはパスワードが違います" & vbLf & "再度試みてください"
    ie.Quit
    Exit Sub
End If

On Error GoTo 0
login_err:

        '必要なデータを転記する
        ie.document.getElementsByName("Subject")(0).Value = inputValues(1)
        ie.document.getElementsByName("20001")(0).Value = inputValues(2)
        ie.document.getElementsByName("20002")(0).Value = inputValues(3)
        ie.document.getElementsByName("20003")(0).Value = inputValues(4)
        ie.document.getElementsByName("20004")(0).Value = inputValues(5)
     
MsgBox "完了" & vbLf & "ブラウザを確認してください"
ie.Visible = True

End Sub
```

##まとめ
実際には転記したいデータがもう少し複雑だったのですが(エクセルのセルを扱う部分)、今回のアウトプットテーマとは関係なかったので単純化してあります。

また、私の場合、Sleepで2秒待機でちょうどうまく動きました。これは状況によると思います。