【问题标题】:OpenFileDialoug Current Thread Must Be STA before OLE calls made在进行 OLE 调用之前,OpenFileDialog 当前线程必须是 STA
【发布时间】:2023-03-18 17:05:01
【问题描述】:

谁能解释一下我看到的这个错误是什么?

在进行 OLE 调用之前,必须将当前线程设置为单线程单元 (STA) 模式。

具体来说,我正在尝试在表单上的 C++/CLI 中打开 SaveFileDialog/OpenFileDialog。

SaveFileDialog^ saveFileDialog1 = gcnew SaveFileDialog;
saveFileDialog1->ShowDialog();
    if (saveFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
    {
        s = saveFileDialog1->OpenFile();
        }
        s->Close();
    }

抛出的错误是

System.Windows.Forms.dll 中出现“System.Threading.ThreadStateException”类型的未处理异常

附加信息:在进行 OLE 调用之前,必须将当前线程设置为单线程单元 (STA) 模式。确保您的 Main 函数上标记了 STAThreadAttribute。仅当将调试器附加到进程时才会引发此异常。

我不太熟悉这个错误的含义。我对线程有一点了解,但我不确定线程​​在这里会成为一个问题。我看到有些人引用了 STAThread 之类的东西,但没有明确说明它的作用,而且微软的文档也没有提到在调用 SaveFileDialog/OpenFileDialog 时抛出这个异常,或者如何处理它。

谢谢!

【问题讨论】:

    标签: multithreading c++-cli openfiledialog savefiledialog sta


    【解决方案1】:

    当您使用 OpenFileDialog 时,会有 很多 代码被加载到您的进程中。不仅是实现对话框的操作系统组件,还有 shell 扩展。程序员为向 Windows 资源管理器添加功能而编写的插件。他们也在那个对话框中工作。有很多,你肯定熟悉的是使 .zip 文件看起来像文件夹的扩展名。

    微软在设计插件界面时所做的一件事是强制扩展是线程安全的。因为这很难做到,而且通常是错误的主要来源。他们承诺创建插件实例的线程也是对插件进行任何调用的线程。从而确保插件始终以线程安全的方式使用。

    不过,这需要您提供一点帮助。您必须承诺您的线程,即调用 OpenFileDialog::Show() 的线程,遵守单线程单元的要求。简称STA。您在程序的 Main() 入口点上使用 [STAThread] 属性做出承诺。或者,如果它是您自己创建的线程,则在启动它之前调用 Thread::SetApartmentState()。

    这只是一个承诺,但是您还必须实现您的承诺。需要做两件事,你承诺永远不会阻塞线程,你承诺泵送一个消息循环。 .NET 程序中的 Application::Run()。 never-block 承诺确保您不会导致死锁。消息循环承诺说您实现了producer-consumer problem 的解决方案。

    这绝不应该是一个问题,目前还不清楚这是如何在您的项目中搞砸的。对话的另一个隐含要求是它必须有一个所有者。另一个可以放在上面的窗口。如果没有,那么用户很有可能永远不会看到该对话框。被另一个程序的窗口覆盖,用户只能偶然发现它。当您创建窗口时,您还必须始终调用 Application::Run() 以便窗口可以响应用户输入。在 C++/CLI 应用程序中使用 boilerplate code 以便正确完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多