蛙蛙推荐:蛙蛙牌网页捕捉器
摘要:你有没有看到一篇好文章想保存到本地,有没有想过只保存网页选中的部分而不要那些不必要的导航和广告,本贴告诉你达到这个目的的思路及主要代码。
思路:首先我们要获取到所有IE窗口,无论是哪个IE进程的,这个我们要用引用"Microsoft Internet Controls(SHDocVw)"的com组件,用它的SHDocVw.ShellWindowsClass类来枚举用户打开的所有的IE页面。然后我们要用GetForegroundWindow API来获取前置的窗口,再用GetClassName API来获取前置窗口的Class,如果是“IEFrame”,说明当前窗口是IE,然后枚举所有的IE页面,对比每个IE页面的句柄是否是当前活动窗口的句柄,如果是,那么这个SHDocVw.InternetExplorer就是对应这当前处于活动窗口的IE的对象。为了方便操作HTML模型和IE对象,我们再引入Microsoft.mshtml程序集(这个是.NET程序集,前面那个SHDocVw是个Com互操作程序集,不过应该每台机器都装了IE,所以SHDocVw不需要单独分发)。SHDocVw.InternetExplorer.Document可以转换成mshtml.IHTMLDocument2类型,然后mshtml.IHTMLDocument2.body有innerHTML属性,就是当前网页的HTML文本了。mshtml.IHTMLDocument2.selection.createRange()表示用户在网页上选中的区域,这个做web的应该很熟,该方法返回mshtml.IHTMLTxtRange类型,该类型有htmlText属性,表示用户所选区域的html文本。
这样所有必要的因素都有了,把这些综合在一起,就可以写个工具来快速保存你感兴趣的网页了。
另外本文还演示如下技巧:
1、如何实现无标题窗口,如果拖动无标题窗口,如何让窗口永远处于前置状态;
2、如何解决前置窗口上的按钮要点击两次才能生效的问题,第一次点击是激活窗口,第二次单击按钮才会生效;
3、让窗体初始化在屏幕的右下角;
主要代码如下,不长
using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using mshtml;
using SHDocVw;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
namespace CapIe
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
public partial class Form1 : Form
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
private fields#region private fields
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
窗口相关#region 窗口相关
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[DllImport("user32.dll")]
private static extern int GetClassName(
IntPtr hWnd,
StringBuilder lpString,
int nMaxCount
);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
拖动无标题窗口相关#region 拖动无标题窗口相关
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public const int HTCAPTION = 0x0002;
public const int SC_MOVE = 0xF010;
public const int WM_SYSCOMMAND = 0x0112;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[DllImport("user32.dll")]
public static extern bool ReleaseCapture();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
[DllImport("user32.dll")]
public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private readonly Timer _timer = new Timer();
private IHTMLDocument2 _doc;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Form 相关#region Form 相关
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
public Form1()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
InitializeComponent();
TopMost = true;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private void Form1_Load(object sender, EventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
_timer.Enabled = true;
_timer.Tick += _timer_Tick;
Location = new Point(Screen.PrimaryScreen.WorkingArea.Width - base.Width,
Screen.PrimaryScreen.WorkingArea.Height - Height); //让窗体初始化在屏幕的右下角
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
网页捕捉相关#region 网页捕捉相关
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//监控当前窗口是否为IE
private void _timer_Tick(object sender, EventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
try
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
IntPtr formHandle = GetForegroundWindow();
if (formHandle == Handle) return;
StringBuilder className = new StringBuilder(256);
GetClassName(formHandle, className, className.Capacity);
if (className.ToString() != "IEFrame")
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
toolStripButton1.Enabled = false;
toolStripButton2.Enabled = false;
return;
}
else
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
toolStripButton1.Enabled = true;
toolStripButton2.Enabled = true;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ShellWindows shell = new ShellWindowsClass();
int ihandle = formHandle.ToInt32();
foreach (InternetExplorer ie in shell)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
int iehandle;
try
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
iehandle = ie.HWND;
}
catch
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
continue;
}
if (ihandle != iehandle) continue;
try
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
_doc = ie.Document as IHTMLDocument2;
}
catch
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
continue;
}
}
}
catch (Exception ex)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Trace.TraceError(ex.Message);
Debugger.Break();
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//捕获全部网页
private void toolStripButton1_Click(object sender, EventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (_doc == null) return;
ShowWeb showWeb = new ShowWeb(_doc.body.innerHTML);
showWeb.ShowDialog(this);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//捕获选取的网页
private void toolStripButton2_Click(object sender, EventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
if (_doc == null) return;
IHTMLTxtRange range = _doc.selection.createRange() as IHTMLTxtRange;
if (range == null) return;
ShowWeb showWeb = new ShowWeb(range.htmlText);
showWeb.ShowDialog(this);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
窗体拖动相关#region 窗体拖动相关
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private void panel1_MouseDown(object sender, MouseEventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
ReleaseCapture();
SendMessage(Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private void panel1_MouseHover(object sender, EventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Cursor = Cursors.SizeAll;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private void panel1_MouseLeave(object sender, EventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Cursor = Cursors.Default;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
下拉菜单处理#region 下拉菜单处理
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Application.Exit();
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
#endregion
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
private void toolStrip1_MouseHover(object sender, EventArgs e)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Focus(); //解决按钮要点击两次的bug
}
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
改进:目前只能当IE为活动窗口时,才能捕捉网页,我们可以先获取鼠标位置,然后用WindowFromPoint获取鼠标所在区域的窗口,再获取这个窗口的Class,看是否是“Internet Explorer_Server”,然后下面的步骤和上面的一样,这样的做的好处是一些IE内核的浏览器,比如傲游啦,GreenBrowser等浏览器也能想办法捕捉网页,因为只要是IE内核,显示网页的那部分的的Window的Class都是"Internet Explorer_Server"。找到这个窗口后再调用GetParent获取上层的窗口,再和ShellWindows枚举出来的窗口句柄对比,找到当前打开的网页。
[DllImport("user32")]
private static extern IntPtr WindowFromPoint(
Point Point //坐标
);
[DllImport("User32.dll")]
public static extern IntPtr GetParent(IntPtr hWnd);
int x = Cursor.Position.X;
int y = Cursor.Position.Y;
Point p = new Point(x, y);
IntPtr formHandle = WindowFromPoint(p);
另外,就是像IE7这种的多标签浏览器,获取当前窗口,还要获取当前激活的标签页是哪个,否则捕获的网页可能不对,这就需要再想办法了,留给大家吧,想实现的话具体大家参考相关链接吧。
点击下载示例(不包含Microsoft.mshtml.dll,应该在C:\Program Files\Microsoft.NET\Primary Interop Assemblies目录下) cap_ie.zip
相关链接:
SOS!!!如何获取鼠标再在的窗口的句柄
http://topic.csdn.net/t/20010612/14/156129.html
GetWindowRect,GetClientRect,和ScreenToClient
http://hi.baidu.com/yh121212/blog/item/521172c646b7211b9c163d3c.html
请教out参数的用法
http://topic.csdn.net/t/20050304/12/3824234.html
从C#程序中调用非受管DLLs [择自博客园]
http://blog.csdn.net/ericksky/archive/2006/07/27/988128.aspx
GetCursorPos/WindowFromPoint/SendMessage (用API函数向Edit框发送字符)
http://hi.baidu.com/gamevip/blog/item/cd4ac8119cef2111b8127b35.html
如何连接到 Internet Explorer 的运行实例
http://support.microsoft.com/kb/176792
FileNotFoundException error using SHDocVw.ShellWindows
http://bytes.com/forum/thread656636.html
VB Webbrowser控件使用方法
http://www.zxbc.cn/html/20080216/31664_3.html
从HWnd得到IWebbrowser2接口
http://www.zxboy.com/article.asp?id=100
GetActiveWindow与GetForegroundWindow两者有何区别?
http://www.qqgb.com/Program/VC/VCJQ/Program_166012.html
MSHTML, Dom, and copying objects from a WebBrowser Control
http://lazycoders.blogspot.com/2007/06/mshtml-dom-and-copying-objects-from.html
我想找到当前IE(7)当前的文档对象,已有部分代码,请求大家帮忙!C#_WinFrom
http://topic.csdn.net/u/20070404/20/17979fe9-a223-44dc-aab5-b8edb8fbffd0.html
Internet Explorer Activity Monitor
http://www.codeproject.com/KB/cs/IE_Activity_Monitor.aspx?fid=229256&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=1350993
C#获得IE进程内的IDocument对象代码
http://blog.csdn.net/shiff/archive/2007/12/05/1919000.aspx