简体   繁体   English

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

[英]Executing JavaScript on C# with CefSharp WPF causes Error

Whenever I try to execute JavaScript through C# using CefSharp (Stable 57.0), I get an error. 每当我尝试使用CefSharp(Stable 57.0)通过C#执行JavaScript时,我都会收到错误消息。 I am simply trying to execute the alert function, so I can make sure that works and later test it out with my own function. 我只是尝试执行警报功能,所以我可以确保它可以工作,然后用我自己的函数测试它。 However, I seem to be getting errors trying to do so. 但是,我似乎在尝试这样做时遇到错误。

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

I have tried both ways of executing the script. 我尝试了两种执行脚本的方法。

The first one: 第一个:

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

Gives me this error: 给我这个错误:

在此输入图像描述

The second: 第二:

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

Gives me this error: 给我这个错误:

在此输入图像描述

My objective is to create a C# function that can execute a JavaScript function in my CefSharp Browser. 我的目标是创建一个可以在我的CefSharp浏览器中执行JavaScript函数的C#函数。

I tried many links/references and there weren't that many on stack overflow. 我尝试了很多链接/引用,堆栈溢出并没有那么多。 I also read The FAQ for CefSharp and couldn't find any simple examples that allow me to execute JavaScript at will through C#. 我还阅读了CefSharp的FAQ,找不到任何允许我通过C# 随意执行JavaScript的简单示例。

In addition, I've verified the events where the Frame is loaded (it finishes loading), and unloaded (it does not unload), and if the webbrowser is null (which it's not), and the message from the: 另外,我已经验证了加载Frame的事件(它完成加载)和卸载(它没有卸载),如果webbrowser为null(它不是),以及来自:的消息:

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

still causes the first error to occur. 仍会导致第一个错误发生。

I tested for GetMainFrame(). 我测试了GetMainFrame()。 It always returns null. 它总是返回null。 ALWAYS. 总是。 Doesn't matter how long I wait, or what conditions I check for. 无论我等待多久,或者我检查的条件。

IMPORTANT 重要

I forgot to add one crucial piece of information, I have 2 assemblies in my project. 我忘记添加一条关键信息,我的项目中有2个程序集。 Both of them compile into separate executables: 它们都编译成单独的可执行文件:

Helper.exe Main.exe Helper.exe Main.exe

main.exe has a window "CallUI" that, when a button gets clicked, it executes the method I created "ExecuteJavaScript()", which is inside of my window "BrowserWindow". main.exe有一个窗口“CallUI”,当单击一个按钮时,它会执行我创建的“ExecuteJavaScript()”方法,它位于我的窗口“BrowserWindow”中。 The CallUI window is declared and initialized in Helper.exe. CallUI窗口在Helper.exe中声明并初始化。

So basically I am trying to use a separate program to open a window, click a button that calls the method and execute javascript. 所以基本上我试图使用单独的程序打开一个窗口,单击一个调用该方法并执行javascript的按钮。 So I think because they are different processes, it tells me the browser is null. 所以我认为因为它们是不同的进程,它告诉我浏览器是null。 However, when I do it all in Main.exe it works fine. 但是,当我在Main.exe中完成所有操作时,它可以正常工作。 Is there a workaround that allows me to use the separate process to create the window from Helper.exe and execute the Javascript from Main.exe? 是否有一种解决方法允许我使用单独的进程从Helper.exe创建窗口并从Main.exe执行Javascript?

It has come to my attention that I was handling the problem the wrong way. 我注意到我正在以错误的方式处理问题。

My problem, in fact, doesn't exist if it's just a single process holding all the code together. 事实上,如果只是将所有代码放在一起的单个进程,我的问题就不存在了。 However, the fact that my project has an executable that was trying to communicate with another was the problem. 但是,我的项目有一个试图与另一个进行通信的可执行文件的事实是问题所在。 I actually never had a way for my helper.exe to talk to my main.exe appropriately. 我实际上从来没有办法让我的helper.exe与我的main.exe正确对话。

What I learned from this is that the processes were trying to talk to each other without any sort of shared address access. 我从中学到的是,这些进程试图在没有任何共享地址访问的情况下相互通信。 They live in separate address spaces, so whenever my helper.exe tried to execute that javascript portion that belonged in Main.exe, it was trying to execute the script in an uninitialized version of a browser that belonged in its own address space and not main.exe. 它们位于不同的地址空间中,因此每当我的helper.exe尝试执行属于Main.exe的javascript部分时,它就会尝试在属于其自己的地址空间而不是主要的浏览器的未初始化版本中执行该脚本。可执行程序。

So how did I solve that problem? 那么我是如何解决这个问题的呢? I had to include an important piece that allowed the helper.exe process to talk to the main.exe process. 我必须包含一个重要的部分,允许helper.exe进程与main.exe进程通信。 As I googled how processes can talk to each other, I found out about MemoryMappedFiles. 当我搜索进程如何相互通信时,我发现了MemoryMappedFiles。 So I decided to implement a simple example into my program that allows Helper.exe to send messages to Main.exe. 所以我决定在我的程序中实现一个简单的例子,允许Helper.exe向Main.exe发送消息。

Here is the example. 这是一个例子。 This is a file I created called "MemoryMappedHandler.cs" 这是我创建的一个名为“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");
        }
    }
}

This is compiled into a dll that both Main.exe and Helper.exe can use. 这被编译成一个DLL,Main.exe和Helper.exe都可以使用。

Helper.exe uses the method PassMessage() to send the message to a Memory Mapped File called "mmf1". Helper.exe使用PassMessage()方法将消息发送到名为“mmf1”的内存映射文件。 Main.exe, which must be open at all times, takes care of creating that file that can receive the messages from Helper.exe. Main.exe必须始终打开,负责创建可以从Helper.exe接收消息的文件。 I sends that Message to a class that holds that message and every time it receives it, it activates an event. 我将该Message发送到一个包含该消息的类,每次收到它时,它都会激活一个事件。

Here is what the Message class looks like: 这是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);
            }
        }
    }
}

Finally, I had to initialize Message in my WebBrowserWindow class like this: 最后,我必须在我的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');");
    }
}

And now it allows me to execute the javascript I need by sending a message from the Helper.exe to the Main.exe. 现在,它允许我通过从Helper.exe向Main.exe发送消息来执行我需要的JavaScript。

Have you tried this link? 你试过这个链接吗? Contains a snippet that checks if the browser is initialised first. 包含一个片段,用于检查浏览器是否首先初始化。

cefsharp execute javascript cefsharp执行javascript

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM