17035


# 概要

次のような構造を持つオブジェクト内のFrameのDocumentの内容（★印）を取得したいです。

[code]

    wbm
      Control
      currentDocument
      Document
        Window
          Frames
            htmlFramesCollection2
              Document
                Body
                  InnerHtml
      m_MRE
      WebBrowser
        base
        Document
          Body
            ★InnerHtml
        Application
          Document
            frames
              body
                InnerHtml
    
[/code]

htmlFramesCollection2内にFrameがある場合は`currentDocument.Window.Frames[name].Document`のような形で取得できているのですが、新規にIEで開いてしまうウィンドウをWebBrowserで開く下記のような形で拡張しているため、目的のFrameはWebBrowser内にあります。

[code]

    public class ExtendedWebBrowser : WebBrowser
        {
            private AxHost.ConnectionPointCookie cookie;
            private WebBrowser2EventHelper helper;
            [DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
        [DispIdAttribute(200)]
    
        public object Application
        {
            get
            {
                if (this.ActiveXInstance == null)
                {
                    throw new AxHost.InvalidActiveXStateException("Application", AxHost.ActiveXInvokeKind.PropertyGet);
                }
                return this.ActiveXInstance.GetType().InvokeMember("Application", System.Reflection.BindingFlags.GetProperty, null, this.ActiveXInstance, null);
    
    
            }
        }
    
        [DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
        [DispIdAttribute(552)]
        public bool RegisterAsBrowser
        {
            get
            {
                if (this.ActiveXInstance == null)
                {
                    throw new AxHost.InvalidActiveXStateException("RegisterAsBrowser", AxHost.ActiveXInvokeKind.PropertyGet);
                }
                return (bool)this.ActiveXInstance.GetType().InvokeMember("RegisterAsBrowser", System.Reflection.BindingFlags.GetProperty, null, this.ActiveXInstance, null);
    
    
            }
            set
            {
                if (this.ActiveXInstance == null)
                {
                    throw new AxHost.InvalidActiveXStateException("RegisterAsBrowser", AxHost.ActiveXInvokeKind.PropertySet);
                }
                this.ActiveXInstance.GetType().InvokeMember("RegisterAsBrowser", System.Reflection.BindingFlags.SetProperty, null, this.ActiveXInstance, new object[] { value });
            }
        }
    
        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected override void CreateSink()
        {
            base.CreateSink();
            helper = new WebBrowser2EventHelper(this);
            cookie = new AxHost.ConnectionPointCookie(this.ActiveXInstance, helper, typeof(DWebBrowserEvents2));
        }
    
        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected override void DetachSink()
        {
            if (cookie != null)
            {
                cookie.Disconnect();
                cookie = null;
            }
            base.DetachSink();
        }
    
        public event WebBrowserNewWindow2EventHandler NewWindow2 = (o, e) => { };
    
        protected virtual void OnNewWindow2(WebBrowserNewWindow2EventArgs e)
        {
            NewWindow2(this, e);
        }
    
        private class WebBrowser2EventHelper : StandardOleMarshalObject, DWebBrowserEvents2
        {
            private ExtendedWebBrowser parent;
    
            public WebBrowser2EventHelper(ExtendedWebBrowser parent)
            {
                this.parent = parent;
            }
    
            public void NewWindow2(ref object ppDisp, ref bool cancel)
            {
                var e = new WebBrowserNewWindow2EventArgs(ppDisp);
                this.parent.OnNewWindow2(e);
                ppDisp = e.ppDisp;
                cancel = e.Cancel;
            }
        }
    }
    
    public delegate void WebBrowserNewWindow2EventHandler(object sender, WebBrowserNewWindow2EventArgs e);
    
    public class WebBrowserNewWindow2EventArgs : CancelEventArgs
    {
        public object ppDisp { get; set; }
    
        public WebBrowserNewWindow2EventArgs(object ppDisp)
        {
            this.ppDisp = ppDisp;
        }
    }
    
    [ComImport, Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    [TypeLibType(TypeLibTypeFlags.FHidden)]
    public interface DWebBrowserEvents2
    {
        [DispId(251)]
        void NewWindow2([InAttribute(), OutAttribute(), MarshalAs(UnmanagedType.IDispatch)] ref object ppDisp, [InAttribute(), OutAttribute()] ref bool cancel);
    }
    
[/code]

下記は使用する側のコードです。

[code]

    private void WebBrowser_NewWindow2(object sender, WebBrowserNewWindow2EventArgs e)
        {
            // 新しい WebBrowser の初期化
            WebBrowser = new ExtendedWebBrowser();
            WebBrowser.Dock = DockStyle.Fill;
            Control.Controls.Add(WebBrowser);
    
            var tabPage = new TabPage();
    
            // 新しい WebBrowser に表示させる設定
            e.ppDisp = this.WebBrowser.Application;
            WebBrowser.RegisterAsBrowser = true;
            WebBrowser.NewWindow2 += WebBrowser_NewWindow2;
        }
    
[/code]

[MSDN](https://msdn.microsoft.com/ja-
jp/library/system.windows.forms.htmldocument\(v=vs.110\).aspx)に

> An HTML document may contain frames, which are different windows inside of
> the WebBrowser control. Each frame displays its own HTML page. The Frames
> collection is available through the Window property.

という記述があり、Window下にないとアクセスできないのではないかと思うのですが、WebBrowser内にWindowプロパティがなく扱えていません…

# Frameの構造

[code]

    <FRAMESET id=FRAMESET2 onload=SetLoadFlg() border=0 frameBorder=0 rows=300px,*,40px><FRAME noResize src="/hoge/html/hogehoge.html" name=M1 scrolling=no><FRAME noResize src="/web21/execJ/servlet/ACH99OMCL_WEBCNTL?_W_SubFname=M2" name=M2><FRAME noResize src="/moge/html/mogemoge.html" name=M3 ></FRAMESET>
    
[/code]

# 動作環境

・.NET Frame Work 4.5  
・Visual Studio2013

# 目的

サイト上のFrame内のDocumentを取得した上で、その中のリンク要素を拾ってサイト内の遷移を勧めたいです。

よろしくお願いします。


CC BY-SA 3.0
2015-09-28T13:55:56.390
17033
2015-09-28T14:50:14.683
12459
question
c# visual-studio dom
C#で個別のFrame内のDocmentを取得するにはどうすればよいのでしょうか？


[WebBrowser.Documentプロパティ](https://msdn.microsoft.com/ja-
jp/library/system.windows.forms.webbrowser.document\(v=vs.100\).aspx)から辿れるクラスは全てCOMをラップしたものに過ぎず、提供されていない機能にアクセスしたい場合はアンマネージインターフェイスへのポインターからアクセスする必要があります。  
これらオブジェクトはDOMを表すものですが、DOMはセキュリティのためフレームを超えてアクセスすることができないよう制限されています。  
これを回避するためにはDOM外からアクセスする必要があります。具体的には

  1. `HtmlDocument.GetElementById()`などで目的のフレームの要素（`HtmlElement`）を取得する
  2. `HtmlElement.DocElement`からアンマネージインターフェイスへのポインターを得る
  3. アンマネージインターフェイスへのポインターから`IHTMLFrameBase2`インターフェイスを得る
  4. `IHTMLFrameBase2.contentWindow`プロパティで`IHTMLWindow2`インターフェイスを得る
  5. `IHTMLWindow2`インターフェイスから`IServiceProvider`インターフェイスを得る
  6. `IServiceProvider.QueryService`メソッドに引数`IID_IWebBrowserApp`と`IID_IWebBrowser2`を渡すことで`IWebBrowser2`インターフェイスを得る
  7. `IWebBrowser2.Document`プロパティで`IHTMLDocument`インターフェイスを得る

以上のステップでフレームに読み込まれたHTMLのDOMにアクセスできます。  
しかし、ステップ2.の時点で.NETオブジェクトではなくCOMインターフェイスですし、最終的に得られるのもCOMインターフェイスですので、その後のDOMアクセスも引き続きCOMインターフェイスを操作する必要があります。

コードを提示することもできますが、ほとんどCOM定義に終始することになるのであまり意味があるとも思えません。


CC BY-SA 3.0
2015-09-28T14:50:14.683
17035
2015-09-28T14:50:14.683
4236
17033
answer