トップ回答者
mshtml.HTMLDocument.framesにて”指定されたキャストは有効ではありません”が発生する

質問
-
表題の通りです。
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)
回答
-
自己解決しました。
こちらの情報の掲載不足で申し訳ありませんが、本処理(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
すべての返信
-
htmlDocument.framesはコード中に2回出てきているようですがどちらでしょうか?
frameCollection = htmlDocument.frames.item(index)
多分こっちだと思いますが、IHTMLDocument2::frames が IHTMLFramesCollection2 であり、IHTMLFramesCollection2::item の返す型は IHTMLWindow2 です。
// Option Strict Offになってます?
あとそれから、
Finally System.Runtime.InteropServices.Marshal.IsComObject(oDc) End Try
これは全く意味のないコードです。Marshal.IsComObjectは文字通り引数のオブジェクトがCOMオブジェクトかどうかを判定するだけのメソッドであり、参照を解放するとかそう言うのは一切ありません。
mshtmlはインプロセスで動作するので、COMオブジェクトの参照カウントの管理はRCW(要するに.NETのインフラ)に任せれば十分でしょう。
-
Hongliang 様
ご回答ありがとうございます。
ご返信が遅れ申し訳ありません。
htmlDocument.framesでのエラーの発生箇所ですが、最初のFor文の段階で既に発生しております。
質問の仕方が不適切でした。すみません。
htmlDocumentのメソッドとして存在はするようですが、内部では表題のようにキャストは有効ではありませんと表示され、使用できません。
「存在はする」というのは、デバッグで停止させ、htmlDocumentを展開し、該当のメソッドを表示して確認しています。
// Option Strict Offになってます?
→ 現在のサンプルではオフになっていますが、実装しているソースではONにしています。
また、htmlDocument の型を、IHTMLDocument2にしても変わらず、同様の箇所(For文)の部分でエラーが発生します。
For文の中の受けている変数の型が違うという点は修正しておきます。
Finallyの部分の処理もサンプルなので適当に記載してしまいました。
いくらサンプルといえどダメですね。
すみません。
同様のものを使うとすれば
System.Runtime.InteropServices.Marshal.FinalReleaseComObject
ですかね。
-
今回の問題(キャスト無効)の直接の解決策ではありませんが・・・
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).aspxC# のコードですが、以下のような感じです。
// ページ内の各 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; }
-
System.Windows.Forms.WebBrowser は SHDocVw.dll のマネージラッパーです。SHDocVw.dll が何かは以下の URL のページを見てください。
Internet Explorer のアーキテクチャ
http://msdn.microsoft.com/ja-jp/library/dd163924.aspxなので、WebBrowser から操作するのは IE です。
> 今回は、アプリケーションと、独立したIEとの連携処理になりますので、
というのは、見かけが違うだけで、「独立したIEとの連携処理」という要件は満たしてますよ。
#「却下」ってずいぶんきつい言い方ですね。「採用できない」と言うことをお勧めします。 -
SurferOnWww 様
ご回答ありがとうございます。
「却下」の言い回しにより不快な思いをさせて申し訳ありません。
返信の際に妥当な言葉が出てきませんでした。
掲載のページ、拝見いたしました。
>というのは、見かけが違うだけで、「独立したIEとの連携処理」という要件は満たしてますよ。
こちらの要件の記述が悪いため、以下とさせてください。
「WebBrowserコントロールを使用せず、vb.net側からInternetExplorerのHTMLドキュメントを取得し、フレームHTMLの場合はさらにフレーム内のHTMLドキュメントを取得したい」というのが要件になります。
-
自己解決しました。
こちらの情報の掲載不足で申し訳ありませんが、本処理(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