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),
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
public
void
Stat(
out
STATSTG pstatstg,
int
grfStatFlag)
{
pstatstg = new STATSTG ();
}
#endregion
}


