locked
How to use a newwindow2event in C# BUT In a New Thread

    Question

  • Hi:

    I wrote an application that use the axWebbrowser control (not the webbrowser that came with .net 2.0) and till now, when a new windowsevent was occurs, I sue the following code that works ok:

       private void axWebBrowser1_NewWindow2(object sender,
          AxSHDocVw.DWebBrowserEvents2_NewWindow2Event e)
      {
         Form1 frmWB;
         frmWB = new Form1();
         frmWB.axWebBrowser1.RegisterAsBrowser = true;
         e.ppDisp = frmWB.axWebBrowser1.Application;
         frmWB.Visible = true;
      }

    Now, I want to create the new form in a new trhead, in order to prevent that, in case that the main form will be close, the second one (just created) must be NOT closed.

    For this, I have the following code, but I don't know how to set the e.ppDisp in order that teh newForm created in a separate thread receive the passed uRL:

     private void axWebBrowser1_NewWindow3(object sender,
        AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e)
     {
         System.Threading.Thread t = 
               new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(ThreadProc));
         t.SetApartmentState(ApartmentState.STA);
         t.Start(e);
     }

      public static void ThreadProc(object e)
     {
        AxSHDocVw.DWebBrowserEvents2_NewWindow3Event f =
          (AxSHDocVw.DWebBrowserEvents2_NewWindow3Event)e;
        Form1 newForm = new Form1();
        Application.Run(newForm);

        // THE PROBLEM IS HERE, how can I use the previous sentences
        // newForm.axWebBrowser1.RegisterAsBrowser = true;
        // e.ppDisp = newForm.axWebBrowser1.Application;
        // because now the newForm is in a separate thread

     }

    Thanks in Advance
    Ernesto Aides
    Ashdod - Israel

    Thursday, January 21, 2010 12:41 PM

Answers

  • I was wrong, the problem is not doing that line in the parent window's thread. The problem is, you need to have it run before the end of the NewWindow3 event.

    class Parameters
    {
        public AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e;
        public bool started;
    }
    public static void ThreadProc(object o)
    {
        Parameters p = (Parameters)o;
        Form1 frmWB = new Form1(false);
        p.e.ppDisp = frmWB.axWebBrowser1.Application;
        p.started = true;
        Application.Run(frmWB);
    
    }
    private void axWebBrowser1_NewWindow3(object sender,
        AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e)
    {
        System.Threading.Thread t =
            new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(ThreadProc));
        t.SetApartmentState(ApartmentState.STA);
        Parameters p = new Parameters();
        p.e = e;
        t.Start(p);
        while (!p.started) Thread.Sleep(100);
    }
    • Marked as answer by Ernesto Aides Monday, January 25, 2010 1:29 PM
    Monday, January 25, 2010 1:02 PM

