Web浏览器控制限制

我在Windows窗体C#项目中使用WebBrowser控件,并想知道您可以同时运行多少个此类应用程序实例的任何限制。 (换句话说,MSFT强制执行除物理机器限制之外的任何限制 – CPU /内存等)

WebBrowser控件没有人为限制。

但是,它使用IE的渲染引擎(无论最终用户的计算机上安装了什么版本),因此它使用了相当多的内存。

你想做什么?

如果您正在尝试编写Web浏览器,我建议您使用更好的渲染引擎,例如WebKit或Gecko 。

让我告诉你一些不利之处……

[这里提到的大部分问题已经在StackOverflow的前一个答案部分得到了一定程度的回答或解决,如果你很好奇,可以随意浏览我的WebBrowser-Control相关答案]。

  1. 检测页面何时真正完成加载是非常难以可靠的,事实上,你必须使用一系列黑客才能做到这一点,一些方法和想法甚至没有谈到在线,不知道,但是我花了多年时间与这个控件进行斗争,我已经想出了一些东西,并开发了一个代码库来使其工作! 如果您需要帮助,我可以提供更多细节。

  2. 让我直截了当地告诉你。 修复了webbrowser控件上的默认呈现引擎,以确保所有平台之间的兼容性。

    基本上,如果你安装的浏览器是IE 7 – IE 9,那么使用的渲染引擎只是IE 7.0(默认情况下)。

    但是,如果你安装的IE版本是IE 6或更低版本,则使用的渲染引擎是IE 4.0(不是开玩笑),除非你设置它。

    有一种误解,即WebBrowser控件使用当前安装的任何内容(当前的IE版本),但事实并非如此,因为他们这样做是为了减少向后兼容性问题。 您可以通过在普通浏览器中访问www.whatsmyuseragent.com,然后在WebBrowser控件中再次访问该网站,看到(作为证据)这确实是您的问题,您将看到它表示MSIE 7.0 :)。

    您可以将其设置为使用当前安装的Internet Explorer版本,在页面中使用META标记,或者在将运行webbrowser控件的计算机上编辑注册表(编辑Current_User和Local_Machine都可以)。

    因此,出于兼容性原因,默认情况下它将以IE7标准模式呈现页面。 为防止这种情况发生,请按照我在下面提供的链接进行讨论,该链接将讨论META标记方法和注册表编辑方法以解决此问题(适用于32位和64位系统)。 该解决方案包含在对其他人关于function不正确或意外工作的问题的回答中。 阅读问题不是正确解释/理解答案所必需的。 链接在这里:

    脚本WebBrowser控件中的脚本运行速度较慢 (Ctrl +单击以在新选项卡中打开)。

  3. 事件系统非常hacky,你真的需要知道没有正确记录的东西和一些根本没有记录的东西。 事实上,就产品设计而言,我已经宣称它是MS最差的产品之一,而且还缺乏他们在其上提供的体面文档。 他们干燥的MSDN风格文档是可笑的。

  4. 坏帧支持,如果你调用document.frames.length,你只会得到顶层文档下的帧,而不是所有帧,你需要编写自己的函数来获取所有嵌套帧(无限嵌套)如果你需要帮助,我已经这样做了。 帧检测和引用非常重要,在检测页面何时完成加载时起着至关重要的作用。 在那里,在WebBrowser控件上使用.Busy和.ReadyState是不够的。 事实上,它远远不够。

  5. 没有内置系统可以摆脱每个页面弹出的JavaScript对话框,包括新的IE9对话框,让人们看到“你确定要离开这个页面”的消息。 我已经开发了例程来完成它并摆脱它们,基本上,其中一个方法涉及执行从WebBrowser控件发送到html页面的JavaScript,指示它摆脱警报,确认,打印对话框(以及获取摆脱我之前提到的新IE 9对话框)。 这些是来自JS的潜在对话框,我基本上运行JavaScript,告诉浏览器.alert函数是Null(即:一个空的方法/函数什么都不做),我对所有这些做同样的事情4个来自JavaScript的对话框。 当然,如果你计算的盒子超过4盒(如果你的数量更多,请随时告诉我)。 另外,还有第二种方法可以做到这一点,它不仅会阻止JavaScritp对话框,而且会阻止每个会出现在webbrowser控件中的对话框,此方法使用WinHooks,并截获之前的对话框它显示,您可以从对话框中获取所需的信息(其内容为文本,标题/标题为文本等),并决定是否要显示或取消显示,甚至模拟任何部分的点击对话框(即:任何按钮),以便堆栈认为问题或信息对话框已正确响应。 这是一个有趣的方法,我已经读过但还没有尝试过,我真的很期待在有空闲时间后理解WinHook流程。 像往常一样,如果你需要帮助,请随时查看我以前对各种webbrowser控制问题的一些答案,因为我已经回答了很多,如果不这样做,请告诉我。 请记住,这在很大程度上取决于知道页面何时完全加载,这很难做到(但可能,使用未记录的方法,以100%可靠的方式)。 所以要点1)。 将多次相关。

  6. 没有可靠或简单的方法来控制持续或保存的缓存信息,再一次,您必须开发自己的例程来执行您想要的缓存信息,过滤,删除或尝试阻止所有缓存类型,包括存储在本地系统上的历史信息,cookie和实际缓存文件。 如果您查看DeleteUrlCacheEntry,它将为您提供两种方法来自行完成,我也很确定我之前有一些讨论如何在StackOverflow上执行此操作。 使用DeleteUrlCacheEntry,您可以使用以“Cookie:”标记开头的缓存项目,“Visited:”标记以及只是普通网站地址的项目(以“http://”和“https://”开头) (是的,https被缓存; |,至少位置信息是无论如何)。另请注意,通过DeleteUrlCacheEntry(以及随附的FindFirstUrlCacheEntry / FindNextUrlCacheEntry用于遍历整个缓存)提供的此信息不包括您的实际Internet浏览器历史记录项目。“访问:”站点列表与您的实际历史记录列表分开,当您单击Internet Explorer菜单栏上的*符号并进入历史记录部分(从collections夹部分)时,您会看到该列表。我是不确定为什么他们这样做,以及确切的,正式的差异是什么(以及为什么会有差异),但它是在要找出的事项清单上(请随时在评论中告诉我们)。因为, “访问:”列表是您的网站列表 ave访问过,IE历史记录几乎是你访问过的网站列表。 我不认为他们区分您手动键入和输入的网站,而不是HTML页面或浏览器自动检索的零碎(例如通过iframe等,以及自动重定向,弹出窗口等) …所以我发现很难理解区别是什么,一旦我发现,我会更新这一点。

  7. 覆盖默认用户代理不是正确构建的,您可以将自己的用户代理传递到导航方法,但是一旦用户在那里导航,该网站将在您设置时获取您的程序用户代理详细信息,但是,这赢得了永远不会。 因此,一旦用户跟踪导航页面上的链接,WebBrowser控件将继续发送WB控件用于呈现您的站点的实际(真实)用户代理,除非您拦截导航,取消导航并使用重新导航再次发送您自己的用户代理时再次使用.navigate方法。 这将无法解决图像和LINK标记文件等问题,因为您没有获取这些事件的BeforeNavigate事件,因此您无法拦截它们并修改为它们发送的标头。 相反,您需要通过导入一些外部函数urlmon.dll来使用外部解决方案 – 这可以100%完成并且完美无缺,但是,它是另一个添加的依赖项(但是urlmon.dll包含在所有相关的Windows版本中)。

  8. 没有“将我的所有WB控制活动重定向到此特定帧”属性或方法,尽管您可以并且必须开发它,如果您想要或需要,唯一的帧支持是.navigate附带的TargetFrameName参数对于每个需要在那里进行的操作,您需要获取对它的引用并指导您在那里手动执行的所有操作,因为用户可以从任何框架中单击事物,除非您检查,否则您不知道或不知道为了它。

  9. 具有指向外部域的帧的站点的跨框架安全性:如您所知,如果您在abc.com上有一个页面,并且它具有来自名为xzy.com的域的源的iframe(正如大多数广告客户在中继时所做的那样)如果您尝试访问该帧,则无论您的应用程序在哪个提升的权限下运行,您将遇到跨框架域安全问题。 它是愚蠢的,他们甚至不会告诉你它,相反,你指向框架的参考文件将没有任何数据,你将无法使用它,WB控制不会告诉你原因。 您可以访问的只是框架的源URL,就是它,它内部没有任何内容。 解? 好吧,你的机器上有一个可以注册的TypeLib可用于覆盖它,不是内置在WB控件中,甚至没有内置到你自己的编程接口中,实际上它是你需要通过引用使用的外部C例程并注册TypeLib(现在不确定是否有一种新方法可以在.NET中使用此方法)。 但是,您需要在当前的编程环境中围绕此TypeLib编写代码(使用TypeLib注册中的东西的代码过多,所以这不仅仅是调用函数的问题,而是围绕该函数编写更多代码’将要使用)。

  10. 打开/关闭JavaScript,打开/关闭导航设置,例如导航声等。如果您正在编写Web提取程序,导航声音会让您的用户发疯,打开或关闭这些选项并不会内置到WebBrowser控件中,如果需要,可以使用注册表全局更改内容,然后在完成后将其更改回来。 您需要查找每个互联网设置相关设置/选项的注册值。 有一些方法可以为您的应用程序实例执行此操作,我相信从InternetSecuritySettings导入例程,但是再一次,没有内置到WB中,只有另一系列的hacks要添加到列表中。

  11. 当然,您需要检测是否存在互联网连接,以及是否存在互联网连接。 WB Control甚至没有给你一丝希望,即使它是让它工作的重要部分。 所以,如果你不想让MS拨号连接的烦人弹出窗口(对于那些使用拨号的人)或互联网向导用于其他连接,那么每次出现你的WB控件都要进行连接或尝试在某处导航,那么您将需要使用控件来手动检查连接,并且此控件必须是MS之外的控件,并且控件不具有MS API的核心(因为MS Internet API是API的触发这些弹出框进行互联网连接)。 因此,您需要从头开始编写一个不使用winsocks的外部winsocks类型控件,学习如何使用它,并在每次使用WB执行操作之前使用它来尝试检查互联网是否已连接控制。

  12. 你会得到很多“自动化错误”或“未指定的错误”消息,它甚至没有告诉你出了什么问题,当你处理实时html文档/页面上的元素时,这些通常是在有html时以不推荐的方式完成,即使它是浏览器可以处理和阅读的方式,并定期处理。 例如,如果你有一个带有target = _top的Anchor链接,并且你在_top部分周围没有引号,即使浏览器理解这一点并按预期运行,webbrowser控件也会抛弃它并放弃,抛出一个“未指明的错误” – 甚至没有告诉你它是什么超级挑剔。 所以,你必须确保元素是这样编写的:target =“_ top”才能使WB控件表现出来,并且对每个实时文档进行这些更改可能会很乏味,而且你需要如果需要,编写通用例程来为每个页面执行此操作 – 在文档满载后运行的例程(为了这样做,您必须可靠地检测)。 如果我必须选择使用WB控件正确执行的最难的事情,则必须检测页面何时完全可靠地加载。 最重要的是,使用WB控制也是你需要做的最重要的事情,因为几乎所有东西都取决于对此的准确检测。

  13. 它需要一个单独的历史对象,因为如果您在导航过程中选择“无历史记录”,或者找到一种无历史导航工作的方法,您可以确定返回或转发到这些页面将无法工作(即:调用。 GoBack或.GoForward到这些页面和地址)。 从历史记录中删除或指定不为此特定导航保留历史记录后,除非您转到该页面,否则无法返回。 即使页面已从全局历史记录中删除(这是无历史浏览的唯一方式),它们应该保留一个应该可以返回的内存历史记录列表。 因此,如果您尝试返回,您将(在所有内容之上)获得运行时错误,并且仅在最近的.NET时间内它们提供了一个名为.CanGoBack的方法来检查您是否可以返回,之后(如果使用pre.NET)你应该围绕这个编写代码或者尝试保持你的位置(这不容易做,但仍然可行)。

我可以坚持下去(我想)但是我现在就把它留在那里,然而,除了那些东西,它是一个非常酷的控制,并打开了通向一个全新的应用程序和想法世界的大门。 正如我在其中的几点中所提到的,这些都是我已经解决的问题(还有更多,我在需要解决方案时已经解决了),所以如果您有任何疑问或需要帮助,请让我知道,因为我很乐意至少试着帮助你。

当我试图弄清楚这些东西时,周围没有人来帮助我,因为没有人真正了解这种控制,所以我不得不一点一点地弄清楚事情。 从那以后,它越来越受欢迎,并且有更多的人使用它(特别是因为.NET版本提供了渐进的改进)。 因此,很高兴能帮助那些我以前遇到的情况,因为我记得这是一个可怕而孤独的地方,而MS没有做任何明智的文档。 它只是他们为内部使用而开发的东西,让其他人使用它,同时只提供所有属性,方法和事件的输入/输出参数/参数列表和返回值列表,这就是它 – 没有意义或上下文或者与之相关的真实代码示例,当然,在解决随之而来的一系列问题方面没有任何文档明智。

好吧,现在这样做,会对人们对这种控制和使用它的意见感兴趣,所以随时发表评论。 照顾自己。 ERX。

试试这段代码,看看会发生什么:

 int count = 0; List
forms = new List
(); try { while (true) { Form f = new Form(); WebBrowser wb = new WebBrowser(); f.Controls.Add(wb); f.Show(); wb.Url = new Uri(@"http://www.stackoverflow.com"); forms.Add(f); count++; } } catch { MessageBox.Show(count.ToString()); }

我猜它会有数百个,但我不知道。