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?

FuukaChan
  • 29
  • 6
  • I currently have COVID, so maybe a bit cloudy, but I don't see anything obvious. Why are you using a timer? – Gregory A Beamer Jan 10 '21 at 22:16
  • @GregoryABeamer I have to check the string every minute, but on the site it updates more frequently, at the moment the timer is at 5 seconds to do quick tests – FuukaChan Jan 10 '21 at 22:21
  • 1
    Does this answer your question? [webbrowser.document throws Specified cast is not valid exception](https://stackoverflow.com/questions/12559930/webbrowser-document-throws-specified-cast-is-not-valid-exception) – JuanR Jan 11 '21 at 04:41
  • @JuanR solved using invoke. thanks – FuukaChan Jan 11 '21 at 08:15

1 Answers1

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.

Jesus Salas
  • 652
  • 3
  • 14