Invalid cast only when function called from timer

1

im trying to do a program that read a string from a website e send it to another. the process to read string for the first works correctly, and also the function to send a string to the other works, but have problem when this function was called from the timer..

here is part of my code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using CefSharp.WinForms.Internals;

namespace CodePinger
{
    public partial class Form1 : Form
    {
        public bool login = true;
        private static System.Timers.Timer TimerCheck;
        public Form1()
        {
            InitializeComponent();
            TimerCheck = new System.Timers.Timer(5000);
            TimerCheck.Elapsed += new ElapsedEventHandler(CheckEvent);
            TimerCheck.AutoReset = true;
            CheckForIllegalCrossThreadCalls = false;
            webBrowser1.ScriptErrorsSuppressed = true;
            chromiumWebBrowser1.Load("https://firstwebsite.com");
            webBrowser1.Navigate("http://secondwebsite.com");
        }
        private async void CheckEvent(Object source, ElapsedEventArgs e)
        {
            if (login) { 
                string script = "document.getElementById('SecondSDISP').innerText;";
                JavascriptResponse jr = chromiumWebBrowser1.EvaluateScriptAsync(script).Result;
                if (jr.Success)
                {
                    if (jr.Result.ToString().Contains("01"))
                    {
                        label2.ForeColor = Color.Red;
                        label2.Text = jr.Result.ToString();
                        sendCode(jr.Result.ToString());
                    }
                }
                else
                {
                    label2.ForeColor = Color.Black;
                    label2.Text = "no data";
                }
                label4.Text = timer.ToString();
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            TimerCheck.Enabled = true;
            TimerCheck.Start();
            button2.Enabled = false;
        }
        public void sendCode(string code)
        {
            string msg = "";
            if (code == "1") msg = "1 coda";
            else msg = code.ToString() + " code";
            var textarea = webBrowser1.Document.GetElementsByTagName("textarea")[0];
            textarea.InnerHtml = msg;
            textarea.Focus();
            var allsvg = webBrowser1.Document.GetElementsByTagName("svg");
            foreach (HtmlElement svg in allsvg)
            {
                if (svg.GetAttribute("className").Contains("-send"))
                {
                    svg.InvokeMember("click");
                    break;
                }
            }
        }
        private void button4_Click(object sender, EventArgs e)
        {
            sendCode("1");
        }
    }
}

also after i started the timer, if i click to button4 to test the function, it works correctly. instead of when its called from timer

the error is:

System.InvalidCastException
  HResult=0x80004002
  Message=Specified cast is not valid.
  Source=System.Windows.Forms
  StackTrace:
   at System.Windows.Forms.UnsafeNativeMethods.IHTMLDocument2.GetLocation()
   at System.Windows.Forms.WebBrowser.get_Document()
   at CodePinger.Form1.sendCode(String code) in C:\Users\Flynns82\source\repos\CodePinger\Form1.cs:line 105
   at CodePinger.Form1.<CheckEvent>d__9.MoveNext() in C:\Users\Flynns82\source\repos\CodePinger\Form1.cs:line 63

the indicated line are:

105) var textarea = webBrowser1.Document.GetElementsByTagName("textarea")[0];
63) sendCode(jr.Result.ToString());

can someone explain me what is the problem?

c#
webbrowser-control
asked on Stack Overflow Jan 10, 2021 by FuukaChan

1 Answer

0

Most likely your problem is you are trying to access the WebBrowser from a non-STA thread (aka the 'UI Thread')

When you use the button4_click handler your code is running on the STA Thread (by default), however, when a Time Event handler is called back it happens in a different thread (which is not the STA one) thus you will have problems invoking/accessing properties on ActiveX/Components (who reside in the STA thread) if you do not "invoke" back into the STA.

I recommend to take a look to the following SO Question: STA vs MTA for a technical explanation.

For solving the invoke problem look into the following SO Question: Automating the InvokeRequired code pattern

On the other hand the browser exposes a NavigateComplete event, you do not need to have a time checking when the page is loaded, just hook yourself to the event and wait for it after navigate, the DOM will be stable once this event fires.

answered on Stack Overflow Jan 11, 2021 by Jesus Salas

User contributions licensed under CC BY-SA 3.0