C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)

C# .Net 2.0实例学习:WebBrowser页面与WinForm交互技巧 2

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
Study Case 4:高亮显示 

上一个例子中我们学会了查找文本——究跟到底,对Web页面还是只读不写。那么,如果说要把所有的搜索结果高亮显示呢?我们很快会想到把所有匹配的文字颜色、背景改一下就可以了。首先想到的可能是直接修改HTML文本吧……但是,与SourceCode的高亮显示不同,我们需要并且只需要高亮页面中的文本部分。HTML标签、脚本代码等等是绝对不应该去改动的。因此我们不能把整个页面的Source Code读进来然后replace,那样有破坏HTML文件结构的可能;我们只能在能够分离出文本与其他内容(标签,脚本……)的前提下进行。

具体方法有很多,下面提供两个比较简单的方法。
方法一:使用TextRange(IHTMLTxtRange) 
有了上一个Case的基础,相信大家立刻会想到使用TextRange。没错,TextRange除了提供查找方法之外,还提供了一个pasteHTML方法,以指定的HTML文本替换当前TextRange中的内容。代码片断如下:
    public partial class HilightDemo : Form
     {
        // 定义高亮显示效果的标签。
        string tagBefore = "<span style='background-color:yellow;color:black'>";
        string tagAfter = "</span>";

        // ……

        private void btnHilight_Click(object sender, EventArgs e)
         {
             HtmlDocument htmlDoc = webBrowser.Document;
            string keyword = txtKeyword.Text.Trim();
            if (keyword == "")
                return;

            object oTextRange = htmlDoc.Body.InvokeMember("createTextRange");

             mshtml.IHTMLTxtRange txtrange = oTextRange as mshtml.IHTMLTxtRange;

            while (txtrange.findText(keyword, 1, 4))
             {
                try 
                 {
                     txtrange.pasteHTML(tagBefore + keyword + tagAfter);
                 }
                catch { }
                 txtrange.collapse(false);
             }
         }
     }

※这段代码里获取IHTMLTxtRange的方式和上面的例子稍稍不同,其实所谓条条大路通罗马,本质是一样的。

方法二:使用DOM(文档对象模型)
将HTML文档解析为DOM,然后遍历每个节点,在其中搜索关键字并进行相应替换处理即可。
    public partial class HilightDemo : Form
     {
        //……

        private void btnHilight_Click(object sender, EventArgs e)
         {
             HTMLDocument document = (HTMLDocument)webBrowser.Document.DomDocument;
             IHTMLDOMNode bodyNode = (IHTMLDOMNode)webBrowser.Document.Body.DomElement;
            string keyword = txtKeyword.Text.Trim();
            if (keyword == "")
                return;

             HilightText(document, bodyNode, keyword);
         }

        private void HilightText(HTMLDocument document, IHTMLDOMNode node, string keyword)
         {
            // nodeType = 3:text节点
            if (node.nodeType == 3)
             {
                string nodeText = node.nodeValue.ToString();
                // 如果找到了关键字
                if (nodeText.Contains(keyword))
                 {
                     IHTMLDOMNode parentNode = node.parentNode;
                    // 将关键字作为分隔符,将文本分离,并逐个添加到原text节点的父节点
                    string[] result = nodeText.Split(new string[] { keyword }, StringSplitOptions.None);
                    for (int i = 0; i < result.Length - 1; i++)
                     {
                        if (result[i] != "")
                         {
                             IHTMLDOMNode txtNode = document.createTextNode(result[i]);
                             parentNode.insertBefore(txtNode, node);
                         }
                         IHTMLDOMNode orgNode = document.createTextNode(keyword);
                         IHTMLDOMNode hilightedNode = (IHTMLDOMNode)document.createElement("SPAN");
                         IHTMLStyle style = ((IHTMLElement)hilightedNode).style;
                         style.color = "black";
                         style.backgroundColor = "yellow";
                         hilightedNode.appendChild(orgNode);

                         parentNode.insertBefore(hilightedNode, node);
                     }
                    if (result[result.Length - 1] != "")
                     {
                             IHTMLDOMNode postNode = document.createTextNode(result[result.Length - 1]);
                             parentNode.insertBefore(postNode, node);
                     }
                     parentNode.removeChild(node);
                 } // End of nodeText.Contains(keyword)
             }
            else 
             {
                // 如果不是text节点,则递归搜索其子节点
                 IHTMLDOMChildrenCollection childNodes = node.childNodes as IHTMLDOMChildrenCollection;
                foreach (IHTMLDOMNode n in childNodes)
                 {
                     HilightText(document, n, keyword);
                 }
             }
         }
     }
上面的两段代码都是为了清晰易懂而精简得不能再简的,有很多地方很不完善。比如,没考虑到如何从高亮显示状态复原;也没有大小写匹配等等。当然,掌握了原理之后相信这些都不会太难。

这两种方法各有优缺点:
使用TextRange较轻量迅速,而且有一个特长,就是可以把跨标签(Tag)的关键字挑出来。例如,有这么一段HTML:
<b>Hel</b>lo World!
先不管作者出于什么目的让Hel三个字母成为粗体,总之显示在页面上的是一句“Hello World!”。在我们希望高亮页面中的“Hello”这个关键字时,如果用DOM分析的话,会得出含有“Hel”的<b>节点和文本节点“lo World!”两个节点,因此无法将其挑出来。而TextRange则能正确识别,将其设置为高亮。因此也可以说TextRange是只和文本有关,和HTML语法结构无关的对象。

但是,TextRange也有其致命缺点,加亮容易,反向的话就很难。换句话说,去除高亮显示的时候不能再用TextRange,而需要采用其他方法。

而DOM方法则正好相反, 由于DOM的树状结构特性,虽然不能(或者很难)跨越Tag搜索关键字,但是去除高亮显示并不繁琐。

Study Case 5:与脚本的互操作 

在Case 1当中,我们已经看到,Web页面的HTML元素的事件,可以由Windows Form端来响应,可以在某种程度上看作是Web页面调用WinForm;那么反过来,WinForm除了可以直接访问Web页面的HTML元素之外,能否调用Web页面里的各种Script呢?

首先是调用Web页面的脚本中已经定义好的函数。假设HTML中有如下Javascript:
function DoAdd(a, b) {
    return a + b;
}
那么,我们要在WinForm调用它,只需如下代码即可:
object oSum = webBrowser.Document.InvokeScript("DoAdd", new object[] { 1, 2 });
int sum = Convert.ToInt32(oSum);
其次,如果我们想执行一段Web页面中原本没有的脚本,该怎么做呢?这次.Net的类没有提供,看来还要依靠COM了。IHTMLWindow2可以将任意的字符串作为脚本代码来执行。
string scriptline01 = @"function ShowPageInfo() {";
string scriptline02 = @"      var numLinks = document.links.length; ";
string scriptline03 = @"      var numForms = document.forms.length; ";
string scriptline04 = @"      var numImages = document.images.length; ";
string scriptline05 = @"      var numScripts = document.scripts.length; ";
string scriptline06 = @"      alert('网页的统计结果:\r\n链接数:' + numLinks + ";
string scriptline07 = @"         '\r\n表单数:' + numForms + ";
string scriptline08 = @"         '\r\n图像数:' + numImages + ";
string scriptline09 = @"         '\r\n脚本数:' + numScripts);}";
string scriptline10 = @"ShowPageInfo();";

string strScript = scriptline01 + scriptline02 + scriptline03 + scriptline04 + scriptline05 +
                    scriptline06 + scriptline07 + scriptline08 + scriptline09 + scriptline10;

IHTMLWindow2 win = (IHTMLWindow2)webBrowser.Document.Window.DomWindow;
win.execScript(strScript, "Javascript");
OK,今天就写到这里吧,再想起什么来再补充吧。欢迎大家多多指正,欢迎讨论。
View Code

