0

I'm trying to simulate a user typing a value into an "input" field on a website, and I'm getting very strange exception when trying to run InvokeMember. I tested several approaches and I found that most online documentation is outdated and simply doesn't work. Unfortunately the mostly suggested solution to my problem seems to throw a very strange exception:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: ''System.MarshalByRefObject.InvokeMember(string, System.Reflection.BindingFlags, System.Reflection.Binder, object[], System.Reflection.ParameterModifier[], System.Globalization.CultureInfo, string[])' is inaccessible due to its protection level'

This is an example code that recreates the problem:

MainWindow.xaml

<Window x:Class="Example.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Example"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
    <DockPanel>
        <WebBrowser x:Name="ie"/>
    </DockPanel>
</Window>

MainWindow.xaml.cs

using mshtml;
using System.ComponentModel;
using System.Threading;
using System.Windows;
using System.Windows.Navigation;

namespace Example
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            ie.LoadCompleted += (o, e) =>
            {
                BackgroundWorker worker = new BackgroundWorker();
                worker.DoWork += (wo, we) => { Thread.Sleep(5000); };
                worker.RunWorkerCompleted += (wo, we) => { DelayedLoadCompleted(); };
                worker.RunWorkerAsync();
            };

            ie.Navigate(@"https://google.com");
        }

        private void DelayedLoadCompleted()
        {
            HTMLDocument doc = (ie.Document as HTMLDocument);

            dynamic input = doc.getElementById("lst-ib");

            input.InvokeMember("onkeypress", new { Key = 65 }); //throws that excetpion
            input.InvokeMember("click"); //throws that excetpion
            input.click(); //works fine
        }
    }
}

The line input.InvokeMember("click"); throws that exception, but input.click(); works just fine.

What is the cause of that exception?

Filip Franik
  • 251
  • 3
  • 13
  • Is there a special reason you use `dynamic`? Thats probably part of the problem here... – thehennyy Oct 04 '18 at 10:25
  • @thehennyy There is no higher reason for using `dynamic` other then code clarity. The `mshtml` library has very strange architecture and it forces jumping between interfaces to access different properties and methods. – Filip Franik Oct 04 '18 at 14:15
  • Please try to change the type from `dynamic` to `HtmlElement`. – thehennyy Oct 04 '18 at 14:21
  • `HtmlElement` does not contain the definition of `InvokeMember` so code doesn't even compile. I think I mistook the cause problem,because now I see that `InvokeMember` is actually implemented inside `dynamic` type so that solution is also useless for my original problem of simulating user keyboard input into an input field on the website. – Filip Franik Oct 04 '18 at 14:39
  • There is a `HtmlElement.InvokeMember` method: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.htmlelement.invokemember?view=netframework-4.7.2 – thehennyy Oct 04 '18 at 14:42
  • @thehennyy This is a class from `System.Windows.Forms` assembly. I cannot directly convert `mshtml` objects into it. I also tried substituting `mshtml` framework completely with `System.Windows.Forms`, but unfortunately the webbrowser component (that's created by WPF) and it's `Document` property cannot be casted to `System.Windows.Forms.HtmlDocument`. – Filip Franik Oct 04 '18 at 14:57
  • Ok yeah thats a problem. Then you have to find a way to call these methods in the `mshtml` world. – thehennyy Oct 04 '18 at 14:59
  • Apparently in `mshtml` there is a method `IHTMLElement3.FireEvent` that can be used to run events on the webbrowser, but so far I was unsuccessful wit my attempts of using it. https://msdn.microsoft.com/pt-br/library/mshtml.ihtmlelement3.fireevent(v=vs.110).aspx – Filip Franik Oct 04 '18 at 15:02
  • Why do you even want to simulate keypresses instead of just setting the text content of the input element? – NineBerry Oct 04 '18 at 16:47
  • @NineBerry Because the input element does not contain values that are sent to the server. Input has a container that handles several events (onkeydown, onkeyup, onkeypress, onchange) that combine data from several inputs into json string that's getting sent via AJAX. Optimally UI testing framework should not depend to much on javascript implementation and just simulate what user would do. – Filip Franik Oct 04 '18 at 16:54
  • Hey, I got the same error. FilipFranik explation is correct. @thehennyy solution worked ! – ahmet gül Jul 05 '21 at 13:35

0 Answers0