Chromium CeF3. Net encapsulation (customized browser)

Source: Internet
Author: User

The first time I wrote an article in the blog, I 'd like to share with you some. Net Package versions about chromium.

One and a half years after I graduated from school, I mainly engaged in. net, winform, Asp.net, and MVC. During this period, a project was maintained, and the Web site project was displayed using the webbrowser of winform to provide a better user experience. Later I heard about HTML5 and would like to try it. But since webbrowser adopts the IE kernel, what is the solution. I found a bunch of browser-related information and learned a lot. For example, chrome frame cannot be combined with webbrowser. Firefox's gecko binary feels redundant and does not continue. Later, we can see that chromium with V8 engine is fast in executing JavaScript, and binary is also very streamlined. The code Looks refreshing and I like it very much. So I used it.

After the integration of data and third-party code, this project was established.

1. The cefglue project is an encapsulation of libcef. dll (libcef. dll is the core of chromium. It can be compiled from the Svn of the open-source project chromium. the version I compiled is 1045)

2. the CEF. Demo project references the cefglue project. It mainly calls the API encapsulated by cefglue on libcef. dll and encapsulates a webbrowser base class.

3. CEF. Demo. Common is the help class library.

4. CEF. Demo. winforms (winform Main Program)

The following is the CEF. Demo project

Among them, democefapp is the core of the CeF3 application. It is in charge of two types of processes. One type of process is the browser process, which has a series of events for rewriting,

There is a V8 engine context initialization completion event. The Code is as follows:

// V8 engine Initialization is complete. You can override protected virtual void oncontextinitialized (){}

Also, when the render process (the render process will be discussed below) is created, the Code is as follows:

// When a new rendering process is created, you can override protected virtual void onrenderprocessthreadcreated (ceflistvalue extrainfo ){}

Another type of process is the render process, which also has many events for rewriting. When you open chrome to browse the Web page, you will find that there are sometimes many chrome processes in task management, the more processes are the render process. Every time you open a new tab or page, the webpage it carries will create a new process, that is, the render process. When you close a tab or page, the process will be killed and resources will be recycled again.

There is an event that the process has been created.

// When the render process is created, you can override protected virtual void onrenderthreadcreated (ceflistvalue extrainfo ){}

There are two other events in the lifecycle of the process.

// When the browser is created, you can override protected virtual void onbrowsercreated (cefbrowser browser) {}// call protected virtual void onbrowserdestroyed (cefbrowser browser ){}

There are events before the browser jump

