• 0

"Function Expected" IE10 Script Error on Disposing of WebBrowser ST


Question

Point of application,

Render Provided html string and print it using Internet Explorer, quickly in the background.

Problem,

WebBrowser control requires to be run in an STA thread stopping this thread (after Disposing the Web Browser) causes an IE script error.

I have a class which starts a WebBrowser Control in an STA thread,

    class RenderHtml : System.Windows.Forms.ApplicationContext
    {
// stuff
        private WebBrowser browser = null;
// more stuff
        public RenderHtml()
        {
            renderThread = new Thread(Run);
            renderThread.SetApartmentState(System.Threading.ApartmentState.STA);
            renderThread.Start();
        }

        private void Run()
        {
// Error Checking Omitted
                    browser = new WebBrowser();
                    browser.DocumentCompleted += HasRendered;
                    browser.ScriptErrorsSuppressed = true;
            Application.Run(this);

Then, I give pipe it Html to load,

        public void RenderNew(string html, AutoResetEvent resultEvent)
        {
// Error Checking Omitted
                    browser.DocumentText = html;
                    browser.Refresh();
// AutoResetEvent Logic Omitted
        }

Then after it finished rendering, I tell it to print to a specific virtual printer.

That all works.

So now, I need to dispose of it.

This is what I have right now

        protected override void Dispose(bool disposing)
        {
            lock (locko)
            {
                if (renderThread != null)
                {
                    renderThread.Abort();
                    renderThread = null;
                    return;
                }
            }
            browser.DocumentCompleted -= HasRendered;
            System.Runtime.InteropServices.Marshal.Release(browser.Handle);
            browser.Dispose();
            base.Dispose(disposing);
        }

        public void Stop()
        {
            resultEvent.Dispose();

            browser.Stop();
            ExitThread();
            Dispose();
        }

The problem is with both renderThread.Abort() and ExitThread() - I have to commit both out not to get an error.

Both of these fail due to the WebBrowser control.

I don't feel like providing a screenshot, so here is the text,

The error comes from IE itself,

Script Error
An error has occurred in the script on this page.
Line: 289
Char: 1
Error: Function Expected
Code: 0
URL: res://ieframe.dll/preview.js

Do you want to continue running scripts on this page?

So, after calling Dispose methods including the WebBrowsers dispose method.

I try to stop the thread. Which gives me this error.

If I did NOT provide any html to render I think (been a long time) there is no Script Error.

But then, it completely kills the point of the application!

Note I do suppress Script Errors - when I created the WebBrowser.

                    browser.ScriptErrorsSuppressed = true;

Also, does anyone know of a way to provide images to the WebBrowser control without going through saving them to disk?

2 answers to this question

Recommended Posts

  • 0

EDIT: Code is Available if you have no f-ing idea what I am talking about.

Now to dispose a WebBrowser,

I can do it from the STA Thread Which runs the Web Browser using Application.run(this).

So I can dispose the WebBrowser when it triggers an even such as a DocumentCompleted event.

Additionally, I can dispose of the Web Browser by using .Invoke(...) method.

Sadly WebBrowser cannot be disposed of from another thread by simply calling the Dispose() method.

I can also set the reference to the STA thread to null as well well as the reference to the WebBrowser

and set the thread to be a background thread.

The issue is, the thread does not terminate.

And to release all memory I have to terminate the damn thread.

Whether before or after dispose, whether from a separate thread or the STA Thread itself (during the DocumentCompleted event)

I get this error.

I guess I am asking is, how am I supposed to properly stop a ApplicationContext with a Web Browser Control properly and dispose of it WITHOUT any errors?

1. Why doesn't the renderThread exit itself (Abort is bad from what I understand)?

2. From where do I Abort the renderThread (STA Thread)? The calling thread (which uses the code)? renderThread itself?

3. Do I abort the thread before or after disposing of the WebBrowser?

4. Is the most proper way to dispose of a WebBrowser from another (calling) thread is to use browser.Invoke(...)?

5. Now there is Exit() ExitThread() renderThread.Abort() ExitThreadCore() - they all give me the same error... where am I supposed to call them to avoid bull?

Also this error may help,

A first chance exception of type 'System.Runtime.InteropServices.InvalidComObjectException' occurred in System.Windows.Forms.dll

Edited by _Alexander
  • 0

Workaround Solution

Even after calling browser.Dispose(),

waiting for the browser.Disposed event handler to finish,

and checking browser.IsDisposed before calling renderThread.Abort()

I still got the dreaded Script Error - An error has occurred in the script on this page Line 289 Char 1 Function Expected Code 0 URL res://ieframe.dll/preview.js

You may also get Script Error - An error has occurred in the script on this page Line 518 Char 1 Error The callee (server [not server application]) is not available and disappeared; all connections are invalid. The call did not execute. Code 0 URL res://ieframe.dll/preview.js

Create Separate Thread Which Waits 1 Second After The WebBrowser is Disposed and the calls renderThread.Abort()

Here is the code for this,

        public void TryDispose()
        {
            //
            // Do not Dispose Twice
            //

            if (_doDispose)
                return;

            _doDispose = true;

            //
            // Dispose Browser
            //

            browser.Invoke(
                new MethodInvoker
                    (
                        () =>
                        {
                            browser.Stop();

                            browser.DocumentCompleted -= HasRendered;
                            browser.Disposed += SetDisposeEvent;

                            if (browser.ActiveXInstance != null)
                                Marshal.ReleaseComObject(browser.ActiveXInstance);
                            if (browser.Handle != null)
                                Marshal.Release(browser.Handle);

                            browser.Dispose();

                        }
                    )
                );

            //
            // Hack Around - Create a Thread which Waits for 1 second before disposing the Web Browser
            //

            var browserDisposeThread = new Thread
                (
                    () =>
                    {
                        disposeEvent.WaitOne(1000);
                        Thread.Sleep(1000); // Wait to Avoid Script Error <:::::::::::::::::::::::
                        if (renderThread.IsAlive)
                        {
                            renderThread.Abort();
                            renderThread = null;
                            browser = null;

                            _applicationThreadReady.Dispose();
                            disposeEvent.Dispose();
                            if (resultEvent != null) resultEvent.Dispose();
                        }
                    }
                );
            browserDisposeThread.Name = "Browser Dispose Thread For " + renderThread.Name;
            browserDisposeThread.IsBackground = true;
            browserDisposeThread.Start();

            Console.WriteLine("TryDispose");
        }

Suggestions, Comments welcome.

Edited by _Alexander
This topic is now closed to further replies.
  • Posts

    • Weird how some people don't need to crash 7 rockets before they get it right.
    • Or it's a bug that can easily be fixed with an update. My guess is the limitation is there to prevent game makers from doing dumb things like having a racing game constantly rumble while the car is in motion. Sounds like the threshold or detection needs to be tweaked if it is triggering for no reason.
    • Nice I guess. Azure's DaaS feature has supported that for years. It's so odd to me how MS is deploying Azure and 365 DaaS as two totally different services with different features. I would think the 365 cloud desktops would just be a slightly dumbed down frontend that manages the same service.
    • Oh and gaming on a PC cost way more. To get PS5 Pro performance on a PC it will cost you more, especially with the crazy GPU costs today. While you can play Last of US and Horizon, finally, you cant play GT7 unless you have a PS5 (other games as well).
    • IT admins will soon be able to provision cloud apps rather than entire Windows 365 Cloud PCs by Usama Jawad As we discussed earlier, Windows 365 Cloud PC is a neat way to access virtualized operating systems without getting access to physical hardware. It makes it much easier to work in hybrid or remote environments using hardware and software managed on the cloud by your organization. However, Microsoft is making this process even more convenient with a private preview for Windows 365 Cloud Apps. In its announcement, Microsoft has revealed that it is testing a way to deliver individual apps to users securely via Windows 365, instead of having an entire Cloud PC provisioned for them. It is important to note that these apps will still be hosted on the Cloud PC, a user just won't need access to a dedicated Cloud PC. Microsoft believes that this improved way of app delivery will facilitate seasonal and remote workers by getting them access to just the line-of-business (LOB) apps that they require, while also offering centralized and simplified management capabilities. Importantly, Redmond believes that this will facilitate migration from on-prem virtual desktop infrastructure (VDI) to the cloud too. Deploying this new experience is fairly straightforward for any IT admin who has prior experience with setting up Windows 365. They will need to select an "app-only" experience during the configuration process instead of the full desktop mode and then control the licenses and app access. During this private preview period, only apps available in the Start menu of the gallery or custom images are supported, but more types of apps will be supported for streaming as we get closer to general availability (GA). On the end-user side, customers with Cloud Apps provisioned for them will be able to launch them from the Windows App gateway. Any security policy that applies to the associated Cloud PC will also apply to the Cloud App in use. Microsoft has encouraged those interested in joining the private preview to contact their Microsoft account team or fill in this form. There is no word yet regarding general availability.
  • Recent Achievements

    • Week One Done
      slackerzz earned a badge
      Week One Done
    • Week One Done
      vivetool earned a badge
      Week One Done
    • Reacting Well
      pnajbar earned a badge
      Reacting Well
    • Week One Done
      TBithoney earned a badge
      Week One Done
    • First Post
      xuxlix earned a badge
      First Post
  • Popular Contributors

    1. 1
      +primortal
      671
    2. 2
      ATLien_0
      284
    3. 3
      Michael Scrip
      223
    4. 4
      +FloatingFatMan
      196
    5. 5
      Steven P.
      137
  • Tell a friend

    Love Neowin? Tell a friend!