Behrooz
Behrooz

Reputation: 1734

Show and ShowDialog won't work

It is not like anything i have seen before.
When i call (new System.Windows.Forms.Form()).ShowDialog() a form shows for a millisecond or something and then vanishes.
I traced the calls and got This:

System.Windows.Forms.Form.Dispose
System.ComponentModel.Component.Dispose
System.Windows.Forms.Application.ThreadWindows.Dispose
System.Windows.Forms.Application.ThreadContext.DisposeThreadWindows
System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop
System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner
System.Windows.Forms.Application.ThreadContext.RunMessageLoop
System.Windows.Forms.Form.ShowDialog Esfand.Program.Main C#

I have tried anything that comes to mind to fix this.

Although I have showed a login form before trying to show this form.
I don't think there is anything special going on the login form(usual boring stuff, connect to server, send credentials, receive data).
I'm using main thread for forms. I have experience with Messaging and message loops. and i have used threads in the login form.

EDIT: Clarification for what Cody Gray suggested:

This is what I have in void Main(string[]):

LoginForm login = new LoginForm ();
login.ShowDialog ();//works
if (login.DialogResult == DialogResult.OK)
{
    MainForm f = new MainForm ();
    f.ShowDialog ();//won't work
}

Creating and Showing the MainForm in a new thread made everything to just start working again.but random errors occur on each form that makes this solution not good enough.

EDIT 2:
The FormClosing event doesn't even trig.

System.Windows.Forms.Form A;
A = new Form();
A.FormClosing += new FormClosingEventHandler((sender, e) => { System.Diagnostics.Debugger.Break();/*won't work. tried Breakpoints and other stuff too*/ });
A.ShowDialog();

EDIT 3: The HandleDestroyed event stack trace:

>   Esfand.exe!Esfand.Program.Main.AnonymousMethod__1(object sender = {System.Windows.Forms.Form}, System.EventArgs e = {System.EventArgs}) Line 50 + 0x6 bytes C#
    System.Windows.Forms.dll!System.Windows.Forms.Control.OnHandleDestroyed(System.EventArgs e) + 0x9e bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Form.OnHandleDestroyed(System.EventArgs e) + 0x13 bytes   
    System.Windows.Forms.dll!System.Windows.Forms.Control.WmDestroy(ref System.Windows.Forms.Message m) + 0x54 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x547 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m) + 0x6d bytes 
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg = 2, System.IntPtr wparam, System.IntPtr lparam) + 0x15e bytes    
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DestroyHandle() + 0xf7 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Control.DestroyHandle() + 0x3e3 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Control.Dispose(bool disposing) + 0x347 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.ContainerControl.Dispose(bool disposing) + 0x19 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Form.Dispose(bool disposing) + 0x26a bytes    
    System.dll!System.ComponentModel.Component.Dispose() + 0x1b bytes   
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadWindows.Dispose() + 0xb3 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.DisposeThreadWindows() + 0x12d bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) + 0x58e bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason = 4, System.Windows.Forms.ApplicationContext context = {System.Windows.Forms.Application.ModalApplicationContext}) + 0x593 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x81 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window owner) + 0x765 bytes    
    Esfand.exe!Esfand.Program.Main(string[] a = {string[0]}) Line 51 + 0x10 bytes   C#

Upvotes: 3

Views: 8239

Answers (6)

l33tmike
l33tmike

Reputation: 351

My understanding is that forms need to be run within an application context.

I inherited some code that launches several forms from the Main context, in the following manner:

var form1 = Form1();
Application.Run(form1);

// form returns, check public method form.ButtonPushed etc
if (form.Button1Pushed)
{
    var form2 = Form2();
    Application.Run(form2);
}

This would successfully launch several forms.

It doesn't feel like a very elegant way of doing things but it works...

Upvotes: 0

cremor
cremor

Reputation: 6876

Your Main method looks weird. I think you are missing a call to Application.Run(). Since you don't want the application to quit as soon as the login form is closed you might need an ApplicationContext. MSDN has an example: http://msdn.microsoft.com/en-us/library/ms157901.aspx

Another possiblity is to call Application.Run() with an invisible form as parameter which then shows the other forms (and is never closed until the application should exit), but this is a quite ugly hack in my opinion.

Upvotes: 0

Uri Abramson
Uri Abramson

Reputation: 6175

Try to define the form as a class member. not inside a function.

Upvotes: 0

YK1
YK1

Reputation: 7612

It looks like IMsoComponentManager.FPushMessageLoopP() will call Application.ThreadContext.DisposeThreadWindows() when there is a WM_QUIT message on the event queue.

Are you posting a quit message by any chance in your LoginForm's button event handlers?

Upvotes: 1

Hans Passant
Hans Passant

Reputation: 941465

this thing is making every single form in my program raising a unique error(e.g. `cannot register drag&drop event handler')

That's a strong hint to the core problem in your code. The RegisterDragDrop() native function will be called when you have any control whose AllowDrop property is set to true. It is called when the native window for your form is created. Unfortunately that is a very bad time for any exception to be raised if you have the 64-bit version of Windows and you forced your program to run in 32-bit mode. The subject of this answer.

There are very few good reasons for RegisterDragDrop() to fail. But one. We can already tell from your snippet that you've been tinkering with Program.cs. The boilerplate version of it looks like this:

static class Program {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]                // <=== Here!!!
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

I put a Big Arrow at the line of code that matters. The [STAThread] attribute is essential in any GUI program. It tells the CLR that it should initialize COM and configure the main thread of your program to be a Single Threaded Apartment. Apartments are a very important COM implementation detail whose scope is a bit beyond this answer. If the attribute is missing then the main thread of your program joins the MTA, the multithreaded apartment. A hostile place for code that is not thread-safe, like drag and drop, the clipboard and the shell dialogs.

Forgetting to use the attribute can cause bewildering exceptions. Especially bad when your dev machine boots the 64-bit version of Vista or Win7, Windows versions that have trouble with exceptions that are raised at critical moments, as explained in the linked answer.

A proper version of your Program.Main() method that doesn't have this problem and otherwise uses recommended practices:

    [STAThread]                // <=== Don't forget this
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        using (var login = new LoginForm()) {
            if (login.ShowDialog() != DialogResult.OK) return;
        }
        Application.Run(new MainForm());
    }

Upvotes: 6

Patrick D&#39;Souza
Patrick D&#39;Souza

Reputation: 3573

Try to check if a thread exception error is being thrown. Check if you see anything in the Application_ThreadException event.

static void Main()
{
    Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
    try
    {
        //Your existing code
    }
    catch (Exception ex)
    {
    }
}

private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
}

EDIT: Another option would be to explicitly set the MainForm as the owner to the newForm being created.

newForm.ShowDialog(MainForm);

I have a feeling that the owner is being set to your Login form by default which was closed and this is auto-closing your new form

Upvotes: 1

Related Questions