IE9をType.InvokeMemberで操作

IE9では、Type.InvokeMemberを利用して、IEを操作することになるのだけど、情報が少ない。
従って、実験を繰り返して調べることになる。
ここでは、その研究結果のコードを掲載しておきます。もっと洗練された方法があるはずだけれど、とりあえず動くものを作るのが必要なので、野暮ったいのは勘弁して下さい。
IE8までは、もっと簡単なコードで充分だったのに、IE9では厳密に指定しないと駄目。

Visual Studio 2010 / VB.net
http://www.moderns.co.jp/files/UsingIE9Object.zip

Imports System.Reflection

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

        'BindingFlags.GetProperty などを短く置き変えることが出来る。
        'Dim getPr As BindingFlags = BindingFlags.GetProperty
        'Dim setPr As BindingFlags = BindingFlags.SetProperty
        'Dim invMe As BindingFlags = BindingFlags.InvokeMethod


        Dim ieObj As Object

        ieObj = CreateObject("InternetExplorer.application") 'IEのオブジェクトを作る
        If ieObj Is Nothing Then
            MsgBox("IE Nothing")
        End If

        ieObj.Visible = True '見えるようにする
        Dim uri As String = My.Computer.FileSystem.CombinePath(My.Application.Info.DirectoryPath, "IE9.html")
        'uri = "http://www.moderns.co.jp/"
        Try
            ieObj.Navigate2(uri)
        Catch
            MsgBox("file not found:" & vbCrLf & uri)
            Exit Sub
        End Try

        Call ieWait(ieObj)



        Dim ieDoc As Object
        Dim typ As Type



        typ = Type.GetTypeFromProgID("mhtmlfile")
        'あるいは、こちらでもOK。
        'typ = Type.GetTypeFromCLSID(New System.Guid("{3050F4E7-98B5-11CF-BB82-00AA00BDCE0B}"))

        'ieDoc = ieObj.Document             'IE8までは、こうした文法で良かった。IE9では、以下のようにするのが良い。
        ieDoc = typ.InvokeMember("document", BindingFlags.GetProperty, Nothing, ieObj, Nothing)

        'Title
        TextBox1.Text &= "title: " & typ.InvokeMember("title", BindingFlags.GetProperty, Nothing, ieDoc, Nothing) & vbCrLf

        'URLは大文字
        TextBox1.Text &= "URL: " & typ.InvokeMember("URL", BindingFlags.GetProperty, Nothing, ieDoc, Nothing) & vbCrLf

        'Linkの数
        TextBox1.Text &= "Link count : " & typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing).length & vbCrLf

        'TextBox1.Text &= "URL: " & GetP("URL", ieDoc) & vbCrLf
        'TextBox1.Text &= "Link count : " & GetP("links", ieDoc).length & vbCrLf

        'Typeを表示 mshtml.HTMLAnchorElementClass となる。
        TextBox1.Text &= typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing)(1).ToString & vbCrLf

        '2番目のリンクのInnerText
        TextBox1.Text &= "Second Link InnterText : " & typ.InvokeMember("innerText", BindingFlags.GetProperty, Nothing, typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing)(1), Nothing) & vbCrLf

        '2番目のリンクをクリックする。
        'Dim links As Object = typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing) 'link 全部のObject
        'typ.InvokeMember("click", BindingFlags.InvokeMethod, Nothing, links(1), Nothing) 'links(1)は、2番目のlinkを意味する。

        'あるいは、こちらでも同じ。
        'Dim link2 As Object = typ.InvokeMember("links", BindingFlags.GetProperty, Nothing, ieDoc, Nothing)(1)   '2番目のlinkのObject (0)1番目 (1)2番目 (2)3番目 ・・・
        'typ.InvokeMember("click", BindingFlags.InvokeMethod, Nothing, link2, Nothing)

        'Call ieWait(ieObj)

        TextBox1.Text &= vbCrLf

        'Body Elementを確定する2種類の方法 
        '1 how to get the body object
        Dim htmlBody As Object
        htmlBody = typ.InvokeMember("body", BindingFlags.GetProperty, Nothing, ieDoc, Nothing)
        'htmlBody = GetP("body", ieDoc)
        TextBox1.Text &= "body innerHTML : " & typ.InvokeMember("innerHTML", BindingFlags.GetProperty, Nothing, htmlBody, Nothing) & vbCrLf & vbCrLf

        '2 how to get the body object
        Dim htmlBody2 As Object
        htmlBody2 = typ.InvokeMember("getElementsByTagName", BindingFlags.InvokeMethod, Nothing, ieDoc, {"body"})(0)
        'htmlBody2 = InvokeM("getElementsByTagName", ieDoc, {"body"})(0)
        TextBox1.Text &= "body innerHTML : " & typ.InvokeMember("innerHTML", BindingFlags.GetProperty, Nothing, htmlBody2, Nothing) & vbCrLf & vbCrLf


        'Form Element
        Dim formElm As Object = typ.InvokeMember("getElementsByName", BindingFlags.InvokeMethod, Nothing, ieDoc, {"formName1"})

        Dim inputElm As Object = typ.InvokeMember("getElementsByTagName", BindingFlags.InvokeMethod, Nothing, formElm(0), {"input"})


        'InputBox  inputElmを利用
        For i As Integer = 0 To inputElm.length - 1
            TextBox1.Text &= typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) & vbCrLf
            If typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) = "siteurl" Then
                typ.InvokeMember("value", BindingFlags.SetProperty, Nothing, inputElm(i), {"input value"})
            End If
        Next

        'CheckBox  inputElmを利用
        For i As Integer = 0 To inputElm.length - 1
            TextBox1.Text &= typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) & vbCrLf
            If typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) = "c1" Then
                typ.InvokeMember("checked", BindingFlags.SetProperty, Nothing, inputElm(i), {"True"})
            End If
        Next

        'RadioButton  inputElmを利用
        For i As Integer = 0 To inputElm.length - 1
            TextBox1.Text &= typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) & vbCrLf
            If typ.InvokeMember("name", BindingFlags.GetProperty, Nothing, inputElm(i), Nothing) = "r1" Then
                typ.InvokeMember("checked", BindingFlags.SetProperty, Nothing, inputElm(i), {"True"})
            End If
        Next


        'Select and Option
        Dim selectElm As Object = typ.InvokeMember("getElementsByName", BindingFlags.InvokeMethod, Nothing, ieDoc, {"sele1"})(0)
        Dim optionsElm As Object = typ.InvokeMember("getElementsByTagName", BindingFlags.InvokeMethod, Nothing, selectElm, {"option"})

        For i As Integer = 0 To optionsElm.length - 1
            TextBox1.Text &= typ.InvokeMember("innerText", BindingFlags.GetProperty, Nothing, optionsElm(i), Nothing) & vbCrLf
            If typ.InvokeMember("innerText", BindingFlags.GetProperty, Nothing, optionsElm(i), Nothing) = "def" Then
                typ.InvokeMember("selected", BindingFlags.SetProperty, Nothing, optionsElm(i), {"True"})
            End If
        Next


        'TextArea
        Dim textAElem As Object
        textAElem = typ.InvokeMember("getElementsByName", BindingFlags.InvokeMethod, Nothing, ieDoc, {"te1"})
        'textAElem = InvokeM("getElementsByName", ieDoc, {"te1"})

        typ.InvokeMember("value", BindingFlags.SetProperty, Nothing, textAElem(0), {"textarea value"})
        'Call SetP("value", textAElem(0), {"textarea value"})



        'Form InnerHTML
        TextBox1.Text &= vbCrLf & "Form innerHTML : " & GetP("innerHTML", InvokeM("getElementsByName", ieDoc, {"formName1"})(0)) & vbCrLf

    End Sub

    ''' <summary>
    ''' IEの表示が完了するまで待つ
    ''' </summary>
    ''' <param name="ieObj"></param>
    ''' <remarks></remarks>
    Sub ieWait(ByRef ieObj As Object)

        Try

            Dim sw As New Stopwatch
            sw.Start()

            Do While (ieObj.Busy OrElse ieObj.ReadyState <> SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE) _
                        AndAlso sw.Elapsed <= New TimeSpan(0, 0, 0, 20)     '読み込み中でも、CheckWatingSecond(20秒)を超えたら抜ける
                Application.DoEvents() '読み込み中なら待つ
            Loop

            sw = Stopwatch.StartNew()
            Do While sw.Elapsed <= New TimeSpan(0, 0, 0, 0, 1000)   '念のため読み込みが終わってもさらに1秒待つ
                Application.DoEvents()
            Loop
            sw.Reset()

        Catch ex As Exception
            'IEが閉じられていた場合などエラーになるので、それをキャッチする。
            MsgBox("Error")


        End Try

    End Sub

    ''' <summary>
    ''' InvokeMemberの、GetPropertyを実行
    ''' </summary>
    ''' <param name="name1"></param>
    ''' <param name="target1"></param>
    ''' <param name="args1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GetP(ByVal name1 As String, ByVal target1 As Object, Optional ByVal args1 As Object = Nothing)

        Dim typ As Type = Type.GetTypeFromProgID("mhtmlfile")
        Return typ.InvokeMember(name1, BindingFlags.GetProperty, Nothing, target1, args1)

    End Function

    ''' <summary>
    ''' InvokeMemberの、SetPropertyを実行
    ''' </summary>
    ''' <param name="name1"></param>
    ''' <param name="target1"></param>
    ''' <param name="args1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function SetP(ByVal name1 As String, ByVal target1 As Object, Optional ByVal args1 As Object = Nothing)

        Dim typ As Type = Type.GetTypeFromProgID("mhtmlfile")
        Return typ.InvokeMember(name1, BindingFlags.SetProperty, Nothing, target1, args1)

    End Function


    ''' <summary>
    ''' InvokeMemberの、InvokeMethodを実行
    ''' </summary>
    ''' <param name="name1"></param>
    ''' <param name="target1"></param>
    ''' <param name="args1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function InvokeM(ByVal name1 As String, ByVal target1 As Object, Optional ByVal args1 As Object = Nothing)

        Dim typ As Type = Type.GetTypeFromProgID("mhtmlfile")
        Return typ.InvokeMember(name1, BindingFlags.InvokeMethod, Nothing, target1, args1)

    End Function

End Class

対象のHTML IE9.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
	<title>IE9 Object</title>
</head>
<body>



<p><a href="http://www.moderns.co.jp/">modern design laboratory</a></p>
<p><a href="http://www.msignal.info/">M.Signal</a></p>

<p><a href="http://www.linkget.info/">LinkGet</a></p>

<form action="form1.html" name ="formName1" method="get">

<input type="text" name="siteurl" size="20" />

<input type="checkbox" name="c1" value="">
<input type="checkbox" name="c2" value="">

<input type="radio" name="r1" value="b1">
<input type="radio" name="r1" value="b2">
<input type="radio" name="r1" value="b3">

<select name="sele1" size="1" tabindex="0">
<option value="">abc</option>

<option value="">def</option>
<option value="">ghi</option>
</select>


<textarea name="te1" rows="2" cols="20" tabindex="0"></textarea>

</form>


</body>
</html>