2015-11-06 100 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,這樣做是正確的。

相關問題