V8Context not created when passing "about:blank" to ChromiumWebBrowser's constructor - c#

The steps to reproduce this are very simple. Just download the latest version of CefSharp.WinForms (57.0.0) with nuget, then add a button and this code to a form:
public partial class Form1 : Form
{
ChromiumWebBrowser WebBrowser;
public Form1()
{
InitializeComponent();
WebBrowser = new ChromiumWebBrowser("about:blank");
panel1.Controls.Add(WebBrowser);
WebBrowser.Dock = DockStyle.Fill;
}
private void testButton_Click(object sender, EventArgs e)
{
MessageBox.Show(WebBrowser.CanExecuteJavascriptInMainFrame.ToString());
}
}
Then run the application, wait a few seconds to make sure "about:blank" has loaded and press the testButton. The message box will show False. In fact, if I attempt to use EvaluateScriptAsync I will get an exception telling me the context has not been created.
One way to solve this is to call ShowDevTools, which seems to somehow force a context to be created. Another solution is to navigate to a non local page such as Google. In this case, even if I go back to "about:blank" I'll be able to run scripts. I tried using a custom scheme registered with CefSettings.RegisterScheme, but navigating to my custom page still does not create a context (I tried passing "about:blank" to the constructor and then navigating to my custom scheme and the other way around too and none worked).
So, is it possible to have CefSharp create a context without having to navigate to a non-local page or to show DevTools?

You will have to use the following functions:
WebBrowser.GetMainFrame().ExecuteJavaScriptAsync(string code);
WebBrowser.GetMainFrame().EvaluateScriptAsync(string code);
This bypasses the regular check for V8Context.
More information from CefSharp, found here:
For frames that do not contain JavaScript then no V8Context will be created. Executing a script once the frame has loaded it's possible to create a V8Context.
You can use browser.GetMainFrame().ExecuteJavaScriptAsync(script) or browser.GetMainFrame().EvaluateScriptAsync to bypass these checks.

Related

How can I use pre-existing form LoadFromXml in WeifenLuo?

I inherited a WinForms application where we are using Dock management with WeifenLuo. I'm trying to use the SaveAsXml and LoadFromXml.
Which works fine if I am ok with a new form every time - a particular form needs to stay available right now and I was hoping to be able to just use the code to hide it on close.
The sample app just recreates the controls every time so I'm at a loss.
If I recreate the control it shows fine. However, trying to make it use the already created control never works.
Load XML - attempt doesn't work:
m_deserializeDockContent = new DeserializeDockContent(GetContentFromPersistString);
_dockPanel = null;
InitDockPanel(); //Initialize DockPanel to full screen
_dockPanel.LoadFromXml(filepath, m_deserializeDockContent);
private IDockContent GetContentFromPersistString(string persistString)
{
if (persistString == typeof(ExistingForm).ToString())
return existingForm;
throw new NotImplementedException();
}
At this point I tried the dispose around _dockPanel and handling the dockPanel of the ExistingForm, but nothing seems to change the outcome. Reading online I discovered maybe blocking the close may help, but still doesn't work.
Example of handling the Form close event:
public ExistingForm()
{
InitializeComponent();
HideOnClose = true;
this.FormClosing += ExistingForm_FormClosing;
}
private void ExistingForm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
this.Hide();
}
Updating LoadXml code to include existingForm.DockHandler.Close();, existingForm.DockHandler.Dispose();, or _dockPanel.Dispose();
Which doesn't work at all and I get an error because the form is disposed of.
The only thing that seems to work is recreating the form
if (persistString == typeof(ExistingForm).ToString())
return new ExistingForm();
Just wondering if I'm missing some handling of the DockHandler (no pun intended).

WinForms Navigated Event

i made a winForms application that uses web browser control that enables the user to sign in with his google or facebook account then after getting the information or any error or exception the form which contains the web browser closes and will return back to the main form, i do the following, prepare the request, navigate() using that request then catch the response with the event Navigated.
in the code all is working fine, but when i build as Release and install the application the Navigated event is never fired up, which is really weird since nothing in my code is in debug condition, any ideas how to solve this issue??
the code at form's load event is:
private void GoogleLogin_Load(object sender, EventArgs e)
{
AuthHelper authHelper = new AuthHelper();
Uri loginURI = authHelper.GetGoogleAuthURI(_appID, redirectURI);
GoogleLoginControl.Navigate(loginURI);
}
the code at the web browser control at Navigated event
private void GoogleLoginControl_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
CoreStaticMembers.ologger.LogToFile("Navigated event with the absolute URL "+ e.Url.AbsoluteUri );
MessageBox.Show("Navigated event is fired");
///used if parameters are empty so ignore the following messages
bool ignore = false;
string code = null;
if (e.Url.AbsolutePath.Equals("/connect/login_success.html"))
{
AuthHelper authHelper = new AuthHelper();
//NameValueCollection parameters = HttpUtility.ParseQueryString(e.Url.Query);
try
{
NameValueCollection parameters = HttpUtility.ParseQueryString(e.Url.Query);
if (parameters != null)
{
string jsonResponse = null;
and after that i continue with normal authentication and data acquiring, keep in mind that this issue only appears when i build as Release then install the application, also the Navigating even is fired for the web browser control, so does the Load event for the parent form
Thanks in advance
UPDATE
by the way i also tried to Navigate with the required URL when i initialize the form by calling Initialize function inside the form's constructor, but the same problem appeared,
i found out that this problem is related to a compatibility issue related to a DLL file, particularly "Newtonsoft" DLL.

Trying to close a form after the next one is shown in C# cf

I've been studying Android lately and I tried to port one of its functions to C# compact framework.
What I did is create an Abstract class that I call Activity.
This class looks like this
internal abstract class Activity
{
protected Form myForm;
private static Activity myCurrentActivity = null;
private static Activity myNextActivity = null;
internal static void LoadNext(Activity nextActivity)
{
myNextActivity = nextActivity;
if (myNextActivity != null)
{
myNextActivity.Show();
if (myCurrentActivity != null)
{
myCurrentActivity.Close();
myCurrentActivity = null;
}
myCurrentActivity = myNextActivity;
myNextActivity = null;
}
}
internal void Show()
{
//PROBLEM IS HERE
Application.Run(myForm);
//myForm.Show();
//myForm.ShowDialog();
//
}
internal void Close()
{
myForm.Close();
}
internal void GenerateForm()
{
///Code that uses the Layout class to create a form, and then stores it in myForm
//then attaches click handlers on all the clickable controls in the form
//it is besides the point in this problem
}
protected abstract void Click(Control control);
//this receives all the click events from all the controls in the form
//it is besides the point in this problem
}
The problem I have is with running the part of the Show() command
Basically all my classes implement the above class, load an xml file and display it.
When I want to transition to a new class/form (for example going from ACMain to ACLogIn)
I use this code
Activity.LoadNext(new ACLogIn);
Which is supposed to load the next form, show it , and unload the current form
I have tried these solutions (in the Show() method) and here is the problem with each one
using myForm.ShowDialog()
This works, but blocks execution, which means that the old form does not close, and the more I move between the forms the more the process stack increases
using myForm.Show()
This works, closes the old form after the old one is shown, but immediately after that closes the program and terminates it
using Application.Run(myForm)
This works only on the first form loaded, when I move to the next form, it shows it then throws an exception saying "Value does not fall within the expected range"
Can someone help me fix this or find an alternative?
If you're really after creating your own framework for this navigation, you need to re-work you thinking. The Form instance passed into Application.Run must never close - when it does, Application.Run finishes execution and (typically) your static void Main entry point exits and the app terminates.
What I would propose is that you change your Activity to either being a UserControl:
public abstract class Activity : UserControl
{
....
}
or Composing one
public abstract class Activity
{
private UserControl m_control;
....
}
Then instead of closing and showing Forms, parent all of the Activities inside the main Form as a container.
As fair warning, this is going to get complex when you start wanting to show things in a Tab motif instead of a Stack, or having split views. Frameworks seem simple to create, but they're not so I'd at least consider using something already done unless you have compelling reasons to want to roll your own.
Application.Run is generally used with the overload that takes a Form parameter. This would be the "main" form that would be responsible for starting/showing other forms. This "main" form could be "hidden". But, I think that's a little awkward.
Alternatively, you don't need a main form, you can use Application.Run() to start a message pump to process Windows messages; but, then the thread is busy processing messages and cannot show dialogs (they must be shown in the thread that is running Application.Run). You can get around this by creating one or more form objects before calling Application.Run and these form objects could create a Timer object that would call Form.Show() or Form.ShowDialog() on the Timer.Tick event handler so that for form is shown after the call to Run. I think this is a little awkward as well.
Both of these solutions kind of circumvent the way you're expected to use Windows and WinForms; so, I think you need to think about re-designing this application to work with the way that Windows and .NET works.

Silverlight 4 Clipboard Security Exception "access is not allowed"?

I'm new in Silverlight and i am doing some tests. With my current test I try to display in real time the current Clipboard content. But there is a weird behaviors with this code :
namespace SilverlightTest
{
public partial class MainPage : UserControl
{
private Timer _timer;
public MainPage()
{
InitializeComponent();
var dispatcher_timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 0, 5)};
dispatcher_timer.Tick += new EventHandler(timer_Callback);
dispatcher_timer.Start();
}
private void timer_Callback(object state, EventArgs eventArgs)
{
current_clip_board.Content = Clipboard.GetText();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
current_clip_board.Content = Clipboard.GetText();
}
}
}
The button Event and the timer Event are suppose to do exactly the same action.
But it doesn't ! The Button works fine and set the clipboard text into the label but the timer throw an exception :
Clipboard access is not allowed
The question is : why ? :)
Thanks.
PS : I would bet on a thread problem :p
Clipboard access, in a partial trust (in-browser) Silverlight application (the scenario you're likely referring to above), is restricted. The GetText property is accessible only in scenarios that the Silverlight runtime determines were initiated by the user. Your example is perfect -- by a button click for example. A dispatch timer however is not user initiated, so the property throws an exception (this is especially important within the context of a in-browser application, which could be a big security hole if you could create a Silverlight application that just ran silently in the browser, watching the user's clipboard updates without their knowledge).
See this clipboard documentation for more details.
Just trigger Clipboard.ContainsText() instead of Text. The method ContainsText is allowed!
Have you tried this:
private void timer_Callback(object state, EventArgs eventArgs)
{
Dispatcher.Invoke(new System.Threading.ThreadStart(delegate()
{
current_clip_board.Content = Clipboard.GetText();
}
}
edit
After a quick search, it appears that Clipboard is only available in response to a user action see here and here.
In partial trust (the default mode for
browser-hosted Silverlight-based
applications), Silverlight also
restricts clipboard access to its two
key APIs GetText and SetText. These
APIs can only be invoked from within a
context that is determined by the
Silverlight runtime to be in response
to a user-initiated action. For
example, clipboard access is valid
from within a handler for a Click or
KeyDown event. In contrast, clipboard
access is not valid from a handler for
Loaded or from a constructor, and
access attempts throw exceptions.
If your only option is to use a timer, then don't do it at all. The clipboad is a shared resource, and you're going to raise "cannot open clipboard" errors in other programs as they try to access the clipboard. i.e. user copies something from WinWord, WinWord tries to open the clipboard, but can't, because you've got it locked while you're examining it.
Hello this works for me but only in IE Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() => HtmlPage.Window.Eval("window.clipboardData.setData('Text','testtestest')"));
just use getData method

How to stop a .NET application from loading if certain criteria aren't met

I need certain criteria to be met, a particular folder needs to be present on the c drive, before this app should load. How, during the load process, can I stop/quit the application.
I already have ascertained if the folder exists. In old VB projects you would just use 'Unload Me' but that isn't in C#. I tried Application.Exit() but that doesn't work under these circumstances and the app still loads, how do I stop it?
Open up Program.cs. In there you'll find you Main() method.
In there, put something like:
if (FolderDoesNotExist())
return ERROR_FOLDER_NOT_EXIST;
(replacing those symbolic names with other stuff as appropriate).
I would create an initialization function that would be the first item to be called from Main(). Depending on your output and how long your initialization takes you can even use a splash window to inform the user about progress. Once all initialization is completed, you can decide if you start the app or not.
// In the main initialization of the main form (in XXX.Designer.cs file InitializeComponent(), for example)
this.Load += new System.EventHandler(this.CheckProcesses);
// The CheckProcess method
private void CheckProcesses(object sender, EventArgs e)
{
try { if (SomethingIsWrongWithThatFolder()) this.Close(); }
catch { }
}
// This will shut the process of your app before the UI actually loads. So, your user doesn't see anything at all

Categories