// Rewritable
Protected virtual bool onbeforenavigation (cefbrowser browser, cefframe frame, cefrequest request, cefnavigationtype navigationtype, bool isredirect) {// by default, false redirection is allowed. Otherwise, false redirection is blocked ;}

Event when page JavaScript context is created

// Rewrite the JavaScript context when it is created
Protected virtual void oncontextcreated (cefbrowser browser, cefframe frame, cefv8context context ){}

The above examples illustrate these events. In fact, these events can also be visually understood as the custom homepage in the blog, and the compilation of an HTML code makes it richer and more beautiful, this is what we want. I don't need to know how the blog garden changed the code I entered on my homepage, but I only need to write the HTML code and footer of the page header separately and hand it over to the blog garden. Libcef. dll can also be regarded as a "blog Garden ".

The above code shows two commonly used classes, cefbrowser and cefframe. below is the code

  public sealed unsafe partial class CefBrowser    {        public CefBrowserHost GetHost()        {            return CefBrowserHost.FromNative(                cef_browser_t.get_host(_self)                );        }        public bool CanGoBack        {            get { return cef_browser_t.can_go_back(_self) != 0; }        }        public void GoBack()        {            cef_browser_t.go_back(_self);        }        public bool CanGoForward        {            get { return cef_browser_t.can_go_forward(_self) != 0; }        }        public void GoForward()        {            cef_browser_t.go_forward(_self);        }        public bool IsLoading        {            get { return cef_browser_t.is_loading(_self) != 0; }        }        public void Reload()        {            cef_browser_t.reload(_self);        }        public void ReloadIgnoreCache()        {            cef_browser_t.reload_ignore_cache(_self);        }        public void StopLoad()        {            cef_browser_t.stop_load(_self);        }        public int Identifier        {            get { return cef_browser_t.get_identifier(_self); }        }        public bool IsSame(CefBrowser that)        {            if (that == null) return false;            return cef_browser_t.is_same(_self, that.ToNative()) != 0;        }        public bool IsPopup        {            get { return cef_browser_t.is_popup(_self) != 0; }        }        public bool HasDocument        {            get { return cef_browser_t.has_document(_self) != 0; }        }        public CefFrame GetMainFrame()        {            return CefFrame.FromNative(                cef_browser_t.get_main_frame(_self)                );        }        public CefFrame GetFocusedFrame()        {            return CefFrame.FromNative(                cef_browser_t.get_focused_frame(_self)                );        }        public CefFrame GetFrame(long identifier)        {            return CefFrame.FromNativeOrNull(                cef_browser_t.get_frame_byident(_self, identifier)                );        }        public CefFrame GetFrame(string name)        {            fixed (char* name_str = name)            {                var n_name = new cef_string_t(name_str, name.Length);                return CefFrame.FromNativeOrNull(                    cef_browser_t.get_frame(_self, &n_name)                    );            }        }        public int FrameCount        {            get { return (int)cef_browser_t.get_frame_count(_self); }        }        public long[] GetFrameIdentifiers()        {            var frameCount = FrameCount;            var identifiers = new long[frameCount];            UIntPtr n_count = (UIntPtr)frameCount;            fixed (long* identifiers_ptr = identifiers)            {                cef_browser_t.get_frame_identifiers(_self, &n_count, identifiers_ptr);                if ((int)n_count != frameCount) throw new InvalidOperationException(); // FIXME: ...            }            return identifiers;        }        public string[] GetFrameNames()        {            var list = libcef.string_list_alloc();            cef_browser_t.get_frame_names(_self, list);            var result = cef_string_list.ToArray(list);            libcef.string_list_free(list);            return result;        }        public bool SendProcessMessage(CefProcessId target, CefProcessMessage message)        {            if (message == null) throw new ArgumentNullException("message");            return cef_browser_t.send_process_message(_self, target, message.ToNative()) != 0;        }    }
  public sealed unsafe partial class CefFrame    {        public bool IsValid        {            get { return cef_frame_t.is_valid(_self) != 0; }        }        public void Undo()        {            cef_frame_t.undo(_self);        }        public void Redo()        {            cef_frame_t.redo(_self);        }        public void Cut()        {            cef_frame_t.cut(_self);        }        public void Copy()        {            cef_frame_t.copy(_self);        }        public void Paste()        {            cef_frame_t.paste(_self);        }        public void Delete()        {            cef_frame_t.del(_self);        }        public void SelectAll()        {            cef_frame_t.select_all(_self);        }        public void ViewSource()        {            cef_frame_t.view_source(_self);        }        public void GetSource(CefStringVisitor visitor)        {            if (visitor == null) throw new ArgumentNullException("visitor");            cef_frame_t.get_source(_self, visitor.ToNative());        }        public void GetText(CefStringVisitor visitor)        {            if (visitor == null) throw new ArgumentNullException("visitor");            cef_frame_t.get_text(_self, visitor.ToNative());        }        public void LoadRequest(CefRequest request)        {            if (request == null) throw new ArgumentNullException("request");            cef_frame_t.load_request(_self, request.ToNative());        }        public void LoadUrl(string url)        {            fixed (char* url_str = url)            {                var n_url = new cef_string_t(url_str, url != null ? url.Length : 0);                cef_frame_t.load_url(_self, &n_url);            }        }        public void LoadString(string content, string url)        {            fixed (char* content_str = content)            fixed (char* url_str = url)            {                var n_content = new cef_string_t(content_str, content != null ? content.Length : 0);                var n_url = new cef_string_t(url_str, url != null ? url.Length : 0);                cef_frame_t.load_string(_self, &n_content, &n_url);            }        }        public void ExecuteJavaScript(string code, string url, int line)        {            fixed (char* code_str = code)            fixed (char* url_str = url)            {                var n_code = new cef_string_t(code_str, code != null ? code.Length : 0);                var n_url = new cef_string_t(url_str, url != null ? url.Length : 0);                cef_frame_t.execute_java_script(_self, &n_code, &n_url, line);            }        }        public bool IsMain        {            get { return cef_frame_t.is_main(_self) != 0; }        }        public bool IsFocused        {            get { return cef_frame_t.is_focused(_self) != 0; }        }        public string Name        {            get            {                var n_result = cef_frame_t.get_name(_self);                return cef_string_userfree.ToString(n_result);            }        }        public long Identifier        {            get { return cef_frame_t.get_identifier(_self); }        }        public CefFrame Parent        {            get            {                return CefFrame.FromNativeOrNull(                    cef_frame_t.get_parent(_self)                    );            }        }        public string Url        {            get            {                var n_result = cef_frame_t.get_url(_self);                return cef_string_userfree.ToString(n_result);            }        }        public CefBrowser Browser        {            get            {                return CefBrowser.FromNative(                    cef_frame_t.get_browser(_self)                    );            }        }        public CefV8Context V8Context        {            get            {                return CefV8Context.FromNative(                    cef_frame_t.get_v8context(_self)                    );            }        }        public void VisitDom(CefDomVisitor visitor)        {            if (visitor == null) throw new ArgumentNullException("visitor");            cef_frame_t.visit_dom(_self, visitor.ToNative());        }    }

Cefframe can be considered as an IFRAME with a global object and a script context. A page has at least one cefframe, which is equivalent to cefbrowser. That is, their relationship is that cefbrowser has at least one cefframe, and a cefframe must survive under cefbrowser.

After introducing the above, there is another one that must be mentioned, that is, WebClient. If democefapp is the master and has everything, then WebClient is the manager.

The WebClient receives communication messages between two processes. The Code is as follows:

// Rewritable
Protected virtual bool onprocessmessagereceived (cefbrowser browser, cefprocessid sourceprocess, cefprocessmessage message) {return false ;}

The cefprocessid is as follows:

    public enum CefProcessId    {        Browser,        Renderer,    }

The message sending method public bool sendprocessmessage (cefprocessid target, cefprocessmessage message) in cefbrowser is referenced by such an instance on the master thread of both processes. When you call some events, you can use these two methods to easily send and receive messages between different processes.

WebClient also contains a lot of detailed rewritable methods.

For example, the following method

       protected virtual CefRequestHandler GetRequestHandler()        {            return null;        }

After the custom cefrequesthandler is defined, we can return the custom cefrequesthandler object. Every time we plan to request, we can process the request, and then send the request through the line after processing, you can even cancel sending this time.

Next let's take a look at the custom webbrowser. Since cefbrowser has previously been defined as the sealed type, I no longer inherit it. I only use it as an attribute for ease of use. Similarly, I also need a butler WebClient to communicate between processes and support request, load, and so on, in order to make my webbrowser provide more required functions. Below is the code

  public sealed class WebBrowser    {        private readonly object _owner;        private readonly CefBrowserSettings _settings;        private string _startUrl;        private CefClient _client;        private CefBrowser _browser;        private IntPtr _windowHandle;        private bool _created;        public WebBrowser(object owner, CefBrowserSettings settings, string startUrl)        {            _owner = owner;            _settings = settings;            _startUrl = startUrl;        }        public string StartUrl        {            get { return _startUrl; }            set { _startUrl = value; }        }        public CefBrowser CefBrowser        {            get { return _browser; }        }        public void Create(CefWindowInfo windowInfo)        {            if (_client == null)            {                _client = new WebClient(this);            }            CefBrowserHost.CreateBrowser(windowInfo, _client, _settings, StartUrl);        }        public event EventHandler Created;        internal void OnCreated(CefBrowser browser)        {            if (_created) throw new InvalidOperationException("Browser already created.");            _created = true;            _browser = browser;            var handler = Created;            if (handler != null)            {                handler(this, EventArgs.Empty);            }        }        internal void Close()        {            if (_browser != null)            {                _browser.Dispose();                _browser = null;            }        }        public event EventHandler<TitleChangedEventArgs> TitleChanged;        internal void OnTitleChanged(string title)        {            var handler = TitleChanged;            if (handler != null)            {                handler(this, new TitleChangedEventArgs(title));            }        }        public event EventHandler<AddressChangedEventArgs> AddressChanged;        internal void OnAddressChanged(string address)        {            var handler = AddressChanged;            if (handler != null)            {                handler(this, new AddressChangedEventArgs(address));            }        }        public event EventHandler<TargetUrlChangedEventArgs> TargetUrlChanged;        internal void OnTargetUrlChanged(string targetUrl)        {            var handler = TargetUrlChanged;            if (handler != null)            {                handler(this, new TargetUrlChangedEventArgs(targetUrl));            }        }        public event EventHandler<LoadingStateChangedEventArgs> LoadingStateChanged;        internal void OnLoadingStateChanged(bool isLoading, bool canGoBack, bool canGoForward)        {            var handler = LoadingStateChanged;            if (handler != null)            {                handler(this, new LoadingStateChangedEventArgs(isLoading, canGoBack, canGoForward));            }        }        public event EventHandler<BeforeResourceLoadedEventArgs> BeforeResourceLoaded;        internal void OnBeforeResourceLoaded(CefRequest request, long frameIdentifier)        {            var handler = BeforeResourceLoaded;            if (handler != null)            {                handler(this, new BeforeResourceLoadedEventArgs(request, frameIdentifier));            }        }    }

Many custom events are used. For example, the custom cefrequesthandler sends a signal to the custom webbrowser when processing a specific request, so the event method is used.

It's too late today... I plan to share it next time

You can take a look at several.

The following is a reference to the above project in winform. It uses a third-party razor view engine to meet the needs of offline and online applications.

Let's take a look at the running effect.

After successful login (asynchronous login is an Ajax method that captures Ajax requests and uses jquery .. Surprised to find that the request method is options, not post or get. No wonder it was not captured at the beginning. This is an episode)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.