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?
.NET ProgrammingC#

Avatar of undefined
Last Comment
bigbadger1

8/22/2022 - Mon
Mike Tomlinson

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

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.
MuhammadAdil

You can use asynchronous threading to achieve this.
http://msdn.microsoft.com/en-us/library/2e08f6yc(VS.71).aspx
Your help has saved me hundreds of hours of internet surfing.
fblack61
ASKER
dbtoth

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
bigbadger1

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
See how we're fighting big data
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
ASKER
dbtoth

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?
ASKER
dbtoth

Also, my SecondScreen form appears then immediately vanishes if I ignore the MDA debug message
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
ASKER
dbtoth

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?
ASKER
dbtoth

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.
bigbadger1

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.
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy