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

Executing JavaScript on C# with CefSharp WPF causes Error

每当我尝试使用 CefSharp(稳定版 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');");
    }
}

我已经尝试了两种执行脚本的方式。

第一个:

webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");

给我这个错误:

第二个:

webBrowser.ExecuteScriptAsync("alert('test');");

给我这个错误:

我的 objective 是创建一个 C# 函数,它可以在我的 CefSharp 浏览器中执行 JavaScript 函数。

我尝试了很多 links/references 并没有那么多堆栈溢出。我还阅读了 The FAQ for CefSharp,但找不到任何简单的示例,可以让我通过 C# 随意执行 JavaScript。

此外,我已经验证了框架加载(完成加载)和卸载(未卸载)的事件,以及网络浏览器是否为空(实际上不是),以及来自该:

webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");

仍然会导致出现第一个错误。

我测试了 GetMainFrame()。它始终 returns 为空。总是。不管我等了多久,或者我检查了什么条件。

重要

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

Helper.exe Main.exe

main.exe 有一个 window "CallUI",当单击按钮时,它会执行我创建的方法 "ExecuteJavaScript()",它在我的 [=74] 中=] "BrowserWindow"。 CallUI window 在 Helper.exe.

中声明和初始化

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

你试过这个link吗?包含检查浏览器是否首先初始化的片段。

private void OnIsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs args)
{
    if(args.IsBrowserInitialized)
    {
        browser.ExecuteScriptAsync("alert('test');");
    }
}

我注意到我处理问题的方式不对。

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

我从中了解到,进程试图在没有任何共享地址访问的情况下相互交谈。它们位于单独的地址 space 中,因此每当我的 helper.exe 试图执行属于 Main.exe 的 javascript 部分时,它试图以未初始化的版本执行脚本属于自己地址 space 而不是 main.exe.

的浏览器

那么我是如何解决这个问题的呢?我必须包括一个重要的部分,它允许 helper.exe 进程与 main.exe 进程对话。当我在 google 上搜索进程如何相互通信时,我发现了 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");
        }
    }
}

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

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

消息 class 如下所示:

[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);
            }
        }
    }
}

最后,我必须像这样在 WebBrowserWindow class 中初始化消息:

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

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