InvalidCastException when reading mshtml.HTMLDocument.Script property

197 views Asked by At

Trying to read the mshtml.HTMLDocument property results in the following exception:

An unhandled exception of type 'System.InvalidCastException' occurred in mscorlib.dll Additional information: Specified cast is not valid. occurred

This is happening on the line "object script = doc.Script;"

Code:

using System;
using System.Reflection;
using mshtml;
using SHDocVw;

namespace ConsoleApp12
{
    class Program
    {
        static void Main(string[] args)
        {
            string command = string.Empty;

            while (command != "exit")
            {
                Console.Write("Enter command: ");
                command = Console.ReadLine();

                if (command == "go")
                {
                    ShellWindows shellWindows = new SHDocVw.ShellWindows();
                    foreach (var shellWindow in shellWindows)
                    {
                        var ie = shellWindow as SHDocVw.InternetExplorer;
                        if (ie != null)
                        {
                            var doc = ie.Document as HTMLDocument;
                            if (doc != null)
                            {
                                if (doc.title.Contains("Test Page"))
                                {
                                    object script = doc.Script;
                                    script.GetType().InvokeMember("DoSomething", BindingFlags.InvokeMethod, null, script, null);
                                }
                            }
                        }
                    }
                }
                else
                {
                    Console.WriteLine("Unrecognized command");
                }
            }
        }
    }
}

Here is the test page I am using:

<!DOCTYPE html>
<html>
<head>
  <title>Test Page</title>
</head>
<body>

<script>

function sayHello()
{
    alert('Hello');
}

</script>

<h1>My First Heading</h1>
<p>My first paragraph.</p>

</body>
</html>

and here are my project references:

    <Reference Include="Interop.SHDocVw">
      <HintPath>..\..\..\TestApp\lib\Interop.SHDocVw.dll</HintPath>
      <EmbedInteropTypes>True</EmbedInteropTypes>
    </Reference>
    <Reference Include="Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
      <EmbedInteropTypes>False</EmbedInteropTypes>
    </Reference>
1

There are 1 answers

0
Eric Scherrer On

Turns out all I needed to do was run it as single-threaded apartment. This answer gave me the hint I needed: https://stackoverflow.com/a/19275241/2382032

using System;
using System.Reflection;
using System.Threading;
using mshtml;
using SHDocVw;

namespace ConsoleApp12
{
    class Program
    {
        static void Main(string[] args)
        {
            string command = string.Empty;

            while (command != "exit")
            {
                Console.Write("Enter command: ");
                command = Console.ReadLine();

                if (command == "go")
                {
                    Thread thread = new Thread(() =>
                    {
                        ShellWindows shellWindows = new SHDocVw.ShellWindows();
                        foreach (var shellWindow in shellWindows)
                        {
                            var ie = shellWindow as SHDocVw.InternetExplorer;
                            if (ie != null)
                            {
                                var doc = ie.Document as HTMLDocument;
                                if (doc != null)
                                {
                                    if (doc.title.Contains("Test Page"))
                                    {
                                        object script = doc.Script;
                                        script.GetType().InvokeMember("sayHello", BindingFlags.InvokeMethod, null, script, null);
                                    }
                                }
                            }
                        }
                    });
                    thread.SetApartmentState(ApartmentState.STA);
                    thread.Start();
                }
                else
                {
                    Console.WriteLine("Unrecognized command");
                }
            }
        }
    }
}