2

它不像我以前见过的任何东西。
当我调用 (new System.Windows.Forms.Form()).ShowDialog() 时,表单会显示一毫秒左右,然后消失。
我追踪了电话并得到了这个:

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#

我已经尝试了任何想到的方法来解决这个问题。

尽管在尝试显示此表单之前我已经显示了一个登录表单。
我不认为登录表单有什么特别的(通常无聊的东西,连接到服务器,发送凭据,接收数据)。
我正在为表单使用主线程。我有消息传递和消息循环的经验。我在登录表单中使用了线程。

编辑:澄清科迪格雷的建议:

这就是我所拥有的void Main(string[])

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

在新线程中创建和显示 MainForm 使一切重新开始工作。但是每个表单上都会出现随机错误,这使得该解决方案不够好。

编辑 2:
FormClosing 事件甚至不会触发。

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();

编辑 3: HandleDestroyed 事件堆栈跟踪:

>   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#
4

6 回答 6

5

这件事使我的程序中的每一个表单都引发了一个独特的错误(例如,“无法注册拖放事件处理程序”)

这是对代码中核心问题的强烈暗示。当您有任何控件的 AllowDrop 属性设置为 true 时,将调用 RegisterDragDrop() 本机函数。创建表单的本机窗口时调用它。不幸的是,如果您拥有 64 位版本的 Windows 并且您强制您的程序以 32 位模式运行,那么对于引发任何异常都是一个非常糟糕的时机。这个答案的主题。

RegisterDragDrop() 失败的充分理由很少。但是一个。我们已经可以从您的代码段中看出您一直在修改 Program.cs。它的样板版本如下所示:

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());
    }
}

我在重要的代码行放了一个大箭头。[STAThread] 属性在任何 GUI 程序中都是必不可少的。它告诉 CLR 它应该初始化 COM 并将程序的主线程配置为单线程单元。公寓是一个非常重要的 COM 实现细节,其范围有点超出这个答案。如果缺少该属性,则程序的主线程将加入 MTA,即多线程单元。非线程安全的代码(如拖放、剪贴板和 shell 对话框)的不利位置。

忘记使用该属性可能会导致令人困惑的异常。当您的开发机器启动 64 位版本的 Vista 或 Win7 时尤其糟糕,Windows 版本在关键时刻引发异常时遇到问题,如链接答案中所述。

您的 Program.Main() 方法的正确版本没有此问题,并且使用推荐的做法:

    [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());
    }
于 2013-05-12T11:32:53.747 回答
1

尝试检查是否抛出了线程异常错误。检查您是否在 Application_ThreadException 事件中看到任何内容。

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)
{
}

编辑: 另一种选择是将 MainForm 显式设置为正在创建的 newForm 的所有者。

newForm.ShowDialog(MainForm);

我有一种感觉,默认情况下所有者被设置为您的登录表单,该表单已关闭,这将自动关闭您的新表单

于 2013-04-21T06:06:05.743 回答
1

当事件队列上有 WM_QUIT 消息时,它看起来IMsoComponentManager.FPushMessageLoopP()会调用。Application.ThreadContext.DisposeThreadWindows()

您是否有机会在您LoginForm的按钮事件处理程序中发布退出消息?

于 2013-05-12T20:05:54.097 回答
0

尝试将表单定义为类成员。不在函数内部。

于 2013-05-13T07:19:36.237 回答
0

我的理解是表单需要在应用程序上下文中运行。

我继承了一些从 Main 上下文中启动多个表单的代码,方式如下:

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

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

这将成功启动几种形式。

这感觉不是一种非常优雅的做事方式,但它确实有效......

于 2013-05-14T16:06:46.657 回答
0

你的Main方法看起来很奇怪。我认为您错过了对Application.Run(). 由于您不希望应用程序在登录表单关闭后立即退出,您可能需要一个ApplicationContext. MSDN 有一个例子:http: //msdn.microsoft.com/en-us/library/ms157901.aspx

另一种可能性是Application.Run()使用不可见的表单作为参数调用,然后显示其他表单(并且在应用程序退出之前永远不会关闭),但在我看来这是一个非常丑陋的黑客攻击。

于 2013-05-14T08:56:00.300 回答