none
mshtml.HTMLDocument.framesにて”指定されたキャストは有効ではありません”が発生する RRS feed

  • 質問

  • 表題の通りです。

    Public Class Form1
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
            Dim shell As Object = Nothing
    
            Try
    
                Dim oSW As New SHDocVw.ShellWindows
                Dim oWB As Object = Nothing
                Dim htmlDocument As mshtml.HTMLDocument = Nothing
                Dim htmlElement As mshtml.IHTMLElement = Nothing
                Dim childElement As mshtml.IHTMLElement = Nothing
                Dim frameCollection As mshtml.FramesCollection
    
                'IEがすでに起動中であるかを確認(起動中のエクスプローラも含まれる)
                For Each oWB In oSW
                    'エクスプローラは除外する
                    If TypeName(oWB.Document) = "HTMLDocumentClass" Then
    
                        Dim oDc As Object = Nothing
    
                        Try
                            oDc = oWB.Document
    
                            If oDc.All.tags("frame").length >= 1 Then
                                MsgBox("フレーム数:" & oDc.All.tags("frame").length)
                            End If
    
                            htmlDocument = TryCast(oDc, mshtml.HTMLDocument)
    
                            For index As Integer = 0 To htmlDocument.frames.length - 1
    
                                frameCollection = htmlDocument.frames.item(index)
                                MsgBox(String.Format("{0}番目のフレームの中身", index.ToString) & vbCrLf & vbCrLf & _
                                        frameCollection.document.body.innerText())
                            Next
    
                        Finally
                            System.Runtime.InteropServices.Marshal.IsComObject(oDc)
                        End Try
                    End If
                Next
            Catch ex As Exception
            Finally
            End Try
        End Sub
    End Class
    

    上記コードで、フレームを使用したHTML(Frameタグ使用)のフレームごとのドキュメントの取得が確認できております。

    これを、現在業務で使用しておりますアプリケーションへ同様の実装を行ったところ、表題のように

    htmlDocument.frames

    の部分にて、”指定されたキャストは有効ではありません”が発生いたします。

    特定条件下において発生するものと思われますが、アドバイスいただけると助かります。

    <環境>

    IE9 or 10

    .Net FrameWork 3.5

    開発環境 Visual Studio 2008

    開発言語 vb.net

    <補足>

    参照設定にてmshtml.dllは以下の3つをそれぞれ参照して実行しましたがすべてエラーが発生しました。

    C:\Program Files\Microsoft.NET\Primary Interop Assemblies
    C:\Program Files\Microsoft Visual Studio 9.0\Visual Studio Tools forOffice\PIA\Office11
    C:\Program Files\Microsoft Visual Studio 9.0\Visual Studio Tools forOffice\PIA\Office12

    業務で使用しているアプリケーションは複数のアプリケーションが乗っており、その中の一つのアプリケーションで使用しております。

    メイン(exe)

     ┝ サブ(dll)

     ┝ サブ(dll) ★この中の一つのdllの中で使用

     ┗ サブ(dll)

    2013年9月13日 13:17

回答

  • 自己解決しました。

    こちらの情報の掲載不足で申し訳ありませんが、本処理(dll)は内部でスレッド処理を行っておりました。

    そのため、スレッド部分において、明示的に下記を設定することにより、表題のエラーが解決いたしました。

    ご回答いただいた皆様ありがとうございました。

    今後ともよろしくお願いします。

    t.SetApartmentState(ApartmentState.STA)

    http://msdn.microsoft.com/ja-jp/library/system.threading.thread.setapartmentstate(v=vs.90).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1

    ※リンク貼り付けでエラーが出るため、直書きしています。httpが大文字になっています。

    • 回答としてマーク t-shino 2013年9月18日 8:32
    2013年9月18日 8:32

