C#引用Microsoft CDO将网页另存为mht的注意事项

1. 注意CreateMHTMLBody方法对应的CDO.CdoMHTMLFlags的设置,否则断网后图片等内容不能正常显示。

源自:http://hi.baidu.com/i7521/item/11a5b0999830f1da7a7f011c

上网的时候看到好的文章,大多数人都会把它保存下来。有的人可能会把页面内容复制下来存成文本文件,这种保存方式网页里的图片就丢失了,因此,ie浏览器提供了另一种保存方式,从菜单里选择“文件”->“另存为”,然后选择“单个文件mht”,这样的话,会把页面内容(页面上的图片也会打包进去)打包存成一个独立的文件,以后再用ie浏览器或其它支持mht格式的浏览器都可以在本地浏览了。

代码里怎么实现这种功能呢?其实mht文件是一种格式为MHTML(Multipurpose Internet Mail Extension HTML)的文件,是由RFC 2557定义的把一个多媒体的页面所有内容都保存到同一个文档的解决方案。我们可以根据RFC 2557的定义,完全由自己写代码来实现。但在windows平台下,也可以利用windows系统提供的类库来实现,这就是利用CDO这个COM组件来实现。

下面以C#代码为例说明怎么写代码,首先添加对Microsoft CDO for Windows 2000 Library 这个Com组件的引用,再添加adodb这个COM组件的引用, 然后按照下面的样子写代码:
string url = "http://news.sina.com.cn/c/2010-08-09/223320860143.shtml";
CDO.MessageClass msg = new CDO.MessageClass();

try
{
string mhtFile = "c:\\test\\test.mht";
msg.MDNRequested = false;
msg.MimeFormatted = true;
msg.CreateMHTMLBody(url, CDO.CdoMHTMLFlags.cdoSuppressNone, string.Empty, string.Empty);
msg.GetStream().SaveToFile(mhtFile, ADODB.SaveOptionsEnum.adSaveCreateOverWrite);
return 0;
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
return -1;
}
finally
{
msg = null;
}

需要注意的是CdoMHTMLFlags这个参数的取值,网上不少例子传的值是cdoSuppressAll,这样的话网页里所有的图片、音频等多媒体内容都不会打包进去,浏览时如果原网站把那张图片删掉了,那么你就看不到图片了,只有传递cdoSuppressNone时才会把那些图片、音频等多媒体内容都打包进去,这样即使网站删掉了图片,你仍然可以看到图片,因为图片内容已经打包到文件里去了。

 

2. 在Windows XP中运行到CreateMHTMLBody这句时报错的对应方法:

源自:http://blog.chinaunix.net/uid-26966966-id-3205396.html

牛人啊,太牛了,使用以后在XP下再也不提示“没有注册接口”了,泪牛满面。

 

 如题。当保存一个带有GZIP压缩的网站页面时,有时候会射出如下异常:

“Invalid Syntax" (无效的语法)
or
"Interface not registered" (接口未注册)

这两个异常的罪魁祸首在于CDO依赖于URLMON.DLL。CDO使用URLMON.DLL来与页面打交道,外部调用会传入URL给URLMON进行处理,并等待它返回。这时有意思的事情开始了,URLMON.DLL通过异常方式来处理外部请求,因此它会开启一些工作线程去处理事务。当这些工作线程从服务器取回页面,并发现是GZIP-compressed的,它就会调用一个COM来解压缩这些内容。接下来。。大致你也能猜到吧。
URLMON并未在工作线程上调用 CoInitialize,因此,当然程序就挂了。
这两个异常是由两个不同的问题引起的。第一个异常是由于没有初始化COM,因此没有成功地创建IClassFactory interface;第二个异常是由于虽然初始化了COM,但并没有在特定的工作线程中初始化。

知道了前因后果之后,解决问题的方法就比较多了,比如您是网站站长,您可以GZIP禁掉;又比如您可以把IE打开,关闭HTTP1.1(因为1.1允许压缩,但1.0不允许)。
当然,做为一名的开发者,您肯定不屑这么干。
那您应该比较感兴趣下面的代码,我以C#为例:
private static int INTERNET_OPTION_HTTP_VERSION = 59;

[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct INTERNET_VERSION_INFO
{
public int dwMajorVersion;
public int dwMinorVersion;
}
// BOOL InternetSetOption(
// __in HINTERNET hInternet,
// __in DWORD dwOption,
// __in LPVOID lpBuffer,
// __in DWORD dwBufferLength
//);
[DllImport("wininet.dll")]
public extern static bool InternetSetOption(IntPtr hInternet, int dwOption, ref INTERNET_VERSION_INFO lpBuffer, int dwBufferLength);

public static bool DisableHttp1_1()
{
INTERNET_VERSION_INFO internetVersionInfo = new INTERNET_VERSION_INFO();
internetVersionInfo.dwMajorVersion = 1;
internetVersionInfo.dwMinorVersion = 0;

int n = Marshal.SizeOf(internetVersionInfo);

return InternetSetOption(IntPtr.Zero, INTERNET_OPTION_HTTP_VERSION, ref internetVersionInfo, Marshal.SizeOf(internetVersionInfo));
}

 

 

posted @ 2012-11-20 17:33  KT  阅读(843)  评论(1编辑  收藏  举报