Link to home
Start Free TrialLog in
Avatar of dbtoth
dbtoth

asked on

Starting second form in new thread

Here's the situation... I've got a VS.2005 C# WinForms application in which I needed a way to display a powerpoint PPS or a MSWord document inside a form window... after a very large amount of searching and a lot of dead ends I determined the only way this was going to work was to place an IE browser control on the form in question.

The general idea is that the second monitor (which faces the customers) will spew advertising until display of a specific document is required, then I swap the PPS for the word doc in the IE Browser

I display this form maximized on the secondary monitor. This part worked OK...

            // Launch the secondary screen window
            SecondScreen ss = new SecondScreen();
            this.secondScreen = ss;
            ss.Show();

            // Now start the main window
            mainForm.ShowDialog(this);
            Application.DoEvents();
            this.Close();

For this most part this works OK, until the PPS hits a slide transition, then my main application form mainForm has a mouse and keyboard hiccup until the transition finishes on the slide. This is annoying as hell, particularly when you are trying to type.

I figured I could get around this by trying to launch the new secondScreen form on it's own thread, then it wouldn't interfere with me anymore. It sounded like a good idea at the time...

        private void showSecondScreen()
        {
            SecondScreen ss = new SecondScreen();
            this.secondScreen = ss;
            ss.Show();
        }

and then in my main form load event...

            // Start the second screen
            Thread sf= new Thread(new ThreadStart(showSecondScreen));
            sf.Start();

when the SecondScreen form launches I get an exception error from the AXWebBrowser control...

ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.

Searching for this message resulted in recommendations to set [STAThread] on the main() function. Obviously there's no main() inside the SecondScreen form and the main() in MainForm already has [STAThread] set by the designer.

Any suggestions how I can launch this other window on it's own thread so it's processing doesn't interfere with my main application or some other means of keeping the IE Browser control from messing up the main form?
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Make the SecondScreen form its OWN application that gets passed a filename to display...then launch it with Process.Start().
Avatar of dbtoth
dbtoth

ASKER

The problem is I need to communicate with the window to change it's content once the window is running. Launching a new application with Process.Start() just opens up a loan on interprocess communications hassles unless there's some really easy way to pass information back and forth that I'm not aware of.
You can use asynchronous threading to achieve this.
http://msdn.microsoft.com/en-us/library/2e08f6yc(VS.71).aspx
Avatar of dbtoth

ASKER

Muhammad: I followed the example link, actually I needed to drill for the .NET 2.0 version.

This got rid of the active-x error, but the window doesn't open now, which could mean the error didn't really fix, but I'm just not seeing it

I created the necessary delegates...
        public delegate void AsyncMethodCaller();
and added the code in the Main()
                SecondScreen ss = new SecondScreen();
                AsyncMethodCaller caller = new AsyncMethodCaller(ss.Show);
                IAsyncResult result = caller.BeginInvoke(new AsyncCallback(CallbackMethod), caller);
                Application.Run(new FullScreen());
I'm now getting an exception being thrown in
        private void SecondScreen_Load(object sender, EventArgs e)
        {
>>>      this.DesktopBounds = outScreen.WorkingArea;
            this.WindowState = FormWindowState.Maximized;
        }

Cross-thread operation not valid: Control 'SecondScreen' accessed from a thread other than the thread it was created on.

If I play the delegate game (which I don't really understand since the _Load is running on the same thread) then the cross-thread error goes away...

        delegate void SetBoundsCallback(Rectangle rect);
        private void SetBounds(Rectangle rect)
        {
            if (this.InvokeRequired)
            {
                SetBoundsCallback d = new SetBoundsCallback(SetBounds);
                this.Invoke(d, new object[] { rect });
            }
            else
            {
                this.Bounds = rect;
            }
        }

        private void SecondScreen_Load(object sender, EventArgs e)
        {
            SetBounds(outScreen.WorkingArea);
            this.WindowState = FormWindowState.Maximized;
        }

but after all this the second window never opens.

Any other ideas
ASKER CERTIFIED SOLUTION
Avatar of bigbadger1
bigbadger1

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of dbtoth

ASKER

BigBadger1:

OK, we're getting a lot closer... the window opens without throwing the active-x error, but then I get two errors back to back when I run the application

The first is a VS popup:

No symbols are loaded for any call stack frame. The source code cannot be displayed.

The only option is OK

Then I get an MDA popup

LoaderLock was detected
Message: Attempting managed execution inside OS Loader lock. Do not attempt to run managed code inside a DllMain or image initialization function since doing so can cause the application to hang.

I'm running the thread start code...

            // Start the second screen
            Thread MySecondScreenThread = new Thread(new ThreadStart(this.ShowSecondScreen));
            MySecondScreenThread.SetApartmentState(ApartmentState.STA);
            MySecondScreenThread.Start();

from inside _Load event of my main form.
Looking up that error I found and article that basically says to disable the MDA LoaderLock event... admittedly that will get rid of the MDA message but do you see any practical negative impact from just disregarding the error?
Avatar of dbtoth

ASKER

Also, my SecondScreen form appears then immediately vanishes if I ignore the MDA debug message
Avatar of dbtoth

ASKER

OK.. I've done some tracing

// Start the second screen
MySecondThread = new Thread(new ThreadStart(this.ShowSecondScreen));
MySecondThread.SetApartmentState(ApartmentState.STA);
MySecondThread.Start();

the last line launches ShowSecondScreen()

 private void ShowSecondScreen()
 {
     MySecondScreen = new SecondScreen();
     MySecondScreen.Show();
 }

1. The constructor for SecondScreen runs completely without error after the new SecondScreen()
2. The _Load event in SecondScreen runs fully without error after MySecondScreen.Show() line
3. The instant the _Load event in MySecondScreen completes, the SecondScreen window vanishes.

any idea what I'm still missing?
Avatar of dbtoth

ASKER

I guess the problem was calling .Show() which basically executes and returns, resulting in termination of the thread. I switched to using .ShowDialog() then created a delegate for Shutdown() function that performs this.Close() as part of the main forms _FormClosing event.

in _FormClosing of the main form

if (MySecondThread.IsAlive)
{
    MySecondScreen.Shutdown();
    while (MySecondThread.IsAlive) ;
}

Then in the SecondScreen code...

    delegate void ShutdownDelegate();
    public void Shutdown()
    {
        if (this.InvokeRequired)
        {
            ShutdownDelegate d = new ShutdownDelegate(Shutdown);
            this.Invoke(d);
        }
        else
        {
            this.Close();
        }
    }

Everything works perfectly now.
glad you got it figured out. Sorry I wasn't much help with your follow up problem. Admittedly, this is the first chance I've had to look at this thread since I posted.