使用CefSharp WPF在C#上执行JavaScript会导致错误

Raf*_*ael 11 javascript c# wpf cefsharp

每当我尝试使用CefSharp(Stable 57.0)通过C#执行JavaScript时,我都会收到错误消息.我只是尝试执行警报功能,所以我可以确保它可以工作,然后用我自己的函数测试它.但是,我似乎在尝试这样做时遇到错误.

public partial class WebBrowserWindow : Window
{
    public WebBrowserWindow()
    {
        InitializeComponent();
        webBrowser.MenuHandler = new ContextMenuHandler();
        webBrowser.RequestHandler = new RequestHandler();
    }

    //Trying to execute this with either method gives me an error.
    public void ExecuteJavaScript()
    {
        //webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");

        //webBrowser.ExecuteScriptAsync("alert('test');");
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试了两种执行脚本的方法.

第一个:

webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");
Run Code Online (Sandbox Code Playgroud)

给我这个错误:

在此输入图像描述

第二:

webBrowser.ExecuteScriptAsync("alert('test');");
Run Code Online (Sandbox Code Playgroud)

给我这个错误:

在此输入图像描述

我的目标是创建一个可以在我的CefSharp浏览器中执行JavaScript函数的C#函数.

我尝试了很多链接/引用,堆栈溢出并没有那么多.我还阅读了CefSharp的FAQ,找不到任何允许我通过C#随意执行JavaScript的简单示例.

另外,我已经验证了加载Frame的事件(它完成加载)和卸载(它没有卸载),如果webbrowser为null(它不是),以及来自:的消息:

webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");
Run Code Online (Sandbox Code Playgroud)

仍会导致第一个错误发生.

我测试了GetMainFrame().它总是返回null.总是.无论我等待多久,或者我检查的条件.

重要

我忘记添加一条关键信息,我的项目中有2个程序集.它们都编译成单独的可执行文件:

Helper.exe Main.exe

main.exe有一个窗口"CallUI",当单击一个按钮时,它会执行我创建的"ExecuteJavaScript()"方法,它位于我的窗口"BrowserWindow"中.CallUI窗口在Helper.exe中声明并初始化.

所以基本上我试图使用单独的程序打开一个窗口,单击一个调用该方法并执行javascript的按钮.所以我认为因为它们是不同的进程,它告诉我浏览器是null.但是,当我在Main.exe中完成所有操作时,它可以正常工作.是否有一种解决方法允许我使用单独的进程从Helper.exe创建窗口并从Main.exe执行Javascript?

Raf*_*ael 5

我注意到我处理问题的方式是错误的。

事实上,如果它只是一个将所有代码保存在一起的单个进程,我的问题就不存在。但是,我的项目有一个试图与另一个项目通信的可执行文件这一事实是问题所在。我实际上从来没有办法让我的 helper.exe 适当地与我的 main.exe 对话。

我从中学到的是,这些进程试图在没有任何共享地址访问的情况下相互交谈。它们位于不同的地址空间中,因此每当我的 helper.exe 尝试执行属于 Main.exe 的 javascript 部分时,它都会尝试在属于其自己的地址空间而非主浏览器的未初始化版本中执行该脚本。可执行程序。

那么我是如何解决这个问题的呢?我必须包含一个重要的部分,它允许 helper.exe 进程与 main.exe 进程对话。当我搜索进程如何相互通信时,我发现了 MemoryMappedFiles。所以我决定在我的程序中实现一个简单的例子,它允许 Helper.exe 向 Main.exe 发送消息。

这是示例。这是我创建的名为“MemoryMappedHandler.cs”的文件

public class MemoryMappedHandler
{
    MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen("mmf1", 512);
    MemoryMappedViewStream stream;
    MemoryMappedViewAccessor accessor;
    BinaryReader reader;
    public static Message message = new Message();

    public MemoryMappedHandler()
    {
        stream = mmf.CreateViewStream();
        accessor = mmf.CreateViewAccessor();
        reader = new BinaryReader(stream);

        new Thread(() =>
        {
            while (stream.CanRead)
            {
                Thread.Sleep(500);
                message.MyStringWithEvent = reader.ReadString();
                accessor.Write(0, 0);
                stream.Position = 0;
            }
        }).Start();

    }

    public static void PassMessage(string message)
    {
        try
        {
            using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("mmf1"))
            {
                using (MemoryMappedViewStream stream = mmf.CreateViewStream(0, 512))
                {
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(message);
                }
            }
        }
        catch (FileNotFoundException)
        {
            MessageBox.Show("Cannot Send a Message. Please open Main.exe");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它被编译成一个 Main.exe 和 Helper.exe 都可以使用的 dll。

Helper.exe 使用 PassMessage() 方法将消息发送到名为“mmf1”的内存映射文件。Main.exe 必须始终打开,它负责创建可以从 Helper.exe 接收消息的文件。我将该消息发送到保存该消息的类,每次收到该消息时,它都会激活一个事件。

这是 Message 类的样子:

[Serializable]
public class Message
{
    public event EventHandler HasMessage;

    public string _myStringWithEvent;

    public string MyStringWithEvent
    {
        get { return _myStringWithEvent; }
        set
        {
            _myStringWithEvent = value;
            if (value != null && value != String.Empty)
            {
                if (HasMessage != null)
                    HasMessage(this, EventArgs.Empty);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,我必须像这样在我的 WebBrowserWindow 类中初始化 Message:

public partial class WebBrowserWindow : Window
{
    public WebBrowserWindow()
    {
        InitializeComponent();
        webBrowser.MenuHandler = new ContextMenuHandler();
        webBrowser.RequestHandler = new RequestHandler();
        MemoryMappedHandler.message.HasMessage += Message_HasMessage;
    }

    private void Message_HasMessage(object sender, EventArgs e)
    {
        ExecuteJavaScript(MemoryMappedHandler.message.MyStringWithEvent);
    }

    public void ExecuteJavaScript(string message)
    {
        //webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");

        //webBrowser.ExecuteScriptAsync("alert('test');");
    }
}
Run Code Online (Sandbox Code Playgroud)

现在它允许我通过从 Helper.exe 向 Main.exe 发送消息来执行我需要的 javascript。