すべての返信

  • htmlDocument.framesはコード中に2回出てきているようですがどちらでしょうか?

    frameCollection = htmlDocument.frames.item(index)

    多分こっちだと思いますが、IHTMLDocument2::framesIHTMLFramesCollection2 であり、IHTMLFramesCollection2::item の返す型は IHTMLWindow2 です。

    // Option Strict Offになってます?

    あとそれから、

    Finally
        System.Runtime.InteropServices.Marshal.IsComObject(oDc)
    End Try
    

    これは全く意味のないコードです。Marshal.IsComObjectは文字通り引数のオブジェクトがCOMオブジェクトかどうかを判定するだけのメソッドであり、参照を解放するとかそう言うのは一切ありません。

    mshtmlはインプロセスで動作するので、COMオブジェクトの参照カウントの管理はRCW(要するに.NETのインフラ)に任せれば十分でしょう。

    2013年9月13日 13:29
  • Hongliang 様

    ご回答ありがとうございます。

    ご返信が遅れ申し訳ありません。

    htmlDocument.framesでのエラーの発生箇所ですが、最初のFor文の段階で既に発生しております。

    質問の仕方が不適切でした。すみません。

    htmlDocumentのメソッドとして存在はするようですが、内部では表題のようにキャストは有効ではありませんと表示され、使用できません。

    「存在はする」というのは、デバッグで停止させ、htmlDocumentを展開し、該当のメソッドを表示して確認しています。

    // Option Strict Offになってます?

     → 現在のサンプルではオフになっていますが、実装しているソースではONにしています。

    また、htmlDocument の型を、IHTMLDocument2にしても変わらず、同様の箇所(For文)の部分でエラーが発生します。

    For文の中の受けている変数の型が違うという点は修正しておきます。

    Finallyの部分の処理もサンプルなので適当に記載してしまいました。

    いくらサンプルといえどダメですね。

    すみません。

    同様のものを使うとすれば

    System.Runtime.InteropServices.Marshal.FinalReleaseComObject 

    ですかね。

    2013年9月15日 15:50
  • 今回の問題(キャスト無効)の直接の解決策ではありませんが・・・

    frameset の中の各 frame の System.Windows.Forms.HtmlDocument オブジェクトもしくは mshtml.IHTMLDocument2 オブジェクトが取得できればいいのですよね?

    であれば、System.Windows.Forms の WebBrowser を使えばもっと簡単にできると思います。

    WebBrowser クラス
    http://msdn.microsoft.com/ja-jp/library/system.windows.forms.webbrowser(v=vs.90).aspx

    C# のコードですが、以下のような感じです。

    // ページ内の各 frame の取得
    HtmlWindowCollection windows = 
        this.webBrowser1.Document.Window.Frames;
    
    foreach (HtmlWindow window in windows)
    {
        // System.Windows.Forms.HtmlDocument の取得
        HtmlDocument document = window.Document;
    
        // mshtml.IHTMLDocument2 の取得
        mshtml.IHTMLDocument2 mshtmlDoc = 
            (mshtml.IHTMLDocument2)window.Document.DomDocument;
    }

    2013年9月16日 5:16
  • SurferOnWww 様

    ご回答ありがとうございます。

    WebBrowserを使用した方法というのは、WebBrowserコントロールを使用し、その中にHTMLを表示させて使用する方法のことと解釈しております。

    今回は、アプリケーションと、独立したIEとの連携処理になりますので、ご提案がありましたWebBrowserでの対応は要件に沿わなくなりますので、却下させていただきたいと思います。

    ご回答いただき恐縮ですが、よろしくお願いします。


    • 編集済み t-shino 2013年9月17日 0:55
    2013年9月17日 0:54
  • System.Windows.Forms.WebBrowser は SHDocVw.dll のマネージラッパーです。SHDocVw.dll が何かは以下の URL のページを見てください。

    Internet Explorer のアーキテクチャ
    http://msdn.microsoft.com/ja-jp/library/dd163924.aspx

    なので、WebBrowser から操作するのは IE です。

    > 今回は、アプリケーションと、独立したIEとの連携処理になりますので、

    というのは、見かけが違うだけで、「独立したIEとの連携処理」という要件は満たしてますよ。


    #「却下」ってずいぶんきつい言い方ですね。「採用できない」と言うことをお勧めします。

    2013年9月17日 2:34
  • SurferOnWww 様

    ご回答ありがとうございます。

    「却下」の言い回しにより不快な思いをさせて申し訳ありません。

    返信の際に妥当な言葉が出てきませんでした。

    掲載のページ、拝見いたしました。

    >というのは、見かけが違うだけで、「独立したIEとの連携処理」という要件は満たしてますよ。

    こちらの要件の記述が悪いため、以下とさせてください。

    「WebBrowserコントロールを使用せず、vb.net側からInternetExplorerのHTMLドキュメントを取得し、フレームHTMLの場合はさらにフレーム内のHTMLドキュメントを取得したい」というのが要件になります。

    2013年9月17日 5:05
  • 自己解決しました。

    こちらの情報の掲載不足で申し訳ありませんが、本処理(dll)は内部でスレッド処理を行っておりました。

    そのため、スレッド部分において、明示的に下記を設定することにより、表題のエラーが解決いたしました。

    ご回答いただいた皆様ありがとうございました。

    今後ともよろしくお願いします。

    t.SetApartmentState(ApartmentState.STA)

    http://msdn.microsoft.com/ja-jp/library/system.threading.thread.setapartmentstate(v=vs.90).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1

    ※リンク貼り付けでエラーが出るため、直書きしています。httpが大文字になっています。

    • 回答としてマーク t-shino 2013年9月18日 8:32
    2013年9月18日 8:32