C# WebBrowser制作的HTML文本编辑器

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
C# WebBrowser制作的HTML文本编辑器
· 下载源文件(http: //www.codeproject.com/cs/miscctrl/editor_in_windows_forms/editor2_src.zip) - 42.3 Kb
· 下载演示项目(http: //www.codeproject.com/cs/miscctrl/editor_in_windows_forms/editor2_demo.zip) - 19.7 Kb
· 原文:A Windows Forms based text editor with HTML output
· 类似的控件:HTMLTextBox
 简介
刚才,我在编写一个聊天应用程序,其中一个聊天客户端是基于 web 的并以 ASP.NET 2.0 编写,另一个聊天客户端是 C# 编写的基于 Windows 窗体的 .NET 应用。对于此Windows 窗体客户端,我需要一个可以输出 HTML 的富文本编辑器(a rich text editor) ,以便于 ASP.NET 的客户端可以显示 Windows 窗体客户端的聊天内容。这样,就排除了使用 RTF 文本框的可能。
我设计出的解决方案是在 Windows 窗体客户端,以编辑模式使用一个 WebBrowser 控件。对于 WebBrowser  控件中选定的文本,同时在 WebBrowser 控件的上方放置包含格式按钮的工具栏,以便设置文本格式。
本文说明了这个方案中,使用 WebBrowser 控件建立一个编辑器时的主要难点问题。因为源代码不难理解,我就不深入介绍了。 但是,我会介绍一些必要的实现技巧。
WebBrowser 控件设计模式设置
当使用此组件时,会自动应用设计模式,并为文档建立一个编辑模板。但是,作为参考,下面简单说明这是如何实现的。
应用设计模式需要使用 COM 接口,添加一个 MSHTML 的 "Microsoft HTML Object Library" 的引用,并添加一个对 'MSHTML' 的 'using'。
在把改变写入到 DOM 文档之前,有必要添加一个 body 到控件。要这样做,你可以简单地设置一些文本到 WebBrowser 控件的 DocumentText 属性中。
webBrowser1.DocumentText = "<html><body></body></html>"
下面的代码可以取得新的 DomDocument COM 接口的引用,并设置设计模式为 "On"。
IHTMLDocument2 doc =
webBrowser1.Document.DomDocument as IHTMLDocument2;
doc.designMode = "On";
最后,我把 WebBrowser 控件的上下文菜单替换掉,这样 IE 浏览器的默认上下文菜单就不会显示出来。
webBrowser1.Document.ContextMenuShowing +=
new HtmlElementEventHandler(Document_ContextMenuShowing);
浏览器现在处于设计模式中,使用一个自定义方法来显示指定的上下文菜单。
格式化文本
使用 browser.Document 中的 ExecCommand 方法,你可以把格式和编辑功能应用到设计模式下的浏览器控件。
下面是一些例子:
public void Cut()
{
 webBrowser1.Document.ExecCommand("Cut", false, null);
}
public void Paste()
{
 webBrowser1.Document.ExecCommand("Paste", false, null);
}
public void Copy()
{
 webBrowser1.Document.ExecCommand("Copy", false, null);
}
某些命令用于绑定(显示)当前选区的格式。
public void Bold()
{
 webBrowser1.Document.ExecCommand("Bold", false, null);
}

public void Italic()
{
 webBrowser1.Document.ExecCommand("Italic", false, null);
}
同步刷新选定文本的格式按钮
下面介绍一些比发出格式化命令到浏览器更有用的技巧。每 200 毫秒,我逐一查询浏览器编辑选区的状态,并据此设置工具栏格式按钮的状态。
private void timer_Tick(object sender, EventArgs e)
{
 SetupKeyListener();
 boldButton.Checked = IsBold();
 italicButton.Checked = IsItalic();
 underlineButton.Checked = IsUnderline();
 orderedListButton.Checked = IsOrderedList();
 unorderedListButton.Checked = IsUnorderedList();
 linkButton.Enabled = SelectionType == SelectionType.Text;

 UpdateFontComboBox();
 UpdateFontSizeComboBox();
 if (Tick != null) Tick();
}
你可能已经注意到这儿使用了一个 Tick 计时器事件。外部的组件可以订阅此事件来更新 GUI 的状态。举例来说,它们将基于编辑器控件的状态,刷新“剪切/复制/粘贴/撤销/重复”(操作)的 Enabled 状态。
我通过使用从 WebBrowser 控件返回的 COM 文档接口,来完成此任务,先使用:
IHTMLDocument2 doc = webBrowser1.Document.DomDocument as IHTMLDocument2;
然后,使用 queryCommandState  方法来确定当前选区的状态:
public bool IsBold()
{
 return doc.queryCommandState("Bold");
}

public bool IsItalic()
{
 return doc.queryCommandState("Italic");
}

public bool IsUnderline()
{
 return doc.queryCommandState("Underline");
}
连接按钮和字体控件以一种简单的方式管理,但我将会保留以代码检测的方法。
取得焦点
让控件取得焦点不一定是简单的。 WebBrowser 控件本身不接受焦点。 WebBrowser 控件的文档也不接受焦点。但是,body 会取得焦点,可以假定有一个 body 元素在控件中。
private void SuperFocus()
{
 if (webBrowser1.Document != null &&
 webBrowser1.Document.Body != null)
 webBrowser1.Document.Body.Focus();
}
当然,你决不需要直接调用此方法。在控件上调用 Focus 方法,会把焦点放置到包含了 WebBrowser 控件的编辑器控件上。当接收到 GotFocus  事件时,编辑器控件会自动把焦点转到 WebBrowser 控件文档的 body 上。
取得文本或 HTML
分别使用 BodyHtml 和 BodyText 方法,可以返回 HTML 和文本。
连接到组件程序集
在 Visual Studio 2005 中,你可以连接到一个程序集 (添加一个引用),即使程序集是可执行的(文件)。此编辑器是作为内嵌在窗体的组件来编写的,因此你可以把这个组件添加到控件面板上,并把它拖放到你的应用程序中。此控件的名称为 Editor,在命名空间 Design 中。
结束语
.NET 2.0 中的 WebBrowser 控件可以作为一个有效的文本编辑器来使用。当你需要一个 HTML 编辑器控件时,它很有用。但是在某些范围内,不能完全直接地使用 WebBrowser 控件来实现。本文试图展示一些让它工作的必要技巧。
View Code

C# webBrowser js 交互 调用

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
前面我也有转载过相关文章,当时没有测试,今天测试 ,结果不能用,以前都没注意。
今天整理了一下 。代码如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Security.Permissions;

namespace test10
{
 [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
 [System.Runtime.InteropServices.ComVisibleAttribute(true)]
 public partial class MainForm : Form
 {
  
  public MainForm()
  {
   InitializeComponent();
   webBrowser1.ObjectForScripting = this;
  }
  
  void MainFormLoad(object sender, EventArgs e)
  {
   string s="";
   s+="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">";
   s+="<HTML>";
   s+=" <HEAD>";
   s+="  <TITLE> New Document </TITLE>";
   s+="  <META NAME=\"Generator\" CONTENT=\"EditPlus\">";
   s+="  <META NAME=\"Author\" CONTENT=\"\">";
   s+="  <META NAME=\"Keywords\" CONTENT=\"\">";
   s+="  <META NAME=\"Description\" CONTENT=\"\">";
   s+="  <script>";
   s+=" function ShopXG(inf)";
   s+=" {";
   s+="  alert(inf);";
   s+=" }";
   s+=" var as = 'as';";
   s+="  </script>";
   s+="";
   s+="";
   s+=" </HEAD>";
   s+="";
   s+=" <BODY>";
   s+="  <input type=\"button\" value=\"调用 js 方法\" onClick=\"ShopXG('123123123')\" />";
   s+="  <input type=\"button\" value=\"调用 C# 方法\" onclick=\"window.external.te('我调用到了 C# 方法');\"/>";//调用 C# 的te 方法
   s+="  <input id=\"btnId\" type=\"button\" value=\"C#添加事件\"/>";
   s+=" </BODY>";
   s+="</HTML>";
   webBrowser1.DocumentText =s;
  }
  
  void Button1Click(object sender, EventArgs e)
  {
   HtmlElement el = webBrowser1.Document.GetElementById("btnId");
   el.Click+= new HtmlElementEventHandler(BtnClick);//为 web 按钮添加事件
  }
  
  void Button2Click(object sender, EventArgs e)
  {
   webBrowser1.Document.InvokeScript("ShopXG", new string[] {"我调用到了 js 方法"});//调用 web ShopXG方法
  }

  void BtnClick(object sender, EventArgs e){
   MessageBox.Show("C# 添加事件到 js");
  }
  
  public void te(string s)
  {
   MessageBox.Show(s);
  }
 }
}
View Code

C#通过webbrowser控件与javascript交互

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
C#通过webbrowser控件与javascript交互
1.C#里调用控件里面网页的js函数
// 调用JavaScript的messageBox方法,并传入参数
object[] objects = new object[1];
objects[0] = “C#访问JavaScript脚本”;
this.webBrowser1.Document.InvokeScript(“messageBox”, objects);
//object就是传入的参数,而messageBox则是网页中预定义好的js函数。
通过这种方式C#里面就可以执行Javascript函数,可以把上面的代码放到一个button的click事件里面。
2.C#windows窗体应用webbrowser控件里网页js调用C#窗体的函数
首先需要在代码里面加上
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public partial class Form1 : Form
{
…..//
}
这样使得C#的com对象是对网页里的javascript可见的。
然后在嵌入网页里面通过“window.external.MyMessageBox(‘javascript访问C#代码’)” ,即通过window.external捕获调用c#定义好的函数。
具体Form.cs代码如下(通过vs2008创建的c#window窗体应用,拖拽上一个webbrowser控件和button控件。):
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
System.IO.FileInfo file = new System.IO.FileInfo(“test.html”);
// WebBrowser控件显示的网页路径
this.webBrowser1.Url = new Uri(file.FullName);
// 将当前类设置为可由脚本访问
this.webBrowser1.ObjectForScripting =this;
}
private void button1_Click(object sender, EventArgs e)
{
}
// 提供给JavaScript调用的方法
public void MyMessageBox(string message)
{
MessageBox.Show(message);
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
}
private void button1_Click_1(object sender, EventArgs e)
{
// 调用JavaScript的messageBox方法,并传入参数
object[] objects = new object[1];
objects[0] = “C#访问JavaScript脚本”;
this.webBrowser1.Document.InvokeScript(“messageBox”, objects);
}
}
test.html内容比较简单:
<html>
<head>
<meta http-equiv=”Content-Language” content=”zh-cn”>
<script language=”javascript” type=”text/javascript”>
<!– 提供给C#程序调用的方法 –>
function messageBox(message)
{
alert(message);
}
</script>
</head>
<body>
<!– 调用C#方法 –>
<button onclick=”window.external.MyMessageBox(‘javascript访问C#代码’)” >
javascript访问C#代码</button>
</body>
</html>
配置运行成功的话,可以看到相互调用的效果,希望对需要的童鞋有用!
补充一个js调用C#函数的方法:
1,设置脚本对象:

wb.ObjectForScripting = this; // wb为Webbrowser对象
2,公开方法
public void Alert()
{
MessageBox.Show("dkkfdkf");
}
3,然后页面上用javascript可以调用这个方法
external.Alert();
 看了高人的博客,再补充几个,哈:
Winform WebBrowser控件对访问页面执行、改写、添加Javascript代码
 
大家有兴趣可以加我QQ群交流:14792063 广州软件开发团队使用Winform WebBrowser控件对访问页面执行、改写、添加Javascript代码,可以解决许多问题,实现你想要的效果。可以通过引用Microsoft.mshtml,实现对Javascript的操作,代码如下:代码mshtml.IHTMLDocument2 doc = webBrowser1.Document.DomDocument as mshtml.IHTMLDocument2;mshtml.IHTMLWindow2 win = doc.parentWindow as mshtml.IHTMLWindow2;win.execScript(@"alert('hello webbrowser')", "javascript"); 其实还有一种更好的、无需引用Microsoft.mshtml的实现方式:代码HtmlElement ele = webBrowser1.Document.CreateElement("script");ele.SetAttribute("type", "text/javascript");ele.SetAttribute("text", "alert('hello webbrowser')");webBrowser1.Document.Body.AppendChild(ele); 这种使用.Net框架本身所提供的对象,相比引用框架外的COM,好处是显而易见的,这将更方便于安装部署至客户机上。 执行上述两段代码的效果是一样的,都将弹出网页对话框“hello webbrowser”。如果仅是执行Javascript方法,那么,有更简单的且可获得方法返回值的方式,首先假如页面上有如下Javascript方法:function sayHello(to) { alert('hello ' + to); return 'hi, i am javascript';} 在Winform中执行以下代码,首先会弹出网页对话框“hello webbrowser”,然后是Winform的MessageBox对话框“hi, i am javascript” MessageBox.Show(webBrowser1.Document.InvokeScript("sayHello",new object[]{"webbrowser"}).ToString());Winform WebBrowser控件是一个好东西,它不但可以导航网页,还可以使用它获取一些在客户端浏览器HTML源代码中无法获取的数据。如使用了AJAX获取数据的页面,通过客户端浏览器查看源代码的方式,将无法获取到这部分的数据;又如使用了Javascript对内容进行加密以防止采集的页面,即使让你获得HTML源代码,也难以解密得到你想要的结果。但WebBrowser使得这一切变得简单!有兴趣的朋友欢迎继续阅读本博的另一篇文章《》,讲述如何通过WebBrowser访问加密页面,改写其中的Javascirpt方法获取加密的结果。
View Code

Web Browser Express 概述

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
Web Browser Express 概述
Visual Studio 2005
8(共 8)对本文的评价是有帮助 - 评价此主题
发布日期 : 8/26/2004 | 更新日期 : 8/26/2004
John Kennedy
Microsoft Corporation
摘要:建立您自己的、支持选项卡的 Web 浏览器,以及连接到搜索引擎的集成链接。
下载 WebBrowserExpress.msi 示例文件。
本页内容

 简介 

 利用他人成果的好处 

 设计 Web 浏览器 

 工作原理 

 有意思的几点 

 扩展建议 

 小结 
简介
Web 浏览器的一个功能是在同一浏览器窗口内打开不同选项卡或子页,这个功能正在变得更加普及。当浏览多个站点时,使用选项卡来分开多个页会保持桌面的整齐。有若干种第三方 Web 浏览器在 Windows 和其他平台上提供这一功能,如果您跟我一样,您将发现这是一种让人上瘾的浏览方法。很多浏览器,无论是默认设置还是通过插件,也提供一种快速方法,无须直接使用搜索引擎就可以执行 Web 搜索。能够编写自己的浏览器,并使其能够完成所有这些工作,还能把它微调并调整到完全适合您的需要,那不是很棒吗?

图 1:用 Visual C# Express 设计并实现自己的 Web 浏览器
将这些对功能的渴望变为一种全新的产品看起来好像需要大量的工作。毕竟,开发 Internet Explorer 用了多少时间?(答:很长时间。)我如何能够只用一晚上的时间,单枪匹马,就能复制出 Internet Explorer 的强大 HTML 呈现功能并添加我自己的新功能列表?那是因为我使用 Visual C# Express。

 返回页首 
利用他人成果的好处
在一个晚上编写 Web 浏览器的秘密在于使用其他人的成果。在本例中,秘密是使用了 C# Express WebBrowser 控件。如果您安装了 C# Express 并且打开了帮助,您可能已经看到了一个叫做¡°如何:用 C# Express创建 Windows 应用程序¡±的主题。这一简短的项目将指导您完成创建 Windows 窗体应用程序所涉及的各个步骤。如果您还没有看完,而且您对 C# 不熟悉,我建议您阅读它。
关键之处是,通过使用与 C# Express 配套的控件,创建多个应用程序(包括完整的 Web 浏览器)都是很容易的。一旦 WebBrowser 控件确实已在 Windows 窗体上了,您只需告诉它哪些 URL 是要获取并显示的,以及是否需要返回、向前、刷新或停止。连接到 Internet、获取数据、格式化 HTML、显示图形等所有困难的工作都由该控件处理。
这个项目与帮助项目相近,除了一点,该项目创建多个 WebBrowser 控件并将其添加到 TabControl 中的网页上,而不是只添加一个WebBrowser 控件到 Windows 窗体上。是的,我甚至无须编写代码来创建 TabControl。这是从工具箱到 Windows 窗体拖放的另一个示例。
那么,虽然我知道这看似一个巨大而复杂的应用程序,仿佛需要数月的工作来完成,但事实上我只是连结了现有控件间的点,就在一个晚上完成了所有工作。这就是我的编程方式!

 返回页首 
设计 Web 浏览器

图 2:从工具箱拖动控件是编写这一应用程序的关键
以下描述了我如何着手创建 Web Browser Express 项目。在从 C# Express 新项目对话框创建一个Windows 应用程序之后,我将下列控件拖到 Windows 窗体:
TabControl:这个控件存储所有子页,每个子页能控制一个 WebBrowser 控件。一旦它已经创建,向其添加其他页就会很容易。为了确定它填充了整个 Windows 窗体,Dock 属性被设定为 Fill。这使得该控件保持与 Windows 窗体同样大小,即便是调整大小之后。
MenuStrip:尽管这个应用程序中没有菜单,还是存在 MenuStrip 来提供一个屏幕顶端的区域,按钮和文本框可以添加到这个区域。另外,如果您决定添加一些菜单选项,您可以在这里添加。我将 MenuStrip 拖出以使其变得稍大。
Buttons:需要有一些用于 Web 浏览的简单控件。按钮被拖动到 MenuStrip 中,并调整大小,有一个图像应用于这些按钮。我惟一需要做的一件事就是重新绘制图像背景,使其为浅蓝色,以便看起来像 MenuStrip。
Textboxes 和 ComboBoxes :除了按钮,我还需要一个用于 URL 和搜索字符串的文本框。实际上,URL 是一个 ComboBoxes,允许用户输入一个 Web 地址,并从一个下拉列表中选择项目。这个列表是在设计器中填充的,但如果您希望的话可以以编程方式添加新项。
PictureBox:最右边的 PictureBox 控件是为了装饰用的。Web 浏览器在下载内容时会显示一些动画。
timer:timer 对象用于一秒钟数次发出一个消息。这个消息被一个叫做 timer1_tick() 的方法捕获,并用于更改在 PictureBox 中显示的图像。结果是动画。这并不算是第一流的解决方案,但是它奏效。

 返回页首 
工作原理
当该程序启动后,它所做的第一件事是调用 Create_a_new_tab()。此方法创建一个新选项卡页,将其添加到 TabControl,然后在其上创建一个 WebBrowser 控件。WebBrowser URL 被设定为“主页”,无论它在您的系统上可能是什么。下面是创建新选项卡的代码:
// Create a new Tab Page
TabPage newpage = new TabPage("Loading...");
tabControl1.TabPages.Add(newpage);
 
这是创建新 WebBrowser 控件的代码:
// Create a new WebBrowser control.
WebBrowser webpage = new WebBrowser();       
webpage.Parent = newpage;
webpage.Dock = DockStyle.Fill;
webpage.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webpage_DocumentCompleted);
webpage.GoHome();                              
            
 
此代码确定 WebBrowser 的父级是 Tab 页。它还用设置为 Fill 的 Dock 来确定它也保持在窗口的实际大小。我们还添加了一个事件处理程序:控件通过将消息发送到您的程序来工作。您可以选择您所聆听的消息,以及通过将事件处理程序链接到消息所调用的方法。在本例中,该消息告诉我们 WebControl 已经完成了站点的加载和显示,当完成任务时,它将调用名为 webpage_DocumentComplete() 的方法。这允许我们定义当网页加载完毕时执行的代码。例如,停止动画。
Create_a_new_tab() 方法中的最后一行启用计时器:
timer1.Enabled = true;      
 
计时器轻松地将小段消息发送到 timer1_tick(),它改变在 PictureBox 控件中显示的图像,如下所示:
private void timer1_Tick(object sender, EventArgs e)
        {
            // This method is called by the timer, and we use it to update the
            // image displayed by the PictureBox control to create a simple
            // animation.
 
            image_animation++;
            if (image_animation > 10) image_animation = 0;
 
            switch (image_animation)
            {
                case 0: pictureBox_busy.Image = wbe.Properties.Resources.anim0; break;
                case 1: pictureBox_busy.Image = wbe.Properties.Resources.anim1; break;
                case 2: pictureBox_busy.Image = wbe.Properties.Resources.anim2; break;
...
                case 7: pictureBox_busy.Image = wbe.Properties.Resources.anim7; break;
                case 8: pictureBox_busy.Image = wbe.Properties.Resources.anim8; break;
                case 9: pictureBox_busy.Image = wbe.Properties.Resources.anim9; break;
            }
        }
 
您可以看到,计时器每次激发时,在 PictureBox 中就会显示一个不同的图像。使用您将一个图像分配到按钮或 PictureBox 控件时显示的对话框,从磁盘加载图像。
程序的其余部分由事件驱动 — 当用户单击按钮或者输入一个 Web 地址或搜索字符串时调用特定方法。
例如,Web 导航按钮都调用当前 WebBrowser 控件。例如,如果您单击 Back 按钮,会调用以下方法:
private void button_back_Click(object sender, EventArgs e)
        {
            // Go Back - if the web control can go back, do it.
            WebBrowser thiswebpage = GetCurrentWebBrowser();
            if (thiswebpage.CanGoBack)
                thiswebpage.GoBack();
        }
 
当在 Address 组合框中输入一个 URL 时,我们使用 Web 控件的 navigate 方法来获取并显示该页。下面的代码使用了当前显示在组合框中的文本并将其传递到 navigate 方法:
WebBrowser thiswebpage = GetCurrentWebBrowser();                
thiswebpage.Navigate(comboBoxurl.Text);
timer1.Enabled = true;  
 

 返回页首 
有意思的几点
在编写这个项目时,我想到了几个小窍门。不过,可能它们实际上并不能说是窍门,而是一些技术,当您编写自己的代码时可能发现它们是有用的。
使文本和组合框响应 Return 键。
Address ComboBoxes 和 Search TextBox 允许用户输入文本,然后在单击 Go 按钮时使用这个文本。使用 Text 属性从控件提取文本是很容易的。不过,如果按键盘上的“return”键就可以执行与单击一个按钮同样的操作,这样也很好。我通过从两个文本框检查 KeyUp 消息来使其奏效。当 KeyUp 消息到达时,我检查它是否是 Return 键。如果它是,就触发了与单击按钮相同的操作。
ComboBox 而非TextBox
Web Browser Express 的第一个版本将一个 TextBox用于地址 URL 和 Search 框。这很奏效,但是在实践中每次都要手工输入 URL 十分麻烦。我删除了 ComboBox 并添加了一个 TextBox,用一些 URL 填充这一组合框来使用户开始。您可以从 ComboBox 属性资源管理器添加您自己的 URL。
集成搜索
所有流行的 Web 浏览器都有一个可以输入搜索词汇的文本框,结果会返回到 Web 页中,而不需要首先浏览到搜索引擎。由于 MSN 搜索目前有了更新,这看起来是将此功能内置到我自己的 Web 浏览器中的最佳理由。
这非常简单。只需查看 Internet Explorer 中 MSN 搜索上的历史记录,看一下搜索字符串需要使用的格式。然后 Search 方法将搜索文本追加到 URL 并定位到该链接,结果作为一个标准 Web 页返回。
动画
从图形化 Web 浏览器的早期以来,从 Web 请求内容就是有迹可寻的,这样用户就不会以为它们的计算机出了问题,或者以为所有东西都被锁定了。总的来说,让用户知道有些事在发生并且他们需要有耐心总是个好主意。
这是要实现的项目中我最喜欢的部分之一,如果您在艺术上有几分天赋,那么在创建能够想象到的最酷的徽标时,您可以得到不少乐趣。在本例中,我在一个动画程序中创建了一系列大约 12 个帧,并将其作为 BMP 图像导出,加载到 C# Express 中。

图 3:添加图形十分简单。为一个按钮或 PictureBox 选择图像属性,您可以直接从磁盘导入图像。在开始前确定图像的大小正确。

 返回页首 
扩展建议
如果您已经尝试过了 Web Browser Express,并且希望添加自己的功能,那么我这篇文章就做得不错。为了让您保持忙碌,下面还有几个主意,让您可以相对较快地取得进步。
历史记录:保留所有曾访问过的 Web 站点的记录,这样再访问它们时会比较容易。
自动完成:检查 Return 键的方法也能够检查以前输入过的 URL,并自动将其完成。与 Internet Explorer 相比,您可以更改这一自动完成的方式,比如可以只有在按 Tab 键时才自动完成。
收藏:ComboBox 由 6 个 Web 站点填充,您可以从 Properties 资源管理器很容易地更改这些站点。然而,将一个新按钮添加到MenuStrip 取得当前正在显示的 Web 站点并将其添加到 ComboBox 列表怎么样呢?用这种方法用户可以构建起其收藏站点的列表。当程序退出并重新启动时,您需要一些方法来保存并重新加载这个列表。
集成的 RSS 阅读器:保持比竞争对手领先一步,尽量将 RSS 阅读器内置到您的 Web 浏览器中。

 返回页首 
小结
用 C# Express 创建应用程序的秘密在于:知道哪些控件是可用的,以及用这些控件可以做什么。在本例中,只用了几个控件就构造了一个全功能的 Web 浏览器。祝您自己编程时好运。
John Kennedy 是 C# 用户教育团队的程序员/作者。您可以通过阅读他的网络日记,在联机帮助编写中了解他的成就,网络日记网址为:http://blogs.msdn.com/johnkenn
转到原英文页面

 返回页首
View Code

WebBrowser控件的高级用法,c#和Javascript交互及光标位置恢复

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
蛙蛙推荐:WebBrowser控件的高级用法,c#和Javascript交互及光标位置恢复
摘要:在做Winform应用的时候,有些效果不太好做,不像网页,用CSS和HTML能做出灰常漂亮的界面来,其实用WebBrowser可以让你的程序拥有两者的优势。这里介绍一个winform内嵌WebBrowser做的一个RSS浏览器及内嵌在Winform里的html编辑器的光标恢复问题。
  不知道大家有没有用过FeedDemon,它是一个不错的RSS订阅工具,左边的导航树是Winform的,右边的主区域是用WebBrowser来呈现的,而且在主区域点击某条RSS条目后左边的树节点相应的未读数目就会变化,点击左边的树选择“设置所有项目未已读”,右边主区域的RSS列表就会变为已读图标,这是一个典型的Winform和WebBrowser相结合的例子,既发挥了Winform能利用本地CPU计算能力,响应快的特点,又发挥了HTML编程容易,界面华丽的优势,要用winform写一个右边主区域效果的控件,估计得费不少力。
  我们先来看下这个RSS阅读器的核心功能,首先是利用http请求去获取rss内容,RSS是XML格式的,显示的话,就可以用XSLT来显示,这样可以做到内容和显示相分离,显示部分用WebBrowser来显示,然后呢WebBrowser里的javascript要可以调用Winform方法,Winform也要能调用Webbrowser控件里的javascript方法。
 RSS的XML格式大家都很熟悉了,随便找一段示例如下
 


<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:slash="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
  <channel>
    <title>老农专注数据库编程</title>
    <link>http://www.5do8.com/</link>
    <description>老农如是想如是为</description>
    <copyright>copyright by 5do8</copyright>
    <item read="true">
      <title>我军步兵营所属炮连的98式120火箭筒

..</title>
      <description>我军步兵营所属炮连的98式120火箭筒

..</description>
      <link>/tableforum/App/view.php?bbsid=4&subid=1&fid=65544&tbid=8075</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:03:01 GMT
      </pubDate>
    </item>

    <item read="true">
      <title>温今早看望广州火车站80万滞留旅客:&quot;大..</title>
      <description>温今早看望广州火车站80万滞留旅客:&quot;大..</description>
      <link>/tableforum/App/view.php?bbsid=4&subid=2&fid=65638&tbid=2819</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:03:01 GMT
      </pubDate>
    </item>

    <item read="true">
      <title>温今早看望广州火车站80万滞留旅客:&quot;大..</title>
      <description>温今早看望广州火车站80万滞留旅客:&quot;大..</description>
      <link>/tableforum/App/view.php?bbsid=4&subid=3&fid=65639&tbid=6065</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:03:01 GMT
      </pubDate>
    </item>

    <item>
      <title>07最惹火十部国产片</title>
      <description>07最惹火十部国产片</description>
      <link>http://sh.sohu.com/7/1103/22/column216152269.shtml</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:02:55 GMT
      </pubDate>
    </item>

    <item>
      <title>赚大钱取之有道火爆</title>
      <description>赚大钱取之有道火爆</description>
      <link>http://doc.go.sohu.com/200712/df66a3feef3110edd839666dcb3fc1de.php?url=http://vip.78.cn/zs/gbook_admin/getgo.php?id=452</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:02:55 GMT
      </pubDate>
    </item>

    <item>
      <title>火!等一分钟</title>
      <description>火!等一分钟</description>
      <link>http://61.135.132.134/goto.php?aid=27&amp;pid=1153</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:02:55 GMT
      </pubDate>
    </item>

    <item>
      <title>火车票预售期</title>
      <description>火车票预售期</description>
      <link>http://news.sogou.com/news?query=火车票预售??pid=01003102&p=01010302</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:02:55 GMT
      </pubDate>
    </item>

    <item>
      <title>春运火车票</title>
      <description>春运火车票</description>
      <link>http://news.sogou.com/news?query=春运火车票&pid=01003102&p=01010302</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:02:55 GMT
      </pubDate>
    </item>

    <item>
      <title>轻松购买火车票!</title>
      <description>轻松购买火车票!</description>
      <link>http://61.135.132.134/goto.php?aid=26&amp;pid=1175</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:02:55 GMT
      </pubDate>
    </item>

    <item>
      <title>one-mall·火热招商</title>
      <description>one-mall·火热招商</description>
      <link>http://shop.focus.cn/shopview/450228.html</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:02:55 GMT
      </pubDate>
    </item>

    <item>
      <title>六佰本火热招商进行中</title>
      <description>六佰本火热招商进行中</description>
      <link>http://shop.focus.cn/shopview/450319.html</link>
      <author></author>
      <pubDate>
        Wed, 30 Jan 2008 22:02:55 GMT
      </pubDate>
    </item>

  </channel>
</rss>

  我们还要再写个RSS来呈现这个RSS,就以列表的方式呈现就行了,然后我们设置简单的CSS,让已读的RSS条目显示为蓝色,未读的默认显示为黑色,然后点击每个条目的时候要把颜色改为已读的颜色,并且同时Winform。从上面的RSS定义可以看到我把前三个item元素加了一个read="true"的属性(为了演示目的我手工加的),我们用xslt的if语句来读取这个属性来动态设置RSS条目的样式。最后xslt还要定义一个让winform调用的javascript方法以供后面的演示。最终的XSLT如下,不太熟悉XSLT语法的可以参考我以前贴过的帖子。


<?xml version="1.0" encoding="utf-8" ?>

<xsl:stylesheet

     version="1.0"

     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="html" />

  <xsl:template match="rss/channel">

    <html>

      <head>

        <title>

          <xsl:value-of select="title" />

        </title>

        <SCRIPT LANGUAGE="JavaScript">

          function invokeWin(obj)

          {

          obj.childNodes[0].style.color='blue';

          window.external.winFunction(obj.childNodes[0].href);

          }

          function scriptFunc(str)

          {

          alert(str);

          }

        </SCRIPT>

        <style media="all" lang="en" type="text/css">

          body

          {

          background-color:#ccc;

          }

          .ChannelTitle

          {

          font-family:  Verdana;

          font-size:  11pt;

          font-weight:  bold;

          width:  500px;

          text-align:  center;

          }

          .PostDate

          {

          font-family:  Verdana;

          font-size:  7pt;

          padding-left:  15px;

          }

          A,A:visited

          {

          text-decoration:  none;

          color: #000

          }

          A:link

          {

          text-decoration:  none;

          }

          A:hover

          {

          text-decoration:  underline;

          }

        </style>

      </head>

      <body>

        <xsl:apply-templates select="title" />

        <ol>

          <xsl:apply-templates select="item" />

        </ol>

        <div align="center">© 2008WawaSoft 2008</div>

      </body>

    </html>

  </xsl:template>

  <xsl:template match="title">

    <div class="ChannelTitle">

      <xsl:value-of select="text()" />

    </div>

    <br />

  </xsl:template>

  <xsl:template match="item">

    <li>

      <span onclick="invokeWin(this)">

        <a TARGET="_blank" href="{link}">

          <xsl:if test="@read='true'">

            <xsl:attribute name="style">color:blue;</xsl:attribute>

          </xsl:if>

          <xsl:value-of select="title" />

        </a>

      </span>

      <span class="PostDate">

        <xsl:value-of select="pubDate" />

      </span>

    </li>

  </xsl:template>

</xsl:stylesheet>


程序里面呢,我们得让WebBrowser来显示这个RSS,代码如下
 

private void FWBTest_Load(object sender, EventArgs e)
{
    wb1.AllowWebBrowserDrop = false;
    //wb1.IsWebBrowserContextMenuEnabled = false;
    wb1.WebBrowserShortcutsEnabled = false;
    wb1.ObjectForScripting = this;
    wb1.ScriptErrorsSuppressed = true;

    try
    {
        XslCompiledTransform xslt = new XslCompiledTransform();
        xslt.Load("rss.xslt");
        string HTMLoutput;
        using (StringWriter writer = new StringWriter())
        {
            xslt.Transform("rss.xml", null, writer);
            HTMLoutput = writer.ToString();
        }
        wb1.DocumentText = HTMLoutput;
    }
    catch (XsltException xsle)
    {
        Console.WriteLine("样式表中有错。");
    }
    catch (XmlException xmle)
    {
        Console.WriteLine("加载样式表时出现分析错误。");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
}

 
都是WebBrowser和.net的Xml对象的基本用法。
和javascript交互也很简单,以下分别是让javascript调用的方法和用c#调用javascript方法的代码。

public void winFunction(string str)
{
    toolStripStatusLabel1.Text = string.Format("脚本执行方法:{0}", str);
}

private void toolStripButton1_Click(object sender, EventArgs e)
{
    wb1.Document.InvokeScript("scriptFunc",
    new String[] { "这是winform调用脚本方法" });

}


关键点就是javascript代码的下面这句
window.external.winFunction(obj.childNodes[0].href);
以及c#代码下面这句
wb1.Document.InvokeScript("scriptFunc",new String[] { "这是winform调用脚本方法" });
RSS这部分演示完毕了。
winform下的富文本编辑器控件不太多,一般有两种途径,一种是扩展RichTextBox,要去研究rtf格式,mime协议等,一种是用WebBrowser控件,并把designMode设置为on,然后就是和网页的html编辑器一样,调用一些ExecCommand方法来编辑格式等,这里介绍后者,因为后者实现简单,而且html格式可以直接按原格式贴到互联网上,通用性比较好,这里不具体说一些编辑命令如何实现,这些可以参考文后的参考链接,这里只讨论如何让你的HTML文档关闭后再加载恢复上次编辑的光标位置的功能。
这里需要用一些mshtml对象,所以要在项目里引用Microsoft.mshtml,引用位置默认应该是C:\Program Files\Microsoft.NET\Primary Interop Assemblies\Microsoft.mshtml.dll,我不知道这个组件是不是新安装的windows xp,2003都有,如果没有的话可以把这个dll放到你项目的bin目录下一起发布。
大致原理是这样的,在关闭当前编辑文档的时候获取当前光标的位置,也就是当前选择的元素(虽然doc.selection有可能是个图片,而不是TextRange,但我们只考虑textRange的情况,大家可以写代码过滤掉其它情况,如果当前编辑点不是文本类型,就不考虑恢复光标位置了,呵呵。)。然后给当前选择元素后面插入一个小的span元素,作为一个标识符,最后再把文档的Body的InnerHTML保存到数据库里。下次从数据库里读取保存的html文本,先设置到当前WebBrowser的Body的innerHTML属性,然后通过getElementById方法找上次插入的标识符span,找到这个span就相当于找到了上次的光标位置,最后用body元素createTextRange后调用其moveToElementText方法把光标编辑位置移动到找到的位置。
相应代码如下
 


private void NewDoc()

{

    wb1.Navigate("about:blank");

    IHTMLDocument2 doc = wb1.Document.DomDocument as IHTMLDocument2;

    doc.designMode = "On";

}



private void SaveDoc()

{

    if (wb1.Document != null)

    {

        IHTMLDocument2 doc = wb1.Document.DomDocument as IHTMLDocument2;

        HTMLDocumentClass documentClass = wb1.Document.DomDocument as HTMLDocumentClass;

        IHTMLDOMNode caret_pos = (IHTMLDOMNode)documentClass.getElementById("caret_pos");

        if (caret_pos != null) caret_pos.removeNode(true);

        IHTMLTxtRange range = doc.selection.createRange() as IHTMLTxtRange;

        range.pasteHTML(caretHtml);

        range.collapse(true);

        _text = doc.body.innerHTML;

        doc.body.innerHTML = "";

    }

}



private void LoadDoc()

{

    if (!string.IsNullOrEmpty(_text))

    {

        IHTMLDocument2 doc = wb1.Document.DomDocument as IHTMLDocument2;

        doc.body.innerHTML = _text;

        IHTMLBodyElement bodyElement = doc.body as IHTMLBodyElement;

        if (bodyElement != null)

        {

            IHTMLTxtRange range = bodyElement.createTextRange();

            HTMLDocumentClass documentClass = wb1.Document.DomDocument as HTMLDocumentClass;

            IHTMLElement caret_pos = documentClass.getElementById("caret_pos");

            if (caret_pos != null)

            {

                range.moveToElementText(caret_pos);

                range.select();

            }

        }

        _text = "";

    }

}




注:代码写的不严谨,只用于演示目的,请勿用于生产环境。

关于Winform html编辑器的参考链接
http://windowsclient.net/articles/htmleditor.aspx
http://www.codeproject.com/cs/miscctrl/editor_in_windows_forms.asp
http://www.codeproject.com/KB/IP/WYSIWYG_netHTML2.aspx
关于恢复光标位置的参考链接
设置光标位置的问题:SetDocumentHTML(html) 之后, SetCaretPos(curpos) 为何失效?
http://topic.csdn.net/t/20050729/22/4177529.html
HTML可视化编辑器中IE丢失光标位置的问题。
http://hi.baidu.com/jindw/blog/item/8c3e928ba1f04dd0fc1f10d2.html
用土办法记忆可编辑div 内的光标位置- 极湖- by OU(链接不可用,请从google缓存里查看)
http://my.opera.com/jlake/blog/2008/05/05/div
How to RemoveChild from HtmlElement from C#
http://bytes.com/forum/thread453742.html
本文源码下载地址如下
 WebBrowserDemo.zip
View Code

WebBrowser 设置代理完全解决方案

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
微软webbrowser控件也就是IE插件,他的所有功能就像IE类似,当然设置也是一样的,下面介绍下webbrowser如何设置代理,可不要用这个对抗广告联盟哦

You can change the proxy with InternetSetOption method from the wininet.dll, here is a example to set the proxy:

using System.Runtime.InteropServices;

Public struct Struct_INTERNET_PROXY_INFO 
{ 
public int dwAccessType; 
public IntPtr proxy; 
public IntPtr proxyBypass; 
}; 
[DllImport("wininet.dll", SetLastError = true)] 
private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength);

private void RefreshIESettings(string strProxy) 
{ 
const int INTERNET_OPTION_PROXY = 38; 
const int INTERNET_OPEN_TYPE_PROXY = 3; 

Struct_INTERNET_PROXY_INFO struct_IPI; 

// Filling in structure 
struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_PROXY; 
struct_IPI.proxy = Marshal.StringToHGlobalAnsi(strProxy); 
struct_IPI.proxyBypass = Marshal.StringToHGlobalAnsi("local"); 

// Allocating memory 
IntPtr intptrStruct = Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI)); 

// Converting structure to IntPtr 
Marshal.StructureToPtr(struct_IPI, intptrStruct, true); 

bool iReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY, intptrStruct, Marshal.SizeOf(struct_IPI)); 
} 

