此文做法不是 Control.DrawToBitmap ,而是直接QueryInterface 浏览器Com对象的 IViewObject 接口,用它实现的Draw方法,画到图像上。

  首先,定义IViewObject的接口声名,如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Security;
using System.Runtime.InteropServices; namespace SnapUtility
{
/// <summary>
/// 从 .Net 2.0 的 System.Windows.Forms.Dll 库提取
/// 版权所有:微软公司
/// </summary>
[SuppressUnmanagedCodeSecurity]
internal static class UnsafeNativeMethods
{
public static Guid IID_IViewObject = new Guid("{0000010d-0000-0000-C000-000000000046}"); [ComImport, Guid("0000010d-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IViewObject
{
[PreserveSig]
int Draw([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [In] NativeMethods.tagDVTARGETDEVICE ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, [In] NativeMethods.COMRECT lprcBounds, [In] NativeMethods.COMRECT lprcWBounds, IntPtr pfnContinue, [In] int dwContinue);
[PreserveSig]
int GetColorSet([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [In] NativeMethods.tagDVTARGETDEVICE ptd, IntPtr hicTargetDev, [Out] NativeMethods.tagLOGPALETTE ppColorSet);
[PreserveSig]
int Freeze([In, MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, [Out] IntPtr pdwFreeze);
[PreserveSig]
int Unfreeze([In, MarshalAs(UnmanagedType.U4)] int dwFreeze);
void SetAdvise([In, MarshalAs(UnmanagedType.U4)] int aspects, [In, MarshalAs(UnmanagedType.U4)] int advf, [In, MarshalAs(UnmanagedType.Interface)] System.Runtime.InteropServices.ComTypes.IAdviseSink pAdvSink);
void GetAdvise([In, Out, MarshalAs(UnmanagedType.LPArray)] int[] paspects, [In, Out, MarshalAs(UnmanagedType.LPArray)] int[] advf, [In, Out, MarshalAs(UnmanagedType.LPArray)] System.Runtime.InteropServices.ComTypes.IAdviseSink[] pAdvSink);
}
}
}

  该接口.net 自己带了,只是internal形式,所以只有想办法用Reflector 将它弄出来,相关的还有几个类,分别是tagLOGPALETTE,COMRECT,tagDVTARGETDEVICE.
定义如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Drawing;
using System.Runtime.InteropServices; namespace SnapUtility
{
/// <summary>
/// 从 .Net 2.0 的 System.Windows.Forms.Dll 库提取
/// 版权所有:微软公司
/// </summary>
internal static class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
public sealed class tagDVTARGETDEVICE
{
[MarshalAs(UnmanagedType.U4)]
public int tdSize;
[MarshalAs(UnmanagedType.U2)]
public short tdDriverNameOffset;
[MarshalAs(UnmanagedType.U2)]
public short tdDeviceNameOffset;
[MarshalAs(UnmanagedType.U2)]
public short tdPortNameOffset;
[MarshalAs(UnmanagedType.U2)]
public short tdExtDevmodeOffset;
} [StructLayout(LayoutKind.Sequential)]
public class COMRECT
{
public int left;
public int top;
public int right;
public int bottom;
public COMRECT() { } public COMRECT(Rectangle r)
{
this.left = r.X;
this.top = r.Y;
this.right = r.Right;
this.bottom = r.Bottom;
} public COMRECT(int left, int top, int right, int bottom)
{
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
} public static NativeMethods.COMRECT FromXYWH(int x, int y, int width, int height)
{
return new NativeMethods.COMRECT(x, y, x + width, y + height);
} public override string ToString()
{
return string.Concat(new object[] { "Left = ", this.left, " Top ", this.top, " Right = ", this.right, " Bottom = ", this.bottom });
}
} [StructLayout(LayoutKind.Sequential)]
public sealed class tagLOGPALETTE
{
[MarshalAs(UnmanagedType.U2)]
public short palVersion;
[MarshalAs(UnmanagedType.U2)]
public short palNumEntries;
}
}
}

  现在可以通过 Marshal.QueryInterface 将浏览器COM实例的IViewObject接口取出,添加 System.Runtime.InteropServices 命名空间引用,Marshal类位于此命名空间下:

object hret = Marshal.QueryInterface(Marshal.GetIUnknownForObject(pUnknown),
           ref UnsafeNativeMethods.IID_IViewObject, out pViewObject);

  pUnknown为 com对象实例,将IViewObject 指针对象 pViewObject 转化为接口对象.

ViewObject = Marshal.GetTypedObjectForIUnknown(pViewObject, 
          typeof(SnapLibrary.UnsafeNativeMethods.IViewObject)) as SnapLibrary.UnsafeNativeMethods.IViewObject;

  调用draw方法,绘制到图象上,以下是TakeSnapshot方法的完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging; using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security;
using mshtml; namespace SnapUtility
{
/// <summary>
///WebSnapshot 的摘要说明
/// </summary>
public class WebSnapshot
{
public WebSnapshot(){ } public static Bitmap GetHtmlImage(Uri uri, int Width)
{
WebBrowser webBrowser = new WebBrowser();
//webBrowser.Size = new Size(Width, 10);
webBrowser.ScrollBarsEnabled = false;
webBrowser.Url = uri;
while (webBrowser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
} webBrowser.Width = webBrowser.Document.Body.ClientRectangle.Width;
webBrowser.Height = webBrowser.Document.Body.ClientRectangle.Height;
webBrowser.Url = uri;
Bitmap bitmap = TakeSnapshot(webBrowser.ActiveXInstance, new Rectangle(, , webBrowser.Width, webBrowser.Height)); webBrowser.Dispose(); return bitmap; } /// <summary>
/// 取快照
/// </summary>
/// <param name="pUnknown">Com 对象</param>
/// <param name="bmpRect">图象大小</param>
/// <returns></returns>
public static Bitmap TakeSnapshot(object pUnknown, Rectangle bmpRect)
{
if (pUnknown == null)
return null;
//必须为com对象
if (!Marshal.IsComObject(pUnknown))
return null; //IViewObject 接口
UnsafeNativeMethods.IViewObject ViewObject = null;
IntPtr pViewObject = IntPtr.Zero;
//内存图
Bitmap pPicture = new Bitmap(bmpRect.Width, bmpRect.Height);
Graphics hDrawDC = Graphics.FromImage(pPicture);
//获取接口
object hret = Marshal.QueryInterface(Marshal.GetIUnknownForObject(pUnknown),
ref UnsafeNativeMethods.IID_IViewObject, out pViewObject);
try
{
ViewObject = Marshal.GetTypedObjectForIUnknown(pViewObject, typeof(UnsafeNativeMethods.IViewObject)) as UnsafeNativeMethods.IViewObject;
//调用Draw方法
ViewObject.Draw((int)System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT,
-,
IntPtr.Zero,
null,
IntPtr.Zero,
hDrawDC.GetHdc(),
new NativeMethods.COMRECT(bmpRect),
null,
IntPtr.Zero,
);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
//释放
hDrawDC.Dispose();
return pPicture;
}
}
}

  

  到此既完成了对Com对象的图象抓取.那么现在给它提供一个浏览器的实例,让它实现对 web page 的快照。
  .net 2.0提供了webbrowser对象,它是对activex对象的包装,它的使用很简单,这里就不详细说明。
  WebBrowser 对象的实例的属性ActiveXInstance就是它的原生COM对象,获取它的IVewObject接口,即可调用它实现的Draw方法把网页绘制到指定的DC上.

  这里提供一个测试用的代码:

前台页面设置:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" AspCompat="true" %>

后台调用代码:

using System.Drawing;
using System.IO;
using SnapUtility; public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Bitmap MyImage = WebSnapshot.GetHtmlImage(new Uri(@"http://www.hao123.com/"), );
string folder = Server.MapPath("Html/"); //如果目录不存在则创建目录
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder); MyImage.Save(folder + DateTime.Now.Ticks.ToString() + ".jpeg");
MyImage.Dispose();
}

  当然,这样做可能太复杂了,因为.net 为我们简化了所有的工作,简单到任意的 contrl 对象都支持 DrawToBitmap 方法。不过想要了解机制的朋友们,可以研究一下.

Asp.Net 之 网页快照的更多相关文章

  1. ASP.NET 之 网页快照 (DrawToBitmap)

    一.添加引用 在解决方案上单击右键,选择“Add Reference...”,添加“System.Windows.Forms”,添加完后,Web.Config 中应该有类似下面的内容: <sys ...

  2. 基于Asp.net C#实现HTML转图片(网页快照)

    一.实现方法 //WebSiteThumbnail.cs文件,在BS项目中需要添加对System.Windows.Forms的引用 using System; using System.Data; u ...

  3. php 利用第三方软件进行网页快照

    网页快照有很多方法,具体的大家可以百度下.这里我复制一位别人的. 这里我只说下利用第三方软件(Web2Pic_Pro)实现. (1). 下载web2pic_pro软件.下载地址 http://isha ...

  4. ASP.NET Core 之 Identity 入门(一)

    前言 在 ASP.NET Core 中,仍然沿用了 ASP.NET里面的 Identity 组件库,负责对用户的身份进行认证,总体来说的话,没有MVC 5 里面那么复杂,因为在MVC 5里面引入了OW ...

  5. Asp.Net Mvc 使用WebUploader 多图片上传

    来博客园有一个月了,哈哈.在这里学到了很多东西.今天也来试着分享一下学到的东西.希望能和大家做朋友共同进步. 最近由于项目需要上传多张图片,对于我这只菜鸟来说,以前上传图片都是直接拖得控件啊,而且还是 ...

  6. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  7. ASP.NET Core应用的错误处理[3]:ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”

    DeveloperExceptionPageMiddleware中间件利用呈现出来的错误页面实现抛出异常和当前请求的详细信息以辅助开发人员更好地进行纠错诊断工作,而ExceptionHandlerMi ...

  8. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库

    在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...

  9. ASP.NET_各个币种之间的汇率转换(实时)使用Yahoo汇率。

    近期开发支付平台的时候有运用到各国的实时汇率之间的转换问题,于是在往上找了很多相关资料,以下就是一些参考网址: 1.提供API接口的网站:https://www.showapi.com:这个网站有提供 ...

随机推荐

  1. ASP.NET MVC中的Json Binding和Validate

    引子:电子商务网站支付功能页面往往会有很多信息,对于这些信息的保存,往往是分步完成的,那么使用Ajax最合适不过了,比如其中的收货人信息模块.这些信息的新建和编辑保存都是用Ajax来完成的.那么有几种 ...

  2. asp.net MVC 中@Html.Partial,@Html.Action,@Html.RenderPartial,@Html.RenderAction区别

    @Html.Action:需要有对应的Action,并且Action方法有返回值.(注:处理完业务逻辑同时,也需要返回所需值) @{Html.RenderAction}:需要有对应的Action,Ac ...

  3. bzoj 1061 [Noi2008]志愿者招募(数学模型,MCMF)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1061 [题意] 雇人满足每天至少需要的人数. [思路一] Byvoid的题解 clic ...

  4. QTREE系列题解

    打了快一星期的qtree终于打完了- - (其实还有两题改不出来弃疗了QAQ) orz神AK一星期前就虐完QTREE 避免忘记还是简单写下题解吧0 0 QTREE1 题意: 给出一颗带边权树 一个操作 ...

  5. 第二百六十三天 how can I 坚持

    今天解脱了,放下了,小罗娜,不给力,话说下一步该咋办呢. 鱼不想过双十一自杀了.这都二十二号了,好快. 该把给罗娜说的那些话保存下来.可惜已经删了. 不知道做的对不对,反正就是没缘分,就这样吧. 睡觉 ...

  6. 第二百四十九天 how can I 坚持

    竟然让我跟着他们去旅游..泡温泉,滑雪..西北坡,不去白不去. 罗娜,你别把我拉黑啊.哎,不知道咋办. 晚上玩了四局LOL,全输了,伤心. 还有今天抢票没抢到. 该怎么破,12点半正好在吃饭啊. 睡觉 ...

  7. WebService学习之四:关于JAX-WS 注释

    基于 XML 的 Web Service 的 Java API"(JAX-WS)通过使用注释来指定与 Web Service 实现相关联的元数据以及简化 Web Service 的开发.注释 ...

  8. Android实例-读取设备联系人(XE8+小米2)

    相关资料: http://www.colabug.com/thread-1071065-1-1.html 结果: 1.将权限打开Read contacts设置为True,不然报图一的错误. 2.搜索空 ...

  9. HDU 4791 Alice's Print Service (2013长沙现场赛,二分)

    Alice's Print Service Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  10. ASP.NET面试题总结

    1.ASP.NET中的身份验证有那些?你当前项目采用什么方式验证请解释ASP.NET身份验证模式包括Windows.Forms(窗体).Passport(护照)和None(无). 1.Windows身 ...