Welcome Guest Search | Active Topics | Sign In | Register

Recommendation to ensure we have a valid javascript to call Options
Christian Porzio
Posted: Tuesday, December 6, 2016 11:35:16 AM
Rank: Advanced Member
Groups: Member

Joined: 10/4/2016
Posts: 104
Hi,

I have not been able to implement a 100% reliable way:
1/ Ensure it was safe to invoke a javascript function
2/ Prevent the JSException popup message to be displayed in case I failed #1

Basically I am checking it is safe to invoke a javascript function using: CanEvalScript though I might wait a little bit before giving up totally

However sometimes CanEvalScript returns true, but my page had changed in between when I actually invoke my call therefore throwing a JSException - which is ok I guess because I don't think I will ever be able to guaranty a synchronized call from my wrapper.

BUT... at least I would like to save my user to see this "big" JSException message that itself says it can be avoided if the code catches the exception. I think I am doing that, yet the popup keep showing up.

Any idea how I could improve #1 - if applicable but primarily how to guaranty #2

As always thank you very much for your pertinent responses.

This is my code:

Code: C#
public override bool ExecuteScript(string function, object[] pars)
        {
            try
            {
                if (checkFunctionExist(function))
                {
                    if (!canExecute()) return false;
                    webView.GetDOMWindow().InvokeFunction(function, pars);
                    return true;
                }
            }
            catch (EO.WebBrowser.JSException)
            {
                  // Swallow the exception? Looks like not!
            }
            catch (Exception e)
            {
                if (e.InnerException != null)
                    MessageBox.Show("Exception: " + e.Message + " / " + e.InnerException.Message, "JavaScript Error", MessageBoxButton.OK, MessageBoxImage.Error);
                else
                    MessageBox.Show("Exception: " + e.Message, "JavaScript Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            return false;

        }

        private bool canExecute()
        {
            int attempt = 0;
            while (!webView.CanEvalScript)
            {
                if (++attempt > 10)
                    return false;
                Thread.Sleep(100);
            }
            return true;
        }
eo_support
Posted: Tuesday, December 6, 2016 11:40:15 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,072
Hi,

The recommended way for you to do this is to through QueueScriptCall. That function is asynchronous and will call a callback supplied by you when its done. So you can call QueueScriptCall and then after a certain amount of time if your callback is not called then something is wrong (either the script takes too long, the page is too busy) and you would kill the page and recreate the WebView (similar to Chrome's "the page is unresponsive, do you want to wait or kill the page" message).

You should never do Thread.Sleep when you wait. Nothing will happen with the WebView when you call Thread.Sleep. This is because the WebView is driven by windows messages. So unless you pump messages, nothing will happen on the WebView. If you must wait, you should call WebView.DoEvents.

Thanks!
Christian Porzio
Posted: Wednesday, December 7, 2016 8:36:13 AM
Rank: Advanced Member
Groups: Member

Joined: 10/4/2016
Posts: 104
Thanks a lot, I will follow these recommendations and keep you updated. Also I definitely like the approach and I agree, I was using Sleep but suspected this did not do any good.
Christian Porzio
Posted: Tuesday, December 13, 2016 2:07:38 PM
Rank: Advanced Member
Groups: Member

Joined: 10/4/2016
Posts: 104
Hi,

I am trying to implement the asynchronous call a you suggested but looks like I am missing something.

I have created a class to handle the asynchronous call:
Code: C#
class JSScriptHander
    {
        private object _scriptCallResult;
        private AutoResetEvent _done;
        private ScriptCall _call;

        public object ScriptCallResult
        {
            get { return _scriptCallResult; }
        }

        public ScriptCall Call
        {
            get { return _call; }
        }

        public AutoResetEvent Done
        {
            get { return _done; }
        }

        public JSScriptHander (string script)
        {
            _done = new AutoResetEvent(false);
            _call = new ScriptCall(script, ScriptCallDone);
        }

        public void ScriptCallDone(object sender, ScriptCallDoneEventArgs e)
        {
            _scriptCallResult = e.Call.Result;
            _done.Set();
        }
    }


then this is how I'm using it:

Code: C#
JSScriptHander jshdl = new JSScriptHander(cmd); // cmd contains the javaScript command
webView.QueueScriptCall(jshdl.Call);

if (!jshdl.Done.WaitOne(1000)) // Hopefully this should take less than 1s
   return false; // this always fails


If I wait an infinite amount of time, the call never return but eventually after a minute or two, my application throws an exception:
Code: C#
System.ComponentModel.Win32Exception occurred
Message: Exception thrown: 'System.ComponentModel.Win32Exception' in EO.WebBrowser.dll
Additional information: PostMessage to WebView failed.


No doubt I am doing something very wrong here though the design looks ok to me.

Would you have a working example of these calls?

Thank you for your expertise.

Regards
eo_support
Posted: Tuesday, December 13, 2016 2:21:30 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,072
Hi,

You fell into the same trap again of knowing too much about multi-thread programming. : ) As already explained early, you can not do block wait in the thread that runs the WebView (this includes but not limited to Thread.Sleep and WaitableHandle.WaitOne). Nothing will happen on the WebView if you do block wait. In this case you will need to use the wait method on the ScriptCall object instead.

Thanks!
Christian Porzio
Posted: Tuesday, December 13, 2016 2:30:33 PM
Rank: Advanced Member
Groups: Member

Joined: 10/4/2016
Posts: 104
LOL! Well obviously I still need to learn about multi-threading programing - what a shame...

Indeed the right code is:

Code: C#
JSScriptHander jshdl = new JSScriptHander(cmd);
ScriptCall myCall = webView.QueueScriptCall(jshdl.Call);

if (!myCall.WaitOne(1000))
     return false;


and this works as expected!

Thank you for your quick reply.


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.