private void SomeFunc() 
{ 
RefreshIESettings("192.168.1.200:1010"); 

System.Object nullObject = 0; 
string strTemp = String.Empty; 
System.Object nullObjStr = strTemp;
axWebBrowser1.Navigate("http://willstay.tripod.com", ref nullObject, ref nullObjStr, ref nullObjStr, ref nullObjStr); 
}

-------------------------------------------------------------------------------------------------------------------------------------

昨 天做的投票机遇到个新问题,昨天开始那个投票开始现在ip地址,每个地址只能投5票/天。如果每次更改ie的连接为代理服务器,那也麻烦死了,如 果改用webclient,那昨天的2个多小时就白费了,上网一通狂收还真找到了办法,这下好办了,建了一个proxy.txt文档,里面放上从网上收到 的代理服务器,然后程序读到一个listbox里面,每次需要更换ip的时候只要单击一次,就可以还一个地址重新投票了。
附上proxy.cs

using System.Runtime.InteropServices;//需要添加这个引用
public struct Struct_INTERNET_PROXY_INFO
{
public int dwAccessType;
public IntPtr proxy;
public IntPtr proxyBypass;
};
[DllImport("wininet.dll", SetLastError = true)]
private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength);
public void RefreshIESettings(string strProxy)
{
const int INTERNET_OPTION_PROXY = 38;
const int INTERNET_OPEN_TYPE_PROXY = 3;
Struct_INTERNET_PROXY_INFO struct_IPI;
// Filling in structure
struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
struct_IPI.proxy = Marshal.StringToHGlobalAnsi(strProxy);
struct_IPI.proxyBypass = Marshal.StringToHGlobalAnsi(”local”);
// Allocating memory
IntPtr intptrStruct = Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI));
// Converting structure to IntPtr
Marshal.StructureToPtr(struct_IPI, intptrStruct, true);
bool iReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY, intptrStruct, Marshal.SizeOf(struct_IPI));
}

