2

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#
Behrooz
  • 1,696
  • 2
  • 32
  • 54
  • 2
    try set a breakpoint in the dialog, my guess is it throws and exception – Johan Larsson Apr 21 '13 at 05:48
  • Also make sure you are creating and showing the dialog when executing on the main thread. Bad things happen when you try to create or show UI forms from a background thread. – dthorpe Apr 21 '13 at 05:50
  • Did you try creating an object of `form` then calling it?? – Shaharyar Apr 21 '13 at 05:51
  • @dthorpe I'm using main thread for this, I'm sure about that. – Behrooz Apr 21 '13 at 05:51
  • @Shaharyar That's what I'm doing. (new System.Windows.Forms.Form()).ShowDialog() – Behrooz Apr 21 '13 at 05:52
  • @JohanLarsson You think there could be something wrong with the login? – Behrooz Apr 21 '13 at 05:54
  • Funny, Just tried running the form on another thread and it worked. Still waiting to see a real reason behind this. – Behrooz Apr 21 '13 at 06:05
  • You cannot show forms on multiple threads. Everything to do with the UI needs to happen only on one thread, the main (UI) thread. That's the real reason behind all of this. See [here](http://stackoverflow.com/questions/4759334/how-can-i-close-a-login-form-and-show-the-main-form-without-my-application-closi/4759407#4759407) for the correct way to display a login form before your main form. – Cody Gray - on strike Apr 21 '13 at 12:19
  • The login form IS on the main thread. see the edit. – Behrooz Apr 21 '13 at 20:41
  • Your main form should not be shown with `ShowDialog()`. – David Heffernan Apr 21 '13 at 21:00
  • 1
    Add an event handler for the FormClosing event and set a breakpoint on it. Look at the call stack. – Hans Passant Apr 21 '13 at 21:04
  • @HansPassant Didn't work.See the edit. – Behrooz Apr 21 '13 at 21:34
  • I don't see an edit. It wasn't supposed to "work", it shows you why Winforms decided to close the form. – Hans Passant Apr 21 '13 at 21:36
  • @HansPassant You're fast. I just made the edit. – Behrooz Apr 21 '13 at 21:38
  • Another thing, The problem persists on windows 7, windows xp and windows 7 in kvm.Didn't have time to test on anything else. – Behrooz Apr 21 '13 at 22:25
  • please, anyone?this thing is making every single form in my program raising a unique error(e.g. `cannot register drag&drop event handler') – Behrooz Apr 22 '13 at 12:18
  • Try to reduce your code to a [short, self-contained, correct, compilable example](http://sscce.org/). If you can't see the problem while doing that already, you can post it and we can probably help you better. – dialer May 12 '13 at 10:59
  • @dialer: The code is too big for that. – Behrooz May 12 '13 at 11:57
  • Also i tried stripping off every single line of code in main and kept the few lines in question. Nothing changed. – Behrooz May 12 '13 at 12:02
  • @Behrooz: If you replace ShowDialog with show does it work? If you replace Mainform with just Form f = new Form (); does it work? – bobbyalex May 13 '13 at 07:29

6 Answers6

5

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());
    }
Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • +1, I'll check this soon.I have just lost access to the upstream code for a few days. – Behrooz May 12 '13 at 11:55
  • 1
    Well, I cannot offer another explanation why RegisterDragDrop() would fail, don't know enough about your execution environment and I can't see your Main() method or your Login form. It otherwise explains everything you saw so *do* verify your assumptions. Add a line of code that calls System.Threading.Thread.CurrentThread.GetApartmentState() and ensure you get STA back. – Hans Passant May 12 '13 at 12:04
  • If you use any ActiveX component on your LoginForm then consider the possibility that it has a bug and calls CoUninitialize(), that would be fatal as well. – Hans Passant May 12 '13 at 12:15
  • I haven't used any external libraries or ActiveX components. – Behrooz May 12 '13 at 12:16
  • And i forgot to mention this has happened on both x86 and 64 bit versions of windows seven. I'm debugging in 64-bit windows and 'Any CPU'. – Behrooz May 12 '13 at 12:19
  • I'm just thinking at the possibility that this could happen with System.Net.Sockets?I have a lot of networking stuff for login that i change constantly.The login happens in a library with only one reference to System.dll – Behrooz May 12 '13 at 12:27
  • 5
    It is very hard to help SO users that trickle little bits of info one at a time. You'll need to properly document your problem and give us a decent chance to diagnose it. Do so by creating a minimum repro project that exhibits this problem and post it to a file sharing service. – Hans Passant May 12 '13 at 12:28
  • Sorry, I really didn't think that stuff mattered because i had tested every single case for days before asking.I even tried compiling with mono(no success). – Behrooz May 12 '13 at 12:29
  • I'll do that, but it takes time. – Behrooz May 12 '13 at 12:30
1

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

Patrick D'Souza
  • 3,491
  • 2
  • 22
  • 39
1

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?

YK1
  • 7,327
  • 1
  • 21
  • 28
  • No ,There are no API calls and such things in the whole application, not even unsafe code, pure plain .Net without any dlls, no Reflection in system classes, not a single line of hacky code, and that's what hurts me. – Behrooz May 12 '13 at 21:56
  • Ok, have you written any custom code to close the LoginForm? You should rely on the `DialogResult` property of the OK/Cancel or whatever buttons you have. – YK1 May 12 '13 at 22:19
  • this.Close() is not required on Dialogs - you should set the DialogResult property on the buttons - Dialog will close. I am having bad feeling about it - although I cant say it will solve your problem , you can try removing the this.Close() call – YK1 May 13 '13 at 08:28
  • actually Close() will cause a WM_CLOSE and not WM_QUIT - hmmm.. I guess you may want to reveal more about what you are doing in the `LoginForm` - I am almost sure somehow you've ended up with a WM_QUIT in your event queue. – YK1 May 13 '13 at 09:05
0

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

Uri Abramson
  • 6,005
  • 6
  • 40
  • 62
0

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.

cremor
  • 6,669
  • 1
  • 29
  • 72
0

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

l33tmike
  • 351
  • 1
  • 8