.NET:属性网格中的用户定义类型导致挂起

时间:2009-10-06 17:02:55

标签: .net hang

我正在开发基于.NET 2.0插件的应用程序。我的应用程序通过System.Reflection检查指定目录中的其他.NET程序集,在运行时检测/加载插件。这非常有效。我的应用程序包含一个PropertyGrid控件,该控件是从加载的插件中存在的[Browsable(true)]属性填充的。在此PropertyGrid中,browsable-true-properties表现出以下行为:

  • 基本/原始类型(bool,string等)的属性正确加载和清理
  • 当用户未在运行时进行修改时,用户定义类型的属性(如插件侧定义的枚举)正确加载并正确清理
  • 如果用户在运行时修改非标准类型(即通过PropertyGrid更改枚举的值),则应用程序在关闭时挂起。这是我的问题。

使用Visual Studio .NET 2005和Red Gate的Reflector,我能够将挂起与Microsoft.Win32.SystemEvents.WindowThreadProc中的以下代码段隔离开来(我正在使用原始程序集,但我99%肯定这是正确的地方):

 while (flag)
 {
     if (UnsafeNativeMethods.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, 0xff, 4) != 0x102)
     {
          goto Label_0072;
     }
     Thread.Sleep(1);
     continue;
    Label_0053:
     if (msg.message == 0x12)
     {
         flag = false;
         continue;
     }
     UnsafeNativeMethods.TranslateMessage(ref msg);
     UnsafeNativeMethods.DispatchMessage(ref msg);
    Label_0072:
    if (UnsafeNativeMethods.PeekMessage(ref msg, NativeMethods.NullHandleRef, 0, 0, 1))
    {
        goto Label_0053;
    }
}

似乎'flag'未设置为true,因此我的程序永远位于此循环中。我找到了a similar problem at .NET 247的人,但他推荐的解决方法是:

System.Threading.Thread.CurrentThread.SetApartmentState(Threading.ApartmentState.STA)

似乎无法解决问题。

有什么想法吗?

提前致谢。

3 个答案:

答案 0 :(得分:3)

确保您的应用程序的入口点被标记[STAThread] - STAThreadAttribute是.NET 2+中将UI线程标记为STA的唯一方法。在线程启动后设置ApartmentState(在1.1中工作)不再是有效的指导。

这应该是:

public class Program
{
    [STAThread]
    static void Main() 
    {
        Application.EnableVisualStyles();
        Application.Run(new MyMainForm());
    }
}

答案 1 :(得分:0)

看起来你已经错误地隔离了这个问题。您发布的代码是针对WinForms用于捕获系统窗口消息(如WM_SETTINGCHANGE)的不可见窗口的窗口过程。它运行在与主线程不同的线程上,因此它不应以任何方式影响它。如果您刚刚将调试器附加到您的进程,很可能您的错误线程。

这里的标志实际上是在窗口获得WM_QUIT时设置的。但是,这应该没关系,因为线程也是作为后台线程创建的,这意味着当你的主线程终止时它会被杀死 - 所以即使没有设置标志并且它保持循环,它仍然会赢得'暂停应用程序退出。

(如果您查看使用VS2008 SP1的MS调试源服务器提供的.NET源代码,上述所有内容都很容易找到。)

答案 2 :(得分:0)

供将来偶然发现的人参考:

Friend Class Starter

<STAThread()> _
Shared Sub Main()
    Application.EnableVisualStyles()

    Dim client As ClientGUI
    client = New ClientGUI()
    Application.Run(client)

    My.Settings.Save()
End Sub
End Class