Flier's Sky

天空,蓝色的天空,眼睛看不到的东西,眼睛看得到的东西

导航

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

Posted on 2004-07-08 09:31  Flier Lu  阅读(17838)  评论(3编辑  收藏  举报

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

http://www.blogcn.com/user8/flier_lu/index.html?id=1125200&run=.0D9CAA6

趁周末想折腾一下嵌入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), 
trueout 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), trueout 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

  
       
public void Stat(out STATSTG pstatstg, int grfStatFlag)
       
{
         pstatstg 
= new STATSTG ();
       }

  
       
#endregion
     }