使用的时候,调用RefreshIESettings
py.proxy py1 = new proxy();
py1.RefreshIESettings(”221.4.155.51:3128″);
System.Object nullObject = 0;
string strTemp = String.Empty;
System.Object nullObjStr = strTemp;
webBrowser1.Navigate(”http://www.hfxsy.cn”, null, null, null);
View Code

WebBrowser控件读html流并显示

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
C# WebBrowser控件读html流并显示
2008-04-22 08:52 677人阅读 评论(2) 收藏 举报
//环境VS2005,WinXPSP2

  //test.txt 为html源代码

         private void Form1_Load(object sender, EventArgs e)

         {

             string str = null;

            StreamReader sr = new StreamReader("D:/test.txt", Encoding.Default);

             webBrowser1.Navigate("about:blank");

            webBrowser1.Document.OpenNew(true);

             str = sr.ReadToEnd();

          webBrowser1.Document.Write(str);

       }
View Code

webBrowser 加载网页时实现进度显示

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
private void Fmain_Load(object sender, EventArgs e)
        {
            Uri uri= new Uri("http://www.baidu.com");
            webBrowser1.Url = uri;
            webBrowser1.ProgressChanged += new WebBrowserProgressChangedEventHandler(webBrowser1_ProgressChanged);
        }
        private void webBrowser1_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e)
        {
            progressBar1.Visible = true;
            if ((e.CurrentProgress > 0) && (e.MaximumProgress > 0))
            {
                progressBar1.Maximum = Convert.ToInt32(e.MaximumProgress);//设置正在加载的文档总字节数
                progressBar1.Step = Convert.ToInt32(e.CurrentProgress);////获取已下载文档的字节数
                progressBar1.PerformStep();
            }
            else if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)//加载完成后隐藏进度条
            {
                progressBar1.Value = 0;
                progressBar1.Visible = false;
            }
        }
