【问题标题】:STAThread missing, but it is thereSTAThread 丢失,但它在那里
【发布时间】:2010-08-27 13:08:07
【问题描述】:

这是我尝试在程序中打开 OpenFileDialog 时收到的错误消息:

"当前线程必须设置为单线程 OLE 之前的线程单元 (STA) 模式 可以拨打电话。确保您的 主函数具有 STAThreadAttribute 标在上面。这个例外只 如果调试器附加到 过程。”

此错误消息的问题在于我的 Main 方法确实附加了 STAThread 属性。我不知道如何处理这个问题。如果它已经存在,我该如何添加。加倍它不是一个好的选择,我尝试擦除它,构建应用程序,添加它并再次构建它,但没有成功。我只是不明白。

private void btnOldFind_Click(object sender, EventArgs e)
{
     openFileDialog1.Multiselect = false;
     openFileDialog1.FileName = "";
     openFileDialog1.ShowHelp = false;
     openFileDialog1.AutoUpgradeEnabled = true;
     openFileDialog1.InitialDirectory = @"C:\";
     openFileDialog1.Filter = "Microsoft Installer (*.msi)|*.msi|All Files (*.*)|*.* ";
     openFileDialog1.FilterIndex = 1;
     openFileDialog1.RestoreDirectory = true;

     if (openFileDialog1.ShowDialog() == DialogResult.OK)
     {
         textBoxOldInstallation.Text = openFileDialog1.FileName;
     }
}

主要方法是:

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

并且没有显式地完成线程。老实说,只是一个非常基本的程序。

EDIT2::

这是完整的错误信息,包括调用堆栈

System.Threading.ThreadStateException 未处理 Message="当前线程必须设置为单线程单元 (STA) 模式,然后才能进行 OLE 调用。确保您的 Main 函数上标记了 STAThreadAttribute。仅当调试器附加到进程时才会引发此异常。" 源="系统.Windows.Forms" 堆栈跟踪: 在 System.Windows.Forms.FileDialog.RunDialog(IntPtr hWndOwner) 在 System.Windows.Forms.CommonDialog.ShowDialog(IWin32Window 所有者) 在 System.Windows.Forms.CommonDialog.ShowDialog() 在 c:\tfs\DocuWare .NET\DocuWare NewGen\src\Tools\MSI_Comparison\MSI_Comparison_GUI\Form1.cs:line 70 中的 MSI_Comparison_GUI.Form1.btnOldFind_Click(Object sender, EventArgs e) 在 System.Windows.Forms.Control.OnClick(EventArgs e) 在 System.Windows.Forms.Button.OnClick(EventArgs e) 在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs 事件) 在 System.Windows.Forms.Control.WmMouseUp(消息和 m,MouseButtons 按钮,Int32 点击) 在 System.Windows.Forms.Control.WndProc(消息和 m) 在 System.Windows.Forms.ButtonBase.WndProc(消息和 m) 在 System.Windows.Forms.Button.WndProc(消息和 m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(消息& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息和 m) 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam) 在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(味精和味精) 在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID,Int32 原因,Int32 pvLoopData) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 原因,ApplicationContext 上下文) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 原因,ApplicationContext 上下文) 在 System.Windows.Forms.Application.Run(窗体 mainForm) 在 c:\tfs\DocuWare .NET\DocuWare NewGen\src\Tools\MSI_Comparison\MSI_Comparison_GUI\Program.cs: 18 中的 MSI_Comparison_GUI.Program.Main() 在 System.AppDomain._nExecuteAssembly(程序集程序集,字符串 [] 参数) 在 System.AppDomain.ExecuteAssembly(字符串 assemblyFile,证据 assemblySecurity,String [] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(对象状态) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态) 在 System.Threading.ThreadHelper.ThreadStart() 内部异常:

【问题讨论】:

  • 你能告诉我们代码,你是如何创建对话框的吗?您是否在程序中创建了另一个线程?
  • 已添加为您的阅读乐趣:P
  • 你确定你当时在主线程中执行,并且在主线程中已经创建了openFileDialog1?
  • 也许你的项目有不止一个Main 方法和另一个你认为使用的方法?这里使用的是MSI_Comparison_GUI.Program.Main() in c:\tfs\DocuWare .NET\DocuWare NewGen\src\Tools\MSI_Comparison\MSI_Comparison_GUI\Program.cs:line 18。
  • @Adkins 如果是这种情况,您的最后一个选择是尝试使用尽可能少的代码在另一种解决方案中重现此问题。如果可以,请打开Connect w/MS。在这里发布addy,我会赞成它。如果您不能重现,则必须逐行、逐个类、逐个项目文件地梳理这两个项目,看看两者之间有什么不同。抱歉,我无法提供更多帮助。

标签: c#


【解决方案1】:

您可能面临 Connect1 上报告的以下问题:

.vshost.exe forces wrong threading model used when debugging a .exe if a .dll of the same name exists in same bin directory

根据该问题,当您同时拥有 myprogram.exemyprogram .dll 文件在您的输出文件夹中。

该问题可能特定于某些旧版本的 Visual Studio (2005),我无法使用 VS 2010 重现它。

显而易见的解决方法是更改​​ dll 的名称或将 dll 移动到另一个文件夹。

这种情况可能是因为您将项目的输出类型从类库更改为 Windows 应用程序。

1不清楚这个问题是否被微软确认,只是说这个问题不在VS产品团队的责任范围内。

