<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    如鵬網 大學生計算機學習社區

    CowNew開源團隊

    http://www.cownew.com 郵件請聯系 about521 at 163.com

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      363 隨筆 :: 2 文章 :: 808 評論 :: 0 Trackbacks
    一篇介紹寫自定義瀏覽器的很好的文章:
    from:http://www.codeproject.com/csharp/ExtendedWebBrowser.asp

    Sample Image

    Contents

    1. Introduction
    2. The goals, challenges, and solutions
    3. Creating the extended WebBrowser component
    4. Using the component
    5. Conclusion

    1: Introduction

    .NET 2.0 has a new WebBrowser control in the System.Windows.Forms namespace. This control itself is very useful, but doesn't supply some events that might be needed in certain situations. This article explains how to extend the WebBrowser control and add functionality for things like pop-up blocking, script error handling, and handling new windows in a tabbed browser environment.

    For extending the WebBrowser control, some features are not documented in the Help files of the .NET Framework. Not letting us be stopped by the "This method supports the .NET Framework infrastructure and is not intended to be used directly from your code." message, it is possible to create an object that implements IWebBrowser2 and use all the functionality of the underlying browser. Besides this, DWebBrowserEvents2 can be implemented for adding events to the control.

    This article assumes that you have already some knowledge of the browser interfaces IWebBrowser2 and DWebBrowserEvents2. Some knowledge about COM Interop and interfaces is also required.

    2: The goals, challenges, and solutions

    The goals of this component are:

    • Handling script errors in a neat way
    • Blocking unwanted pop-ups
    • Enabling functionality for tabbed browsing or MDI browsing
    • Making sure that a window is closed when it is closed by script

    This section explains the problems associated with the goals and their solutions, in a short form. The next section goes more into the coding details.

    Handling Script Errors

    The WebBrowser control has a ScriptErrorsSuppressed property... Setting this property to true does actually a bit more than it is supposed to. It not only disables the script error dialog, but also the dialog for logging on to a secure website with user certificates... What if we still want that functionality, or we would like to be notified when a script error has taken place, or we would like to know all the details about the script error?

    The script error can be caught by the HtmlWindow.Error event. This event fires whenever a script error occurs, with all the details. The challenge is that HtmlWindow is to be accesed with the HtmlDocument object, which is not always available. HtmlDocument comes available as soon as the Navigated event is fired. But what if the user refreshes the browser with F5? Sorry, the Navigated event doesn't fire. After some testing, I found that the only reliable way was to use the DownloadComplete event, which is not part of the default WebBrowser control.

    Solution:

    1. Implement DWebBrowserEvents2
    2. Create a DownloadComplete event
    3. When DownloadComplete fires, subscribe to the HtmlWindow.Error event
    4. Use the error event for obtaining the script error information
    5. Set the Handled property to true to suppress the script error

    Blocking unwanted pop-ups

    Pop-ups are most of the time not very welcome, or could be inappropriate. To block these things, some additional information is needed. NewWindow3 gives this information when the user uses Windows XP SP2, or Windows 2003 SP1 or better. If this event is not fired, NewWindow2 takes its place. When NewWindow3 is fired, you can check:

    • If the user initiated the action that leads to the new window
    • If the user holds the override key (the Ctrl Key)
    • If it is a pop-up displayed because of a window that is closing
    • The URL that is going to be opened
    • And more...

    Using NewWindow3 clearly is very interesting for this purpose. To use this event, DWebBrowserEvents2 needs to be implemented.

    Solution:

    1. Implement DWebBrowserEvents2
    2. Create a new event and a new event arguments class
    3. Launch this event with the appropriate information
    4. After the event is fired, see if the navigation needs to be canceled

    Enabling functionality for tabbed browsing or MDI browsing

    Tabbed browsing seems to gain popularity these days. For Internet Explorer 7, this is one of the new features. The challenge in tabbed browsing is that you need to create a window when this is needed by scripts or links. Besides this, window name resolution should work over multiple windows or tabs. (For example: <A href="http://SomeSite" target="SomeWindowName"/>) To achieve this, the automation object (called ppDisp in the NewWindowX event, and Application in the IWebBrowser2 interface) should be passed from the new browser back to the event. To get access to the Application property, it is needed to get a reference to the underlying IWebBrowser2 interface.

    Solution:

    1. Override AttachInterfaces and DetachInterfaces
    2. Store a reference to the IWebBrowser2 interface object
    3. Create a property called Application that exposes the Application property of the interface
    4. Implement the DWebBrowserEvents2 interface
    5. Listen for NewWindow2 and/or NewWindow3 events
    6. Whenever an event is raised, create a new instance of the browser control
    7. Assign the event parameter ppDisp to the Application property of the new instance

    Making sure that a window is closed when it is closed by script

    When you invoke window.close() in JScript, it looks like the WebBrowser control hangs. Somehow, it can't be used for navigation, nor can it be used for anything else. It would be nice if we know when this happens. There are several events that fire when this happens, but none of the events gives us actually the information needed. Overriding WndProc and seeing if the parent is notified that the browser is destroyed, is the only reliable solution. (If someone knows how to get WindowClosing to work, it would be nice here!)

    Solution:

    1. Override WndProc
    2. Check for the message WM_PARENTNOTIFY
    3. Check for the parameter WM_DESTROY
    4. If this is the case, fire a new event (this event is called Quit, in the example)

    3: Creating the extended WebBrowser component

    From the last section, we have seen that all of this basically comes down to two things:

    1. Implement an object of type IWebBrowser2, for obtaining the Application property of the browser
    2. Implement DWebBrowserEvents2 for firing events

    Implementing IWebBrowser2

    The WebBrowser control has two methods that are undocumented: AttachInterfaces() and DetachInterfaces(). These methods need to be used when you want to obtain a reference to the IWebBrowser2 interface.

    Collapse
      /// <summary>
    /// An extended version of the <see cref="WebBrowser"/> control.
    /// </summary>
    public class ExtendedWebBrowser : System.Windows.Forms.WebBrowser
    {
    private UnsafeNativeMethods.IWebBrowser2 axIWebBrowser2;
    /// <summary>
    /// This method supports the .NET Framework
    /// infrastructure and is not intended
    /// to be used directly from your code. 
    /// Called by the control when the underlying
    /// ActiveX control is created. 
    /// </summary>
    /// <param name="nativeActiveXObject"></param>
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
    protected override void
    AttachInterfaces(object nativeActiveXObject)
    {
    this.axIWebBrowser2 =
    (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
    base.AttachInterfaces(nativeActiveXObject);
    }
    /// <summary>
    /// This method supports the .NET Framework infrastructure
    /// and is not intended to be used directly from your code. 
    /// Called by the control when the underlying
    /// ActiveX control is discarded. 
    /// </summary>
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
    protected override void DetachInterfaces()
    {
    this.axIWebBrowser2 = null;
    base.DetachInterfaces();
    }
    ...
    }

    Next, we can add the Application property.

    /// <summary>
    /// Returns the automation object for the web browser
    /// </summary>
    public object Application
    {
    get { return axIWebBrowser2.Application; }
    }

    This property can be used for creating a new window, and redirecting the browser to this new window, when a new window event is fired.

    Implementing DWebBrowserEvents2

    The following events are implemented in this sample:

    • NewWindow2 and NewWindow3 (for blocking pop-ups and creating new windows)
    • DownloadBegin and DownloadComplete (for handling script errors)
    • BeforeNavigate2 (if you want to see where you're going before even starting to get there)

    To neatly implement DWebBrowserEvents2, it is best to create a privately nested class in the component. This way, all the events that are needed are on one place and easy to find. When we instantiate this class, we provide a reference to the caller, whose methods can be invoked for raising the events we need.

    Events are not attached at component construction, but a bit later. There are two methods here that provide this and can be overridden. These are CreateSink() and DetachSink(). When adding this all up, we get something like this (note that some code has been cut for readability):

    Collapse
      /// <summary>
    /// An extended version of the <see cref="WebBrowser"/> control.
    /// </summary>
    public class ExtendedWebBrowser : System.Windows.Forms.WebBrowser
    {
    // ... (More code here)
    System.Windows.Forms.AxHost.ConnectionPointCookie cookie;
    WebBrowserExtendedEvents events;
    /// <summary>
    /// This method will be called to give
    /// you a chance to create your own event sink
    /// </summary>
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
    protected override void CreateSink()
    {
    // Make sure to call the base class or the normal events won't fire
    base.CreateSink();
    events = new WebBrowserExtendedEvents(this);
    cookie = new AxHost.ConnectionPointCookie(this.ActiveXInstance,
    events, typeof(UnsafeNativeMethods.DWebBrowserEvents2));
    }
    /// <summary>
    /// Detaches the event sink
    /// </summary>
    [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
    protected override void DetachSink()
    {
    if (null != cookie)
    {
    cookie.Disconnect();
    cookie = null;
    }
    }
    /// <summary>
    /// Fires when downloading of a document begins
    /// </summary>
    public event EventHandler Downloading;
    /// <summary>
    /// Raises the <see cref="Downloading"/> event
    /// </summary>
    /// <param name="e">Empty <see cref="EventArgs"/></param>
    /// <remarks>
    /// You could start an animation
    /// or a notification that downloading is starting
    /// </remarks>
    protected void OnDownloading(EventArgs e)
    {
    if (Downloading != null)
    Downloading(this, e);
    }
    // ... (More code here)
        #region The Implementation of DWebBrowserEvents2 for firing extra events
    //This class will capture events from the WebBrowser
    class WebBrowserExtendedEvents :
    UnsafeNativeMethods.DWebBrowserEvents2
    {
    public WebBrowserExtendedEvents() { }
    ExtendedWebBrowser _Browser;
    public WebBrowserExtendedEvents(ExtendedWebBrowser
    browser) { _Browser = browser; }
          #region DWebBrowserEvents2 Members
    // ... (More code here)
    public void DownloadBegin()
    {
    _Browser.OnDownloading(EventArgs.Empty);
    }
    public void DownloadComplete()
    {
    _Browser.OnDownloadComplete(EventArgs.Empty);
    }
    // ... (More code here)
          #endregion
    }
        #endregion
    }

    4: Using the component

    In the last section, we created a new component. Now, it's time to use the new events and get the maximum functionality out of the browser. For each of the goals, the details are explained here.

    Handling the script errors

    In the sample application, there is a tool window that simply shows a list of errors that occured, with their details. A single-instance class holds the script errors' information and notifies the subscribers when this information has been changed. For handling these script errors, the BrowserControl first attaches to the DownloadComplete event, and next subscribes to the HtmlWindow.Error event. When this event is fired, we register the script error and set the Handled property to true.

    Collapse
      public partial class BrowserControl : UserControl
    {
    public BrowserControl()
    {
    InitializeComponent();
    _browser = new ExtendedWebBrowser();
    _browser.Dock = DockStyle.Fill;
    // Here's the new DownloadComplete event
    _browser.DownloadComplete +=
    new EventHandler(_browser_DownloadComplete);
    // Some more code here...
    this.containerPanel.Controls.Add(_browser);
    // Some more code here...
    }
    void _browser_DownloadComplete(object sender, EventArgs e)
    {
    // Check wheter the document is available (it should be)
    if (this.WebBrowser.Document != null)
    // Subscribe to the Error event
    this.WebBrowser.Document.Window.Error +=
    new HtmlElementErrorEventHandler(Window_Error);
    }
    void Window_Error(object sender, HtmlElementErrorEventArgs e)
    {
    // We got a script error, record it
    ScriptErrorManager.Instance.RegisterScriptError(e.Url,
    e.Description, e.LineNumber);
    // Let the browser know we handled this error.
    e.Handled = true;
    }
    // Some more code here
    }

    Blocking unwanted pop-ups, and enabling functionality for tabbed browsing or MDI browsing

    Handling pop-ups should be user configurable. For the purpose of demonstration, I've implemented four levels, ranging from blocking nothing to blocking every new window. This code is part of the BrowserControl, and shows how to do this. After the new window is allowed, the example shows how to let the new browser participate in the window name resolution.

    Collapse
    void _browser_StartNewWindow(object sender,
    BrowserExtendedNavigatingEventArgs e)
    {
    // Here we do the pop-up blocker work
    // Note that in Windows 2000 or lower this event will fire, but the
    // event arguments will not contain any useful information
    // for blocking pop-ups.
    // There are 4 filter levels.
    // None: Allow all pop-ups
    // Low: Allow pop-ups from secure sites
    // Medium: Block most pop-ups
    // High: Block all pop-ups (Use Ctrl to override)
    // We need the instance of the main form,
    // because this holds the instance
    // to the WindowManager.
    MainForm mf = GetMainFormFromControl(sender as Control);
    if (mf == null)
    return;
    // Allow a popup when there is no information
    // available or when the Ctrl key is pressed
    bool allowPopup = (e.NavigationContext == UrlContext.None)
    || ((e.NavigationContext &
    UrlContext.OverrideKey) == UrlContext.OverrideKey);
    if (!allowPopup)
    {
    // Give None, Low & Medium still a chance.
    switch (SettingsHelper.Current.FilterLevel)
    {
    case PopupBlockerFilterLevel.None:
    allowPopup = true;
    break;
    case PopupBlockerFilterLevel.Low:
    // See if this is a secure site
    if (this.WebBrowser.EncryptionLevel !=
    WebBrowserEncryptionLevel.Insecure)
    allowPopup = true;
    else
    // Not a secure site, handle this like the medium filter
    goto case PopupBlockerFilterLevel.Medium;
    break;
    case PopupBlockerFilterLevel.Medium:
    // This is the most dificult one.
    // Only when the user first inited
    // and the new window is user inited
    if ((e.NavigationContext & UrlContext.UserFirstInited)
    == UrlContext.UserFirstInited &&
    (e.NavigationContext & UrlContext.UserInited)
    == UrlContext.UserInited)
    allowPopup = true;
    break;
    }
    }
    if (allowPopup)
    {
    // Check wheter it's a HTML dialog box.
    // If so, allow the popup but do not open a new tab
    if (!((e.NavigationContext &
    UrlContext.HtmlDialog) == UrlContext.HtmlDialog))
    {
    ExtendedWebBrowser ewb = mf.WindowManager.New(false);
    // The (in)famous application object
    e.AutomationObject = ewb.Application;
    }
    }
    else
    // Here you could notify the user that the pop-up was blocked
    e.Cancel = true;
    }

    The reason the event is called StartNewWindow is that the code design guidelines do not allow an event to begin with "Before" or "After". "NewWindowing" doesn't have the same kind of ring to it :)

    Using the Quit event

    When the Quit event is fired, it's simply a matter of finding the right window or tab to close, and Dispose the instance.

    5: Conclusion

    The WebBrowser control is a good control for enabling web content in Windows applications. The additions in this article can be used to overcome the obstacles that developers face when they have no control over what web pages or other content the user might visit with their application. Hopefully, the next version of the .NET Framework will give us a little extra.

    The sample application and source

    The sample application is not a flashy UI, but it does demonstrate everything about this article. The code is commented, and hopefully gives enough information for helping you put your own solution together.

    Acknowledgements

    I would like to thank the following persons that made part of this article possible:

    • The technique for DWebBrowserEvents2 was in the bug list of Microsoft .NET 2.0. This has been used with modification.
    • The technique for WndProc was told by someone called "JoeBlow" on the MSDN forums, who had it derived from the MSKB article #253219.

    This is my first article on The Code Project. Please excuse me for my English. Thanks for reading! If you can add anything or have suggestions or tips, please post a message below.

    License

    This code is copyrighted by The Wheel Automatisering in The Netherlands. Some rights are reserved.

    The code in this license may be used for any purpose, just let your users know where it came from, and share derived code under the same license as this one. Don't blame me if something goes wrong. More information can be found here.

    If you wish to use and/or publish this in commercial closed-source applications, you have my consent. You may use this code under your own license when you do so.

    History

    • 27th of March 2006: First post of this article.

    About Jeroen Landheer


    I am
    - born in The Netherlands
    - living in Chile together with my wife.
    - a Microsoft Certified Professional Developer on all 3 areas (Windows, Web and Enterprise)
    - an MCITP on Microsoft SQL Server 2005 (Database Administrator)
    - an active programmer for about 14 years.
    - a business owner, of a Dutch company called "The Wheel Automatisering" (http://www.thewheel.nl)
    - a coder in C#, VB.Net and Managed C++.
    - someone who likes to share knowledge

    For fun I like to go out with my dogs, enjoy the sun or write some articles that I share with the community.

    Click here to view Jeroen Landheer's online profile.

    posted on 2007-11-20 13:27 CowNew開源團隊 閱讀(1759) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 免费在线观影网站| 男女超爽视频免费播放| AAA日本高清在线播放免费观看| heyzo亚洲精品日韩| 男男gay做爽爽的视频免费| 日产国产精品亚洲系列| 无码免费又爽又高潮喷水的视频 | 毛片网站免费在线观看| 国产免费AV片在线观看| 亚洲乱色熟女一区二区三区丝袜| 中文字幕在线视频免费| 亚洲第一精品福利| 国产大片91精品免费观看不卡| 亚洲第一福利网站在线观看| 免费人人潮人人爽一区二区| 怡红院亚洲怡红院首页| 久久精品国产影库免费看| 久久久久亚洲av无码专区喷水| 四虎成年永久免费网站| 亚洲另类自拍丝袜第五页| 亚洲精品久久久www| 国产成人AV免费观看| 亚洲国产日产无码精品| 国产精品免费看久久久无码| 一级午夜a毛片免费视频| 亚洲AV本道一区二区三区四区| 国产成人免费网站| 日日躁狠狠躁狠狠爱免费视频| 香蕉蕉亚亚洲aav综合| 精品少妇人妻AV免费久久洗澡| 五月天国产成人AV免费观看| 亚洲天堂一区二区| 免费观看久久精彩视频| 亚洲精品中文字幕无乱码麻豆| 日本一道在线日本一道高清不卡免费| 丰满妇女做a级毛片免费观看| 亚洲国产精品热久久| 免费看香港一级毛片| 久久精品免费观看| 亚洲1区2区3区精华液| 亚洲国产高清人在线|