在 cefsharp 中拦截对 window.frameElement 的调用
Intercept calls to window.frameElement in cefsharp
在我的 WinForms 项目中,我正在打开一个 CefSharp 浏览器并加载一个不受我控制的外部 url。通常,此 URL 在外部应用程序中作为 iframe 打开。
该页面使用 window.frameElement
与其父 window 交互,并在 window.frameElement
上调用一些函数。
在 CefSharp 中,我无法删除 window.frameElement
。
有没有其他方法可以知道页面何时调用了 window.frameElement
上的某个函数。
这会很麻烦,但无论如何我都会分享。我创建了一个对我有用的简单示例,希望它对您也有帮助。
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 代码注入 main/top 框架(我们的主页):
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对象,并在JS的全局范围内以frameElementInterceptor
的形式提供:
[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# 拦截器都会收到消息:
警告:虽然这个简单的例子可行,但我确信这里没有考虑各种边缘情况,所以我会非常谨慎地将其投入生产.
此外,我认为更好的解决方案将涉及 CefSharp 方面的代码更改。他们可以启用从 DynamicObject
派生的类型的注册,并启用覆盖 window
上的现有对象(如 frameElement
)。据我所知,自 this question.
以来,这方面没有任何进展
在我的 WinForms 项目中,我正在打开一个 CefSharp 浏览器并加载一个不受我控制的外部 url。通常,此 URL 在外部应用程序中作为 iframe 打开。
该页面使用 window.frameElement
与其父 window 交互,并在 window.frameElement
上调用一些函数。
在 CefSharp 中,我无法删除 window.frameElement
。
有没有其他方法可以知道页面何时调用了 window.frameElement
上的某个函数。
这会很麻烦,但无论如何我都会分享。我创建了一个对我有用的简单示例,希望它对您也有帮助。
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 代码注入 main/top 框架(我们的主页):
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对象,并在JS的全局范围内以frameElementInterceptor
的形式提供:
[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# 拦截器都会收到消息:
警告:虽然这个简单的例子可行,但我确信这里没有考虑各种边缘情况,所以我会非常谨慎地将其投入生产.
此外,我认为更好的解决方案将涉及 CefSharp 方面的代码更改。他们可以启用从 DynamicObject
派生的类型的注册,并启用覆盖 window
上的现有对象(如 frameElement
)。据我所知,自 this question.