View Code

webbrowser 代理

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
百度,google加自己理解后,将所得方法总结一下:

    方法1:修改注册表Software//Microsoft//Windows//CurrentVersion//Internet Settings下 ProxyEnable和ProxyServer。这种方法适用于局域网用户,拨号用户无效。
public partial class Form1 : Form
   {       
 4        //用于刷新注册表
       [DllImport(@"wininet",
       SetLastError = true,
       CharSet = CharSet.Auto,
       EntryPoint = "InternetSetOption",
       CallingConvention = CallingConvention.StdCall)]
11
       public static extern bool InternetSetOption
       (
       int hInternet,
       int dmOption,
       IntPtr lpBuffer,
       int dwBufferLength
       );
20         private void btnStart_Click(object sender, EventArgs e)
       {
           RegistryKey pregkey;
               pregkey = Registry.CurrentUser.OpenSubKey("Software//Microsoft//Windows//CurrentVersion//Internet Settings", true);
               if (pregkey == null)
               {
                   Console.WriteLine("键值不存在");
               }
               else
               {
                   pregkey.SetValue("ProxyEnable", 1);
                   pregkey.SetValue("ProxyServer", "代理地址");
                   //激活代理设置
                   InternetSetOption(0, 39, IntPtr.Zero, 0);
                   InternetSetOption(0, 37, IntPtr.Zero, 0);
                   webBrowser1.Navigate(txtweb.Text, false);
                   // System.Threading.Thread.Sleep(10000);
               }
       }
39}