All replies

  • The GUI thread handles all GUI operations. There is no starting a new GUI thread from a generic worker thread.
    William Wegerson (www.OmegaCoder.Com)
    Thursday, January 21, 2010 1:58 PM
    Moderator
  • Why not?

    You can only have one thread owning one window handle.
    But you can have any number of threads each owning one or more window handles.

    Thursday, January 21, 2010 2:23 PM
  • Hi:

    Can be do what I want to do ? It  is a kind of urgent issue for the application.

    I tried:

    public static void ThreadProc(object e)
    {
     AxSHDocVw.DWebBrowserEvents2_NewWindow3Event f =
      (AxSHDocVw.DWebBrowserEvents2_NewWindow3Event)e;
     Form1 nF = new Form1(false);
     nF.axWebBrowser1.RegisterAsBrowser = true;
     f.ppDisp = nF.axWebBrowser1.Application;
     nF.Visible = true;
     Application.Run(nF);
    }


    but the result is:

    a) a new Form is created that not navigate to nothing.
    b) a InternetExplorer window is open with the desired page to where I want to navigate.

    Thanks in advance
    Ernesto Aides

    Sunday, January 24, 2010 4:42 PM
  • The line

    f.ppDisp = nf.axWebBrowser1.Application;

    needs to run in the parent window's thread.
    Monday, January 25, 2010 9:07 AM
  • Why not?

    You can only have one thread owning one window handle.
    But you can have any number of threads each owning one or more window handles.


    However if you want to have multiple message queues, you'll have a lot of work to do; not least, you'll have to manually handle the multiple message queues. Application.Run() only supports a single one.
    Monday, January 25, 2010 10:33 AM
  • However if you want to have multiple message queues, you'll have a lot of work to do; not least, you'll have to manually handle the multiple message queues. Application.Run() only supports a single one.

    You mean it only supports one message queue per thread.

    If you use Application.Run() on another thread, you can put your first thread to sleep or even end it, and your second window will still be working.
    Monday, January 25, 2010 12:33 PM
  • Hi:

    I tried you sugestion as:

            public static void ThreadProc(object f)
            {
                try
                {
                    Application.Run((Form1)f);
                }
                catch (Exception)
                { }
            }

            private void axWebBrowser1_NewWindow3(object sender,
                AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e)
            {
                System.Threading.Thread t =
                    new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(ThreadProc));
                t.SetApartmentState(ApartmentState.STA);

                Form1 frmWB = new Form1(false);
                frmWB.axWebBrowser1.RegisterAsBrowser = false;
                e.ppDisp = frmWB.axWebBrowser1.Application;
                frmWB.Visible = true;
                //            frmWB.Show();
                t.Start(frmWB);
            }

    but it is not working as expected:

    a) pay attention to the rty/catch in ThreadProc method, if I not use this, I will receive InvalidOperation Exception with message "control -controlname- accessed from a thread other thatn the thread it was created on"

    b) the new window is open and navigate to the desired page, but:

    c) if I close the first windows, the second is closed too (seams to the 2nd. windows was called in the same thread of the first one).

    Can you send me an example how this must be implemented ?

    Thanks !
    Ernesto Aides

    Monday, January 25, 2010 12:42 PM
  • I was wrong, the problem is not doing that line in the parent window's thread. The problem is, you need to have it run before the end of the NewWindow3 event.

    class Parameters
    {
        public AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e;
        public bool started;
    }
    public static void ThreadProc(object o)
    {
        Parameters p = (Parameters)o;
        Form1 frmWB = new Form1(false);
        p.e.ppDisp = frmWB.axWebBrowser1.Application;
        p.started = true;
        Application.Run(frmWB);
    
    }
    private void axWebBrowser1_NewWindow3(object sender,
        AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e)
    {
        System.Threading.Thread t =
            new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(ThreadProc));
        t.SetApartmentState(ApartmentState.STA);
        Parameters p = new Parameters();
        p.e = e;
        t.Start(p);
        while (!p.started) Thread.Sleep(100);
    }
    • Marked as answer by Ernesto Aides Monday, January 25, 2010 1:29 PM
    Monday, January 25, 2010 1:02 PM
  • Thanks a lot Lois. !

    I will check in deep, but my first test was OK.

    Ernesto Aides
    Ashdod - israel

    Monday, January 25, 2010 1:31 PM
  • I have a new question for the same situation:

    In must of cases, we need to open a new window for each navigation using a new thread. This was resolved by the code above from Luis.fr

    But in a few cases, we need to navigate to an existing windows (form), this is, reuse a popup windows previusly opened.

    In the version without threads, I have a class (singletone) that contains a list of references for all Form opened bya  newwindow3 event, and I use one of this references in case that I need to reuse a window, see code below (no multithred option is in use here):

         private void axWebBrowser1_NewWindow3(object sender,
             AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e)
        {
               if (expression to determine that a new window is needed)
                {
                    frmWB = new Form1();
                    // add the reference of the new window in the list (into the singletone class)
                    myUtils.addNewWindow(frmWB, myurl1);
                }
                else
                {
                    // exist in the list into the singletone class, I will use the pointer saved in the list
                    frmWB = myUtils.existWindow(myurl1);
                }
                frmWB.webBrowser1.RegisterAsBrowser = false;
                e.ppDisp = frmWB.webBrowser1.Application;
                frmWB.Visible = true;
                frmWB.toFront();
            }
       }

    But now, I have the second window in a separate thread:

    How I need to pass the neccesary data (in this case
    the AxSHDocVw.DWebBrowserEvents2_NewWindow3Event "e", in a safe mode, to the second thread ?

    Can I use the references to the Forms, or I need to save the references to the threads created ?

    Thanks in advance
    Ernesto Aides

    Tuesday, January 26, 2010 4:08 PM
  • You can use the reference to the Form. Just make sure you don't call directly any method modifying the UI.
    Use the Invoke method to execute code in the thread owning the Form.
    Wednesday, January 27, 2010 10:01 AM
  • Hi Louis:

    I don't understant good what do you means with "Just make sure you don't call directly any method modifying the UI"
    Also, as you can understand, I very very new in the thread programming, and I don't know how I need to use the Invoke method. Can you please send me an example ?

    Thanks a lot for your help

    Ernesto Aides

    Wednesday, January 27, 2010 10:30 AM
  • Whenever you modify something on a Form (or any Control), you need to do it in the thread owning the Form or the Control.
    For this, the Control object provides an Invoke method.

    If you have this code:

    frmWB.webBrowser1.RegisterAsBrowser = false;
    e.ppDisp = frmWB.webBrowser1.Application;
    frmWB.Visible = true;

    and you're in a multi-threaded application, you can add a method like this to the window:

    void HandleNewWindow3(AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e)
    {
        if(InvokeRequired) // This returns true if the current thread doesn't own the handle
            Invoke(new Action<AxSHDocVw.DWebBrowserEvents2_NewWindow3Event>(HandleNewWindow3), e);
        else
        {
            webBrowser1.RegisterAsBrowser = false;
            e.ppDisp = webBrowser1.Application;
            Visible = true;
        }
    }

    and you just need to call it with:

    frmWB.HandleNewWindow3(e);

    If you know that the current thread doesn't own the form (because you always spawn a new thread for every new window), you can remove the test from the method:

    void HandleNewWindow3(AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e)
    {
        webBrowser1.RegisterAsBrowser = false;
        e.ppDisp = webBrowser1.Application;
        Visible = true;
    }

    and always call that method with Invoke:

    frmWB.Invoke(new Action<AxSHDocVw.DWebBrowserEvents2_NewWindow3Event>(frmWB.HandleNewWindow), e);
    Wednesday, January 27, 2010 3:51 PM
  • Louis:

    I don't understand what happend, but I think that I did what you said to me, and the result is: when I call to reuse the form that already exist -i other thread-, the aplicattion hangs... it seams that in any part exist a loop without end...

    I don't see any diference, but... can you see if you found any error in the code:

            private void webBrowser1_NewWindow3(object sender, AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e)
            {
                string myurl = e.bstrUrl.ToString();
                string myurl1 = myurl;
                Form1 frmWB = myUtils.existWindow(myurl);
                if (null != frmWB)
                {
                    // exist in the hashtable - reusable
                    Parameters p = new Parameters();
                    p.e = e;
                    p.started = false;
                    frmWB.Invoke(new
                        Action<Parameters>(frmWB.HandleNewWindow3), p);
                   while (!p.started) Thread.Sleep(100);
                }
                else
                {
                    // non exist on table - new window
                    Thread t = new Thread(
                        new ParameterizedThreadStart(threadProc));
                    t.SetApartmentState(ApartmentState.STA);
                    Parameters p = new Parameters();
                    p.e = e;
                    p.started = false;
                    t.Start(p);
                    while (!p.started) Thread.Sleep(100);
                }
            }

            class Parameters
            {
                public AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e;
                public bool started = false;
            }

            private void HandleNewWindow3(Parameters p)
            {
                    AxSHDocVw.DWebBrowserEvents2_NewWindow3Event e = p.e;
                    string myurl = e.bstrUrl.ToString();
                    Form1 frmWB = myUtils.existWindow(myurl);
                    e.ppDisp = frmWB.webBrowser1.Application;
                    frmWB.Visible = true;
                    frmWB.Show();
                    p.started = true;
            }

     

     

     

    Tuesday, February 09, 2010 1:08 PM
  • I found something, but it does not sence:

    If I do the follow single change:

                    .....
                    // exist in the hashtable - reusable
                    Parameters p = new Parameters();
                    p.e = e;
                    p.started = false;
                    Invoke(new
                        Action<Parameters>(HandleNewWindow3), p);

    It works, but it does not have reference to the second form (frmWB) in any part of the call... just into the method HandleNewWindow3 I use the frmWB....

    Is his correct ? I don't see how the compiler knows in this case what thread is the owner of the form (control).

    Tuesday, February 09, 2010 1:15 PM
  • These two methods don't cause any lock or loop.
    Can you post the code of threadProc?
    Tuesday, February 09, 2010 1:38 PM
  • Here it is:

            public static void threadProc(object o)
            {
                Utils myUtils = Utils.getInstance;
                Parameters p = (Parameters)o;
                Form1 frmWB = new Form1();
                frmWB.webBrowser1.RegisterAsBrowser = false;
                //
                string myurl = p.e.bstrUrl.ToString();
                if (null == myUtils.existWindow(myurl))
                {
                    myUtils.addNewWindow(frmWB, myurl);
                }
                //
                p.e.ppDisp = frmWB.webBrowser1.Application;
                p.started = true;
                Application.Run(frmWB);
            }

    My question is: How the application knows wich thread need to attend to the invoked method handleNewWindow3 ?

    Thanks for your attention
    Tuesday, February 09, 2010 1:55 PM
  • My question is: How the application knows wich thread need to attend to the invoked method handleNewWindow3 ?

    A call to GetWindowThreadProcessId returns the identifier of the thread that created the window.


    I just saw the change you made. If you remove the reference to frmWB, the methods you call belong to 'this', the current Form.

    With your threadProc method, I still don't hang. What's left? The constructor of Form5, the existWindow and addNewWindow methods?
    Tuesday, February 09, 2010 2:40 PM
  • Hi:

    The real strange here is that I make a simple application with webbrowser without all the additional work that I need, and it's work just with your code...

    I will investigate which method make the hang and I will tell you...
    Tuesday, February 09, 2010 3:39 PM
  • Hi:

    I don't understand, the problem is not the application...
    With some sites it is work OK, but in our site is not work, it is hung when call to the form in other thread...
    Thursday, February 11, 2010 10:16 PM