2015-11-06 104 views
0

有人可以向我解释我看到的这个错误是什么吗?OpenFileDialoug当前线程在OLE调用之前必须是STA

在进行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.Threading.ThreadStateException' 的未处理的异常出现在System.Windows.Forms.dll中

附加信息:当前线程必须在进行OLE呼叫之前设置为单线程单元(STA)模式。确保您的Main函数具有标记的STAThreadAttribute。只有在调试器连接到进程时才会引发此异常。

我不是很熟悉这个错误是在说什么。我只知道一些关于线程的知识,但我不确定线程​​是如何成为问题的。我已经看到一些人引用像STAThread这样的东西,但没有提供关于它做什么的明确解释,而且Microsoft的文档没有提到在调用SaveFileDialog/OpenFileDialog时抛出此异常,或者如何处理它。

谢谢!

回答

3

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

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

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

这只是一个承诺,但是,你也必须实现你所承诺的。采取两件事,你承诺永远不会阻止线程,你承诺泵送一个消息循环。 Application :: Run()在.NET程序中。永不封锁的诺言确保你不会造成死锁。消息循环承诺表示您实施producer-consumer problem的解决方案。

这不应该是一个问题,它是如何在您的项目中摸索很不清楚。对话的另一个隐含要求是它必须拥有一个所有者。另一个窗口可以放在上面。如果它没有,那么用户从来没有看到对话的可能性非常高。被另一个程序的窗口覆盖,用户只能偶然发现它。当你创建窗口时,你总是必须调用Application :: Run(),这样窗口可以响应用户输入。在C++/CLI应用程序中使用boilerplate code,这样做是正确的。

相关问题