【讨论】:

  • @Adkins:我只是好奇:这真的是问题所在吗?那你在 VS 2005 上吗?
  • Dangit,我正在寻找类似的东西。我的 fu 失败了。
  • @Hans Passant:由于我无法重现问题,因此很难知道原因,我个人怀疑vshost机制中存在错误,但可能与M​​S的shell团队有关。或者给一些懒惰的支持工程师;-)
  • 如果我们收到 OP 的回复,那就太好了。我发现反馈报告难以置信。这不是托管过程的工作方式。
  • @Hans Passant:这实际上是罪魁祸首。我没有外部 dll、模块、工具包等。我剥离了我的程序,使其全部是纯 autogen VS 代码,加上我打开对话框的调用,问题仍然存在。一旦我更改了 exe 的名称(只需添加“_GUI”),问题就消失了。我仍然对此感到困惑,但至少问题已经解决并消失了!
【解决方案2】:

你有一个不可能的堆栈跟踪。很明显,线程不是问题的原因,一切都在主线程上运行,并且 Main 方法上的 [STAThread] 属性正在设置单元状态。堆栈跟踪显示它确实是入口点。

好吧,坏消息,某种附加组件正在与您的主线程发生冲突。做一些讨厌的事情,比如调用 CoUninitialize 太多次。我曾经遇到过这种情况,花了我一个月的时间才找到它。使用 Project + Properties,Debug 选项卡开始诊断,勾选“Enable unmanaged code debugging”。这让您可以看到哪些 DLL 正在加载到您的程序中,它显示在“输出”窗口中。

第一次领先是当对话框在 first 时间显示正常但在 second 时间失败时。然后你就有了某种 shell 扩展处理程序,它会蠕虫到你的程序中。使用 SysInternals 的 AutoRuns 实用程序并禁用任何非 Microsoft 制造的外壳扩展处理程序。

当对话立即失败时会变得更难。然后使用 Debug + Windows + Modules 并浏览 DLL 列表。注意它们来自哪里,显示在路径列中。不信任任何不像 .NET 或 Microsoft DLL 这样的东西。特别是当您启用 Microsoft 符号服务器时没有符号文件是一个线索。在这方面取得一些进展的一个好方法是将该列表与您在另一台没有此问题的机器上看到的列表进行比较。

我确实有一个关于这个的战争故事。我的 COM 代码在数百台机器上崩溃,我只需要一个小型转储。我花了一个月的时间才发现源代码,一个名为 ffdshow 的开源项目。分布非常广泛,也使用不同的名称。它有一个错误,调用 CoUnitialize 的次数太多了。该错误在发行版中存在两年,但大约一年半前得到修复。 非常很难诊断,直到我开始查看旧版本时才接近它。如果您确实在“模块”窗口中看到了 ffdshow,那么您就关闭了 :)

祝你好运,让我们知道坏人。

【讨论】:

  • “你有一个不可能的堆栈跟踪”。 “不可能”是什么意思?堆栈跟踪对我来说就像一个常规的调试堆栈跟踪......
  • @0xA3: 不可能,如“那不应该抱怨公寓状态”。
【解决方案3】:

不能说没有代码。如果是控制台应用,请在调用方法之前添加以下内容:

Console.Write(System.Threading.Thread.CurrentThread.ApartmentState);

否则,

MessageBox.Show(System.Threading.Thread.CurrentThread.ApartmentState);

看看线程单元状态到底是什么。

【讨论】:

  • 这是一个基本的 Windows 窗体应用程序,没有故意进行线程化。我按照建议使用了那个消息框,它告诉我状态是 MTA。我真的不明白这是怎么回事,就像我说的那样 Main 被标记为 [STAThread] 是由 Visual Studio 自动完成的,除了对 OpenFileDialog 的基本调用之外,我不执行任何其他线程。
  • @adkins 你确定你没有使用屏蔽多线程的框架类吗?喜欢 BackgroundWorker 还是在委托上使用“BeginInvoke”?多线程并非偶然发生。您可以调试并让该异常再次抛出吗?如果您使用异常对象中的调用堆栈更新您的问题,我可能会告诉您转换到 MTA 的位置,如果您正在使用这些转换的框架类之一。
  • 它被添加了,但它并不漂亮。到出现此错误时,我根本没有使用任何东西。我只是加载程序并单击一个按钮来打开 OpenFileDialog。
  • @Adkins 有内部异常吗?
  • 完全没有内部异常。所见即所得。
【解决方案4】:

尝试在主过程、对话框的创建点和使用位置设置断点。然后看看你实际在哪个线程中。另外,检查Thread.CurrentThread.GetApartmentState() 在这些点上的值。

【讨论】:

  • 如上所述,当前线程单元状态是 MTA,但我不确定为什么。
  • @Adkins:是否在所有这些位置都使用 MTA,甚至直接在 main 方法中?
  • @0xA3 我将检查作为主要方法中的第一条语句,它是 MTA。严重的是 STAThread 属性,主签名,然后是检查。
  • 如果不是从 VS 而是从资源管理器或命令行启动 Debug 版本,您会得到相同的结果吗?将 MessageBox.Show(System.Threading.Thread.CurrentThread.ApartmentState); 直接放入您的 main 方法中。
  • @0xA3 当我在 VS 之外运行它时,它仍然是调试版本,它是 STA 并且工作正常。任何机会你都可以为我阐明这一点。我很欣赏这个答案,但如果可能的话,我想更好地理解它。此外,如果您将其放在答案中,我可以将其标记为已回答。谢谢!
【解决方案5】:
t.SetApartmentState(ApartmentState.STA);

上面的代码行对我有用。试一次。

【讨论】:

    猜你喜欢
    • 2018-12-27
    • 2020-07-01
    • 2017-09-13
    • 1970-01-01
    • 2013-07-29
    • 2021-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多