方法2: 修改注册表Software//Microsoft//Windows//CurrentVersion//Internet Settings//Connections下以你拨号连接名为键的值,该键为二进制。这种方法适用于拨号用户。

    
public partial class FrmMain : Form
    {

[DllImport(@"wininet",
        SetLastError = true,
        CharSet = CharSet.Auto,
        EntryPoint = "InternetSetOption",
        CallingConvention = CallingConvention.StdCall)]


        public static extern bool InternetSetOption
        (
        int hInternet,
        int dmOption,
        IntPtr lpBuffer,
        int dwBufferLength
        );

//将值转换为注册表中的二进制值
public byte ChangeTobyte(char i)
        {
            byte key = 0;
            switch (i)
            {
                case '0': key = 48; break;
                case '1': key = 49; break;
                case '2': key = 50; break;
                case '3': key = 51; break;
                case '4': key = 52; break;
                case '5': key = 53; break;
                case '6': key = 54; break;
                case '7': key = 55; break;
                case '8': key = 56; break;
                case '9': key = 57; break;
                case '.': key = 46; break;
                case ':': key = 58; break;
                
            }
            return key;
        }

private void btnStart_Click(object sender, EventArgs e)
        {
             int i = ("代理地址").Length;
                byte[] key = new byte[50];
                char[] source = ("代理地址").ToCharArray();
                key[0] = 60;
                key[4] = 3;
                key[8] = 3;
                key[12] = (byte)i;
                for (int ii = 0; ii < source.Length; ii++)
                {
                    key[16 + ii] = ChangeTobyte(source[ii]);
                }
                string sDirectX = "";
                for (int k = 0; k < key.Length; k++)
                {
                    if (key[k] != 0)
                    {
                        sDirectX += key[k] + " ";
                    }
                }
                //MessageBox.Show(sDirectX);
                RegistryKey pregkey;
                pregkey = Registry.CurrentUser.OpenSubKey("Software//Microsoft//Windows//CurrentVersion//Internet Settings//Connections", true);
                if (pregkey == null)
                {
                    Console.WriteLine("键值不存在");
                }
                else
                {
                    pregkey.SetValue("拨号名字对应键值", key, RegistryValueKind.Binary);
                    //激活代理设置
                    InternetSetOption(0, 39, IntPtr.Zero, 0);
                    InternetSetOption(0, 37, IntPtr.Zero, 0);
                    webBrowser1.Navigate(txtweb.Text, false);
                    webBrowser1.Refresh();
                    
                }

        }
}

