Whenever I try to execute JavaScript through C# using CefSharp (Stable 57.0), I get an error. 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.
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#.
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:
webBrowser.GetMainFrame().ExecuteJavaScriptAsync("alert('test')");
still causes the first error to occur.
I tested for GetMainFrame(). It always returns 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. Both of them compile into separate executables:
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". The CallUI window is declared and initialized in 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. So I think because they are different processes, it tells me the browser is null. However, when I do it all in Main.exe it works fine. 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?
It is possible to implement a C API in JavaScript! This is the approach used in many of Emscripten's libraries, like SDL1 and OpenGL. You can use it to write your own APIs to call from C/C++.
Since Node. js is written in low-level languages like C and C++, it can talk to other programs that are written in C and C++ and vice-versa.
You can modify a WebAssembly module so it can talk to the JavaScript code directly. External functions can be defined in your C or C++ code using the extern keyword.
To execute JavaScript in a browser you have two options — either put it inside a script element anywhere inside an HTML document, or put it inside an external JavaScript file (with a . js extension) and then reference that file inside the HTML document using an empty script element with a src attribute.
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.
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.
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. As I googled how processes can talk to each other, I found out about MemoryMappedFiles. So I decided to implement a simple example into my program that allows Helper.exe to send messages to Main.exe.
Here is the example. This is a file I created called "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.
Helper.exe uses the method PassMessage() to send the message to a Memory Mapped File called "mmf1". Main.exe, which must be open at all times, takes care of creating that file that can receive the messages from Helper.exe. I sends that Message to a class that holds that message and every time it receives it, it activates an event.
Here is what the Message class looks like:
[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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With