代码之家  ›  专栏  ›  技术社区  ›  Jigar

拦截对窗口的调用。cefsharp中的frameElement

  •  1
  • Jigar  · 技术社区  · 8 年前

    在我的WinForms项目中,我打开一个CefSharp浏览器并加载一个不在我控制范围内的外部url。通常,此URL在外部应用程序中作为iframe打开。

    页面使用与其父窗口交互 window.frameElement 并调用一些函数 窗frameElement框架元素 .

    在CefSharp,我无法退出 窗frameElement框架元素 .

    有没有其他方法可以知道页面何时调用了 窗frameElement框架元素 .

    1 回复  |  直到 8 年前
        1
  •  2
  •   Szabolcs Dézsi    8 年前

    这将是相当骇客,但我分享无论如何。我创建了一个简单的例子,对我很有用,我希望它也能帮助你。

    JavaScript端只是一个普通的HTML,带有一个按钮,点击后调用事件处理程序:

    指数html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Test</title>
    
        <script src="app.js"></script>
    </head>
    <body>
        <button onclick="onClick()">Click me</button>
    </body>
    </html>
    

    事件处理程序只调用一个随机函数(甚至不必存在于 frameElement )带有一些参数:

    应用程序。js公司

    function onClick() {
        var x = window.frameElement.greet("Hello", "world");
    }
    

    C侧具有 ChromiumWebBrowser 指向我的页面地址:

    Form1.Designer。反恐精英

    this.browser = new CefSharp.WinForms.ChromiumWebBrowser("http://localhost:3000/index.html");
    

    我订阅 FrameLoadEnd 事件:

    this.browser.FrameLoadEnd += BrowserOnFrameLoadEnd;
    

    处理程序将一些JavaScript代码注入主/顶部框架(我们的主页):

    Form1.cs

    private void BrowserOnFrameLoadEnd(object sender, FrameLoadEndEventArgs frameLoadEndEventArgs)
    {
        if (frameLoadEndEventArgs.Frame.IsMain)
        {
            frameLoadEndEventArgs.Frame.ExecuteJavaScriptAsync(@"
    (function() {
        Object.defineProperty(window, 'frameElement', {
            writable: true
        });
    
        window.frameElement = {};
    
        window.frameElement = new Proxy(window.frameElement, {
            get: function (target, propKey, receiver) {
                return function(...args) {
                    window.frameElementInterceptor.intercept(propKey, args);
                };
            }
        });
    })();");
        }
    }
    

    注入的代码修改 window.frameElement 使用 ES6 Proxy . 当原始页面 window.frameElement.someMethod(arg1, arg2) 我可以注入自定义逻辑。

    我注入的自定义逻辑是调用 frameElementInterceptor intercept 方法,其中包含调用的函数名和传入的参数。

    回到C端,我们在CEFSharp浏览器中注册了一个JS对象,并将其作为 frameElementInterceptor框架元素拦截器 关于JS中的全局范围:

    [ComVisible(true)]
    public class FrameElementInterceptor
    {
        public void Intercept(string propKey, object[] args)
        {
            MessageBox.Show($@"Function '{propKey}' was called with arguments: [{string.Join(", ", args)}]",
    @"Function call intercepted");
        }
    }
    
    public Form1()
    {
        InitializeComponent();
    
        // .....
    
        browser.RegisterJsObject("frameElementInterceptor", new FrameElementInterceptor());
    }
    

    现在所有的部分都准备好了,每当我单击页面中的按钮时,我的C#拦截器就会收到消息:

    MessageBox from C#

    警告 :虽然这个简单的示例有效,但我确信这里没有考虑各种边缘情况,因此我会非常谨慎地将其投入生产。 此外,我认为更好的解决方案将涉及CefSharp方面的代码更改。它们可以注册派生自 DynamicObject 并启用覆盖上的现有对象 window (如 frameElement框架元素 ). 据我所知,自 this question .