方法3: 使用c#自带的webproxy类,使用这种方法可以获得目标网站的响应,但我不会把这种响应用IE反馈出来,有高手帮个忙么?
网上的代码说是MSDN的:
    HttpWebRequest myWebRequest=(HttpWebRequest)WebRequest.Create("http://www.microsoft.com"/); 
    WebProxy myProxy=new WebProxy(); 
    // Obtain the 'Proxy' of the  Default browser.   
    myProxy=(WebProxy)myWebRequest.Proxy; 这行我编译不通过
    // Print the Proxy Url to the console. 
    Console.WriteLine("/nThe actual default Proxy settings are {0}",myProxy.Address); 
    try 
    { 
    Console.WriteLine("/nPlease enter the new Proxy Address that is to be set:"); 
    Console.WriteLine("(Example:http://myproxy.example.com:port/)"); 
    string proxyAddress; 
    proxyAddress =Console.ReadLine(); 
    if(proxyAddress.Length>0) 

    { 
    Console.WriteLine("/nPlease enter the Credentials "); 
    Console.WriteLine("Username:"); 
    string username; 
    username =Console.ReadLine(); 
    Console.WriteLine("/nPassword:"); 
    string password; 
    password =Console.ReadLine(); 
    // Create a new Uri object. 
    Uri newUri=new Uri(proxyAddress); 
    // Associate the newUri object to 'myProxy' object so that new myProxy settings can be set. 
    myProxy.Address=newUri; 
    // Create a NetworkCredential object and associate it with the Proxy property of request object. 
    myProxy.Credentials=new NetworkCredential(username,password); 
    myWebRequest.Proxy=myProxy; 
    } 
    Console.WriteLine("/nThe Address of the  new Proxy settings are {0}",myProxy.Address); 
    HttpWebResponse myWebResponse=(HttpWebResponse)myWebRequest.GetResponse(); 

我改了下:
    
            HttpWebRequest myWebRequest = (HttpWebRequest)WebRequest.Create("http://www.123cha.com");
            WebProxy myProxy = new WebProxy("代理地址", true);
            try
            {
                
                Console.WriteLine("/nThe Address of the  new Proxy settings are {0}", myProxy.Address);
                HttpWebResponse myWebResponse = (HttpWebResponse)myWebRequest.GetResponse();
               
                webBrowser1.DocumentStream = myWebResponse.GetResponseStream();
             

            }
            catch { }
View Code

设置IE浏览器的代理

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
思路:主要是通过修改注册表实现的。
 
代码如下:
using System.Runtime.InteropServices;
using Microsoft.Win32;
 
 //You can change the proxy with InternetSetOption method from the wininet.dll, here is a example to set the proxy
[DllImport("wininet.dll", SetLastError = true)]
private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength);
 
