zoukankan      html  css  js  c++  java
  • 基于Chromium构建Chrome WebBrowser for .net 控件(还有点心得体会)

    http://blog.csdn.net/lllllllllluoyi/article/details/8540054

    首先向360说句sorry,在2011年360极速浏览器出现的时候我去他们论坛里骂过。为什么要到歉呢,因为2012年我把我们公司使用IE WebBrowser改为Chrome控件了,中间遇到的辛酸使我明白360公司能做成产品确实不容易。言归正转,公司的壳程序是C#编写的WinForm程序,刚开始我只找到delphi的Chromium项目,然后在delphi2010中安装好控件后就生成DLL让WinForm程序调用,这种策略是我做这个控件的最大失败。因为我对delphi比较熟,很快控件就能在WinForm程序里跑起来了,很开心,立马根据壳中已经使用的事件和方法在自定义控件中实现,自测一下没有问题后就交给测试人员来试用,半天的功夫,测试员小张就来对我说:罗兄,网页中不能使用键盘上Tab键切换,回车事件响应不了......不会吧,是不是焦点没有定位到自定义控件中,我第一时间就是这样想,然后就是反复的折腾,还是不行。最后Google了一下,好不容易找到一个让自己信服的答案,就是win32的消息循环机制与.net消息机制不一样,嵌入到WinForm中的VCL控件不能得到消息。我靠,这还得了,leader还不把我劈了,leader已经吩咐美工全按chrome浏览器的样式来写了。兵来将挡,水来土淹,我火速Google一个能在.net上跑的版本“CefSharp”  ,下载来看,傻眼了,是C++版的,咋办?熬夜啃吧!

    我分为了两个项目,一是libfuncs,为了使DLL名称一致,我重命名了CefSharp项目,它负责提供操作浏览器的方法和触发事件;二是cwber,它是自定义的WinForm控件,用于在Form上的布局,必须引用libfuncs.dll。

    源码地址:https://sourceforge.net/projects/chromewebbrowse

    cwber比较简单,以下是它的代码:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Data;
    using System.Text;
    using System.Windows.Forms;
    using libfuncs;
    
    namespace cwber
    {
        public partial class ChromeWebBrowser : UserControl
        {
            private ChromeApp chrome = null;
            ToolTip myToolTip = new ToolTip();
            public ChromeWebBrowser()
            {
                InitializeComponent();
                ChromeWebBrowser.CheckForIllegalCrossThreadCalls = false;
            }
            
          
    
            private void ChromeWebBrowser_Load(object sender, EventArgs e)
            {
                if (chrome == null)
                {
                    chrome = new ChromeApp();
                }
                Start();
                
            }
    
            #region 外部调用方法
            libfuncs.DocumentCompletedEvent elementEvent1;
            libfuncs.FrameLoadStartEvent elementEvent2;
            libfuncs.FrameLoadEndEvent elementEvent3;
            libfuncs.FileDownloadingEvent fileDownloading;
            libfuncs.FileDownloadCompletedEvent fileDownloaded;
            libfuncs.ComponentInitialized componentInitialized;
            libfuncs.ToolTipEventListener toolTipEvent;
            public void Start()
            {
                if (chrome != null)
                {
                    chrome.Dock = DockStyle.Fill;
                    
                    if (componentInitialized == null)
                    {
                        componentInitialized = new libfuncs.ComponentInitialized(componentInitializedEvent);
                        chrome.RegisterEvent(componentInitialized);
                    }
                    Controls.Add(chrome);
                    if (elementEvent1 == null)
                    {
                        elementEvent1 = new libfuncs.DocumentCompletedEvent(documentComplete);
                        chrome.RegisterEvent(elementEvent1);
                    }
                    if (elementEvent2 == null)
                    {
                        elementEvent2 = new libfuncs.FrameLoadStartEvent(frameStartStart);
                        chrome.RegisterEvent(elementEvent2);
                    }
                    if (elementEvent3 == null)
                    {
                        elementEvent3 = new libfuncs.FrameLoadEndEvent(frameLoadEnd);
                        chrome.RegisterEvent(elementEvent3);
                    }
                    if (fileDownloading == null)
                    {
                        fileDownloading = new libfuncs.FileDownloadingEvent(this.downloading);
                        chrome.RegisterEvent(fileDownloading);
                    }
                    if (fileDownloaded == null)
                    {
                        fileDownloaded = new libfuncs.FileDownloadCompletedEvent(this.downloaded);
                        chrome.RegisterEvent(fileDownloaded);
                    }
                    if (toolTipEvent == null)
                    {
                        toolTipEvent = new libfuncs.ToolTipEventListener(this.ShowToolTipText);
                        chrome.RegisterEvent(toolTipEvent);
                    }
                    
                    chrome.Visible = true;
                    chrome.BringToFront();
                }
            }
            /*
             * 描述:释放浏览器
             */
            public void Free()
            {
                elementEvent1 = null;
                elementEvent2 = null;
                elementEvent3 = null;
                fileDownloading = null;
                fileDownloaded = null;
                componentInitialized = null;
                toolTipEvent = null;
                chrome.Dispose();
                chrome = null;
            }
            /*
             * 参数:Url 打开网页地址
             * 描述:打开网址。
             */
            public void OpenUrl(string Url)
            {
                if (chrome != null)
                    chrome.Load(Url);
            }
            /*
             * 参数:id 网页中的控件元素ID
             * 描述:根据元素ID获取元素的值,适用于Input,A标签元素
             */
            public string GetElementValueById(string id)
            {
                return chrome == null ? "" : chrome.GetElementValueById(id);
            }
            /*
             * 参数:id 网页中的控件元素ID, value 元素新值
             * 描述:为页面中元素赋予新值。
             */
            public void SetElementValueById(string id, string value)
            {
                if (chrome != null)
                {
                    chrome.SetElementValueById(id, value);
                }
            }
    
            public delegate void TCallBackElementEventListener();
            private List<libfuncs.ElementEventListener> elementEventList = new List<libfuncs.ElementEventListener>();
            /*
             * 描述:附加元素的侦听事件。当该元素触发附加事件时,则执行TCallBackElementEventListener委托方法
             */
            public void AppendElementEventListener(string id, string eventName, TCallBackElementEventListener callFunc)
            {
                libfuncs.ElementEventListener elementEvent = new libfuncs.ElementEventListener(callFunc);
                elementEventList.Add(elementEvent);
                chrome.AddElementEventListener(id, eventName, elementEvent);
            }
            /*
             * 描述:向页面中注入并执行脚本。
             */
            public void ExecuteScript(string script)
            {
                if (chrome != null)
                    chrome.ExecuteScript(script);
            }
    
            public object EvaluateScript(string script)
            {
                if (chrome != null)
                    return chrome.EvaluateScript(script);
                else
                    return null;
            }
    
            /*
             * 描述:计算文件单位。用于文件下载。
             */
            private string CompareFileSize(Int64 size)
            {
                //计算K,M单位
                string strTotalSize = string.Empty;
                if (size < 1024)
                {
                    strTotalSize = size.ToString() + " B";
                }
                else if (size >= 1024 && size < 1024 * 1024)
                {
                    strTotalSize = (size / 1024).ToString() + " KB";
                }
                else
                {
                    strTotalSize = (size / 1024 / 1024).ToString() + " MB";
                }
                return strTotalSize;
            }
    
            #endregion
    
            #region 属性
            public string Url
            {
                get
                {
                    return chrome == null?"":chrome.Core.Address;
                }
            }
            #endregion
    
            #region 事件
            /*控件初始化事件*/
            public event EventHandler ComponentInitializedEventHandler;
            private void componentInitializedEvent()
            {
                EventArgs e = new EventArgs();
                if (ComponentInitializedEventHandler != null)
                    ComponentInitializedEventHandler(this, e);
            }
            /*页面加载完成事件*/
            public event EventHandler DocumentCompletedEventHandler;
            private void documentComplete()
            {
                EventArgs e = new EventArgs();
                if (DocumentCompletedEventHandler != null)
                    DocumentCompletedEventHandler(this, e);
            }
            /*Frame加载完成事件,这里的Frame可以是页面本身,也是iFrame元素*/
            public event EventHandler PageLoadFinishEventHandler;
            private void frameLoadEnd()
            {
                EventArgs e = new EventArgs();
                if (PageLoadFinishEventHandler != null)
                    PageLoadFinishEventHandler(this, e);
            }
            /*Frame加载开始事件,这里的Frame可以是页面本身,也是iFrame元素*/
            public event EventHandler PageLoadStartEventHandler;
            private void frameStartStart()
            {
                EventArgs e = new EventArgs();
                if (PageLoadStartEventHandler != null)
                    PageLoadStartEventHandler(this, e);
            }
            /*下载中事件,不开放该事件*/
            Form downloadForm = null;
            private void downloading(Int64 totalSize, Int64 loadedSize)
            {
                string strTotalSize = CompareFileSize(totalSize);
                string strLoadedSize = CompareFileSize(loadedSize);
    
                if (downloadForm == null)
                {
                    downloadForm = new Form();
                    downloadForm.Text = "下载中";
                    downloadForm.Width = 280;
                    downloadForm.Height = 150;
                    downloadForm.MaximizeBox = false;
                    downloadForm.MinimizeBox = false;
                    downloadForm.ControlBox = false;
                    downloadForm.StartPosition = FormStartPosition.CenterScreen;
                    
    
                    Label label = new Label();
                    label.Left = 20;
                    label.Top = 50;
                    label.Width = 250;
                    label.Text = "已下载:" + strLoadedSize + "/" + strTotalSize;
                    downloadForm.Controls.Add(label);
                }
                downloadForm.Show();
                downloadForm.BringToFront();
                foreach (Control c in downloadForm.Controls)
                {
                    if (c is Label)
                    {
                        Label label = (Label)c;
                        label.Text = "已下载:" + strLoadedSize + "/" + strTotalSize;
                        label.Update();
                    }
                }
                downloadForm.Update();
            }
            /*下载完成事件,不开放该事件*/
            private void downloaded()
            {
                if (downloadForm != null)
                    downloadForm.Close();
                downloadForm = null;
            }
            /*消息提示事件,不开放*/
            private void ShowToolTipText(string text)
            {
                if (chrome == null) return;
                if (string.IsNullOrEmpty(text))
                {
                    myToolTip.RemoveAll();
                    return;
                }
                //保证每行40个字
                int len = text.Length;
                int offset = 40;
                int count = len / offset;
                for (int i = 1; i <= count; i++)
                {
                    text = text.Insert(offset * i, "
    ");
                }
                myToolTip.ShowAlways = false;
                myToolTip.UseAnimation = true;
                myToolTip.UseFading = true;
                //t.SetToolTip(button1, text);
                Point p = Control.MousePosition;
                Point p1 = this.PointToClient(p);
                myToolTip.Show(text, chrome, p1.X+20, p1.Y+10);
            }
            #endregion
        }
    }


    重点是libfuncs中的libfuncs.h、ChromeApp.h、ChromeApp.cpp、ClientAdapter.h、ClientAdapter.cpp五个文件,实现方法都在里面,其他的文件基本都是接口文件。我自己只根据项目实际需求来做的功能,接口没有全部实现。这个部分大家看源代码吧,我用到的地方都注释了。文采不行,写不动,大家原谅。睡了。

    最后说句,我们公司网页美工解脱了!

  • 相关阅读:
    多线程编程(一)
    所谓费曼学习法
    Java 基本数据类型扩充
    好记性不如烂笔头
    Java_面试札记
    Stream替代for-编码五分钟-划水五小时
    为什么启动线程是start方法?
    Java面试札记
    Tree
    手写SpringMVC 框架
  • 原文地址:https://www.cnblogs.com/MaxWoods/p/4124856.html
Copyright © 2011-2022 走看看