1

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

  • 基本/原始类型(布尔、字符串等)的属性正确加载和清理
  • 当用户在运行时不修改时,用户定义类型的属性(如插件端定义的枚举)正确加载并正确清理。
  • 如果用户在运行时修改了非标准类型(即通过 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;
    }
}

似乎“标志”没有设置为真,因此我的程序永远处于这个循环中。我发现有人在 .NET 247 遇到类似问题,但他推荐的解决方法是:

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

似乎没有解决问题。

有什么想法吗?

提前致谢。

4

3 回答 3

3

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

这应该看起来像:

public class Program
{
    [STAThread]
    static void Main() 
    {
        Application.EnableVisualStyles();
        Application.Run(new MyMainForm());
    }
}
于 2009-10-06T17:11:10.370 回答
0

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

这里的标志实际上是在窗口获取 WM_QUIT 时设置的。但是,这无关紧要,因为该线程也是作为后台线程创建的,这意味着当您的主线程终止时它无论如何都会被杀死 - 所以即使没有设置标志并且它继续循环,它仍然不会在退出时挂起应用程序。

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

于 2009-10-06T17:11:20.313 回答
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
于 2009-10-06T18:47:18.943 回答