/// <summary>
/// 设置IE代理
/// </summary>
/// <param name="isNeedProxy">是否需要代理</param>
 private static void SettingsIEBrowserProxy(bool isNeedProxy)
{
           const string INTERNETSETTINGSKEYPATH = "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
            RegistryKey settings = null;
            try
            {
                settings = Registry.CurrentUser.OpenSubKey(INTERNETSETTINGSKEYPATH, true);
                //更改健值,设置代理,  
                if (settings != null)
                {
                    if (isNeedProxy)
                    {
                        settings.SetValue("ProxyEnable", 1);
                        //ip.port 就是代理服务器的ip,port就是端口
                        settings.SetValue("ProxyServer", ip +":" + port);
                    }
                    else
                    {
                        //取消代理
                        settings.SetValue("ProxyEnable", 0);
                    }
                }
                //激活代理设置
                InternetSetOption(IntPtr.Zero, 39, IntPtr.Zero, 0);
                InternetSetOption(IntPtr.Zero, 37, IntPtr.Zero, 0);
            }
            catch (Exception ex)
            {
                 throw ex;
            }
            finally
            {
                if (settings != null)
                {
                    settings.Close();
                }
            }
 }
 
这样就可以实现IE通过代理,来打开网页。
View Code

 通过http代理服务器,实现代理登录

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
C# 通过http代理服务器,实现代理登录
今天接到一个需求,需要通过http代理服务器,实现代理登录。 
思路很简单:
实例化一个代理对象;
把上面的代理对象实例赋给HttpWebRequest、WebService服务对象的Proxy属性,就实现了代理登录。
    
看下面的代码:
//第一步:实例化代理对象,proxyServerAddress表示代理服务器地址,false表示,若代理服务器是本地地址,则跳过http代理服务器。http代理服务器地址一般形式:http://ip:端口
Web代理 proxy = new Web代理("代理服务器地址",false); 
 
//第二步:给代理对象加上验证属性,要看你的http代理服务器是否需要身份验证;proxyname代理用户名,proxypassword代理密码,domainname域名
proxy.Credentials = new NetworkCredential(proxyname,proxypassword,domainname);
 
由于项目上使用的登录是用webservice实现的,这样造成也可以用http代理服务器实现代理登录;
//第三步:实例化登录服务
 ProxyInterfaceService loginService=new ProxyInterfaceService();
 
//第四步:给登录服务对象的代理属性赋值为第一步实例化的代理对象
loginService.Proxy = proxy;
loginService.login("登录用户名","登录密码",null); 
  
若是用http实现的登录也是一样的,只要修改上面的第三、四步的代码就行了。代码如下:
 
HttpWebRequest request = WebRequest.Create("真正登录的服务器地址")  as  HttpWebRequest;
request.Proxy=proxy;
就这样实现了http代理登录,很简单吧。
View Code

为WebBrowser设置代理,打开网页

C# (转载)webbrowser专题(参考资料:https://www.cnblogs.com/blogpro/p/11458390.html)
WebBrowser控件是基于IE浏览器的,所以它的内核功能是依赖于IE的,相信做.NET的人都知道。
       今天的主题,和上一篇文章应该是差不多的,都是通过代理来实现功能的。
        请看下面的代码:
        //1.定义代理信息的结构体
        public struct Struct_INTERNET_PROXY_INFO 
        { 
            public int dwAccessType; 
            public IntPtr proxy; 
            public IntPtr proxyBypass; 
        };
 
        //You can change the proxy with InternetSetOption method from the wininet.dll, here is a example to set the proxy
       //这个就是设置一个Internet 选项,其实就是可以设置一个代理
        [DllImport("wininet.dll", SetLastError = true)] 
        private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength);
 
       //设置代理的方法
        //strProxy为代理IP:端口
        private void InternetSetOption(string strProxy) 
        {
           //设置代理选项
            const int INTERNET_OPTION_PROXY = 38;
           //设置代理类型
            const int INTERNET_OPEN_TYPE_PROXY = 3;
           //设置代理类型,直接访问,不需要通过代理服务器了
            const int INTERNET_OPEN_TYPE_DIRECT = 1;

            Struct_INTERNET_PROXY_INFO struct_IPI;
            // Filling in structure 
            struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
            //把代理地址设置到非托管内存地址中 
            struct_IPI.proxy = Marshal.StringToHGlobalAnsi(strProxy);
            //代理通过本地连接到代理服务器上
            struct_IPI.proxyBypass = Marshal.StringToHGlobalAnsi("local");
            // Allocating memory 
           //关联到内存
            IntPtr intptrStruct = Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI));
            if (string.IsNullOrEmpty(strProxy) || strProxy.Trim().Length == 0)
            {
                strProxy = string.Empty;
                struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
            }
            // Converting structure to IntPtr 
           //把结构体转换到句柄
            Marshal.StructureToPtr(struct_IPI, intptrStruct, true);
            bool iReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY, intptrStruct, Marshal.SizeOf(struct_IPI));
        } 
 
        private void button1_Click(object sender, EventArgs e)
        {
                InternetSetOption("192.168.6.218:3128");
                webBrowser1.Navigate("http://www.baidu.com", null, null, null);
        }
       
       上面是代码是设置代理,要是取消代理怎么实现?
       很简单,把调用InternetSetOption(string strProxy) 函数中的strProxy参数设置为空就行了。
       例如:
       private void button2_Click(object sender, EventArgs e)
        {
                InternetSetOption(string.Empty);
                webBrowser1.Navigate("http://www.baidu.com", null, null, null);
        }
View Code
上一篇:C# webbrowser 多线程操作/跨线程操作


下一篇:Ubuntu下 Hadoop 1.2.1 配置安装