【问题标题】:Getting the HTML source from a WPF-WebBrowser-Control using IPersistStreamInit使用 IPersistStreamInit 从 WPF-WebBrowser-Control 获取 HTML 源
【发布时间】:2011-12-10 04:12:19
【问题描述】:

我正在尝试获取已加载到 WPF WebBrowser 控件中的网页的 HTML 源代码。这样做的唯一方法似乎是将 WebBrowser.Document 的实例转换为 IPersistStreamInit (我必须自己定义,因为它是一个 COM 接口)并调用 IPersistStreamInit.Save 方法,传递一个 一个 IStream 的实现(同样是一个 COM 接口),它将持久化 文档到流。嗯,有点:我总是得到流的前 4 KB,而不是整个文档,我不知道为什么。

IPersistStreamInit 的代码如下:

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Security;

namespace PayPal.SkyNet.BpiTool.Interop
{
    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), 
        SuppressUnmanagedCodeSecurity, 
        Guid("7FD52380-4E07-101B-AE2D-08002B2EC713")]
    public interface IPersistStreamInit
    {
        void GetClassID(out Guid pClassID);
        [PreserveSig]
        int IsDirty();
        void Load([In, MarshalAs(UnmanagedType.Interface)] IStream pstm);
        void Save([In, MarshalAs(UnmanagedType.Interface)] IStream pstm, [In, MarshalAs(UnmanagedType.Bool)] bool fClearDirty);
        void GetSizeMax([Out, MarshalAs(UnmanagedType.LPArray)] long pcbSize);
        void InitNew();
    }
}

这是 IStream-Implementation 的代码:

using System;
using System.IO;
using System.Runtime.InteropServices.ComTypes;

namespace PayPal.SkyNet.BpiTool.Interop
{
    public class ComStream : IStream
    {
        private Stream _stream;

        public ComStream(Stream stream)
        {
            this._stream = stream;
        }

        public void Commit(int grfCommitFlags)
        {
        }

        public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
        {
        }

        public void LockRegion(long libOffset, long cb, int dwLockType)
        {
        }

        public void Read(byte[] pv, int cb, IntPtr pcbRead)
        {
            this._stream.Read(pv, (int)this._stream.Position, cb);
        }

        public void Revert()
        {
        }

        public void SetSize(long libNewSize)
        {
            this._stream.SetLength(libNewSize);
        }

        public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
        {
            pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG();
        }

        public void UnlockRegion(long libOffset, long cb, int dwLockType)
        {
        }

        public void Write(byte[] pv, int cb, IntPtr pcbWritten)
        {
            this._stream.Write(pv, 0, cb);
        }

        public void Clone(out IStream outputStream)
        {
            outputStream = null;
        }

        public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
        {
            this._stream.Seek(dlibMove, (SeekOrigin)dwOrigin);
        }
    }
}

现在我有一个类来总结它。因为我不想重新分配 mshtml-interop-assembly,所以我选择了后期绑定——因为后期绑定在 VB 中更容易,所以我在 VB 中做到了。代码如下:

Option Strict Off
Option Explicit Off

Imports System.IO

Public Class HtmlDocumentWrapper : Implements IDisposable

    Private htmlDoc As Object

    Public Sub New(ByVal htmlDoc As Object)
        Me.htmlDoc = htmlDoc
    End Sub

    Public Property Document As Object
        Get
            Return Me.htmlDoc
        End Get
        Set(value As Object)
            Me.htmlDoc = Nothing
            Me.htmlDoc = value
        End Set
    End Property

    Public ReadOnly Property DocumentStream As Stream
        Get
            Dim str As Stream = Nothing
            Dim psi As IPersistStreamInit = CType(Me.htmlDoc, IPersistStreamInit)
            If psi IsNot Nothing Then
                str = New MemoryStream
                Dim cStream As New ComStream(str)
                psi.Save(cStream, False)
                str.Position = 0
            End If
            Return str
        End Get
    End Property
End Class

现在我应该可以使用所有这些了:

private void Browser_Navigated(object sender, NavigationEventArgs e)
{
    HtmlDocumentWrapper doc = new HtmlDocumentWrapper();
    doc.Document = Browser.Document;
    using (StreamReader sr = new StreamReader(doc.DocumentStream))
    {
        using (StreamWriter sw = new StreamWriter("test.txt"))
        {
            //BOOM! Only 4kb of HTML source
            sw.WriteLine(sr.ReadToEnd());
            sw.Flush();
        }
    }
}

任何人都知道,为什么我没有得到整个 HTML 源代码?非常感谢任何帮助。

问候

阿恩

【问题讨论】:

  • 您是否尝试过使用MSHTML 来获取HTML 文档会更容易。
  • AFAIS 使用 MSHTML 不会让我访问完整的源代码,我真的需要完整的源代码。另一个问题:这是来自将被数百万用户使用的面向客户的应用程序的代码,我不想重新分发 Interop.MSHTML - 鉴于所有不同的 IE 版本,这在过去一直是一个脆弱的解决方案。
  • 看看能不能帮到你stackoverflow.com/questions/677306/…
  • 不,这无济于事,WPF 是另一种野兽。
  • 导航!=加载完成

标签: c# wpf com webbrowser-control com-interop


【解决方案1】:

将您的代码从 Browser.Navigated 移动到 Browser.LoadCompleted,正如盛江在上面正确指出的那样,它可以工作

【讨论】:

    【解决方案2】:

    这只是猜测:

    流的长度未知,因为它可能仍在下载。您需要阅读它,直到它显示 EOF。

    【讨论】:

      猜你喜欢
      • 2014-10-22
      • 2015-07-10
      • 2017-06-11
      • 2018-10-15
      • 1970-01-01
      • 2011-03-17
      • 2014-05-25
      • 2011-04-24
      • 2012-12-27
      相关资源
      最近更新 更多