在cefsharp中拦截对window.frameElement的调用

时间:2018-01-10 08:52:44

标签: c# cefsharp

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

该页面使用window.frameElement与其父窗口进行交互,并在window.frameElement上调用某个函数。

在CefSharp中,我无法删除window.frameElement

还有其他方法可以知道页面何时在window.frameElement上调用某个函数。

1 个答案:

答案 0 :(得分:1)

这将是相当hacky,但我无论如何分享。我创建了一个对我有用的简单示例,我希望它也能为您提供帮助。

JavaScript方面只是一个普通的HTML,带有一个按钮,可以在点击时调用事件处理程序:

<强>的index.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):

<强> app.js

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

C#端有一个ChromiumWebBrowser指向我页面的地址:

<强> Form1.Designer.cs

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);
            };
        }
    });
})();");
    }
}

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

我注入的自定义逻辑是使用被调用函数的名称和传入的参数调用frameElementInterceptor的{​​{1}}方法。

回到C#方面,我们使用CEFSharp浏览器注册一个JS对象,并在JS的全局范围内将其作为intercept提供:

frameElementInterceptor

现在所有部分都已到位,每当我点击页面中的按钮时,我的C#拦截器都会收到消息:

MessageBox from C#

警告:虽然这个简单的例子有效,但我确信这里没有考虑各种边缘情况,所以我会非常谨慎地将它投入生产。 此外,我认为更好的解决方案将涉及CefSharp方面的代码更改。他们可以注册从[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()); } 派生的类型,并启用覆盖DynamicObject上的现有对象(如window)。据我所知,自this question以来没有任何进展。