C#中实现WebBrowser控件的HTML源代码读写

来源:互联网 发布:js 匹配中文 编辑:程序博客网 时间:2024/06/11 21:02

趁周末想折腾一下嵌入ASP.NET的WinForm程序
需要用到WebBrowser控件的HTML源码读写
就把以前的一些代码片断移值到C#下
顺便发个帖子备忘,呵呵
  
思路其实很简单,直接通过document.documentElement.outerHTML
或者使用IPersistStreamInit接口直接对流进行处理
前者我就不废话了,后者实现方法如下
  
首先是写入HTML到已初始化的WebBrowser控件
初始化可以通过Navigate("about:blank")完成
必须确保WebBrowser.Document != null
否则应该推迟到DocumentComplete事件再读写
  
UCOMIStream stream = null;
  
CreateStreamOnHGlobal(Marshal.StringToHGlobalUni(value), true, out stream);
   

 

if(stream != null)
  
{
    IPersistStreamInit persistentStreamInit =
      (IPersistStreamInit)WebBrowser.Document;
  
    persistentStreamInit.InitNew();
    persistentStreamInit.Load(stream);
    persistentStreamInit = null;
}


  
UCOMIStream是COM中IStream的CLR版本
CreateStreamOnHGlobal函数从一个字符串的地址
创建一个IStream供使用
  


[DllImport("ole32.dll", PreserveSig=false)]
static extern void CreateStreamOnHGlobal(IntPtr hGlobal,
    Boolean fDeleteOnRelease, [Out] out UCOMIStream pStream);

  
然后就是通过IPersistStreamInit接口初始化并载入HTML源码,
IPersistStreamInit接口CLR缺省没有导入,定义如下
  

[ComVisible(true), ComImport(), Guid("7FD52380-4E07-101B-AE2D-08002B2EC713"),
   InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPersistStreamInit
{
    void GetClassID([In, Out] ref Guid pClassID);
  
    [return: MarshalAs(UnmanagedType.I4)] [PreserveSig]
    int IsDirty();
  
    void Load([In, MarshalAs(UnmanagedType.Interface)] UCOMIStream pstm);
    void Save([In, MarshalAs(UnmanagedType.Interface)] UCOMIStream pstm,
              [In, MarshalAs(UnmanagedType.I4)] int fClearDirty);
    void GetSizeMax([Out, MarshalAs(UnmanagedType.LPArray)] long pcbSize);
    void InitNew();
}

  
读取HTML也是类似思路,将HTML源码写到一个IStream中
然后转换成字符串供C#代码使用,不过实现方式比较麻烦
  
比较简单的方法还是使用ole32.dll提供的函数
重建流,但这需要预先设定流的长度,如
  

UCOMIStream stream = null;
  
CreateStreamOnHGlobal(Marshal.AllocHGlobal(4096), true, out stream);
  
IPersistStreamInit persistentStreamInit =
    (IPersistStreamInit)WebBrowser.Document;
  
persistentStreamInit.Save(stream, 0);
persistentStreamInit = null;
  
IntPtr pStr;
  
GetHGlobalFromStream(stream, out pStr);
  
return Marshal.PtrToStringAnsi(pStr);

  
然后使用GetHGlobalFromStream函数和
Marshal.PtrToStringAnsi将流转换为字符串
另外一种方法是自行实现一个支持IStream接口的类
通过流的方式灵活完成读取操作,我比较喜欢这种


using(MemoryStream stream = new MemoryStream())


{
    ComStreamAdapter adapter = new ComStreamAdapter(stream);
  
    IPersistStreamInit persistentStreamInit =
      (IPersistStreamInit)WebBrowser.Document;
  
    persistentStreamInit.Save(adapter, 0);
  
    stream.Seek(0, SeekOrigin.Begin);
  
    using(StreamReader reader = new StreamReader(stream))
    {
      return reader.ReadToEnd();
    }
}


  
这里的ComStreamAdapter是一个使用了adapter模式的类
将普通的System.IO.Stream转换为IStream支持的类
  
   

   public class ComStreamAdapter : UCOMIStream
      {
        private Stream _stream;


  
        public ComStreamAdapter(Stream stream)
        {
          _stream = stream;
        }
  
        UCOMIStream Members#region UCOMIStream Members
  
        public void Commit(int grfCommitFlags)
        {
        }
  
        public void Clone(out UCOMIStream ppstm)
        {
          ppstm = null;
        }
  
        public void CopyTo(UCOMIStream pstm, long cb, System.IntPtr pcbRead, Syste
m.IntPtr pcbWritten)
        {
        }
  


        public void Revert()
        {
        }
  
        public void LockRegion(long libOffset, long cb, int dwLockType)
        {
        }
  
        public void UnlockRegion(long libOffset, long cb, int dwLockType)
        {
        }
  
        public void Seek(long dlibMove, int dwOrigin, System.IntPtr plibNewPositio
n)
        {
          _stream.Seek(dlibMove, (SeekOrigin)dwOrigin);
  
          if(plibNewPosition != IntPtr.Zero)
          {
            Marshal.WriteInt32(plibNewPosition, (int)_stream.Position);
          }
        }


  
        public void Read(byte[] pv, int cb, System.IntPtr pcbRead)
        {
          int size = _stream.Read(pv, (int)_stream.Position, cb);
  
          if(pcbRead != IntPtr.Zero)
          {
            Marshal.WriteInt32(pcbRead, size);
          }
        }
  
        public void Write(byte[] pv, int cb, System.IntPtr pcbWritten)
        {
          _stream.Write(pv, 0, cb);
  
          if(pcbWritten != IntPtr.Zero)
          {
            Marshal.WriteInt32(pcbWritten, cb);
          }
        }
  
        public void SetSize(long libNewSize)


          _stream.SetLength(libNewSize);
        }
  
        public void Stat(out STATSTG pstatstg, int grfStatFlag)
        {
          pstatstg = new STATSTG ();
        }
  
        #endregion
      }