2015-11-06 15 views
0

Может кто-нибудь объяснить мне, что это за ошибка, которую я вижу?OpenFileDialoug Текущая тема должна быть STA до того, как сделанные вызовы OLE

Текущий поток должен быть установлен в режим однопоточной квартиры (STA) до того, как вызовы OLE могут быть выполнены.

В частности, я пытаюсь открыть SaveFileDialog/OpenFileDialog внутри C++/CLI в форме.

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

Дополнительная информация: Текущий поток должен быть настроен на режим однопоточной квартиры (STA) до того, как могут быть сделаны вызовы OLE. Убедитесь, что ваша основная функция имеет STAThreadAttribute, отмеченный на нем. Это исключение возникает только в том случае, если к процессу прикреплен отладчик.

Я не очень хорошо знаю, что говорит эта ошибка. Я немного знаю о потоках, но я не уверен, что проблема с потоками будет проблемой. Я видел, как некоторые люди ссылаются на такие вещи, как STAThread, не давая ясного объяснения тому, что он делает, и в документации Microsoft не упоминается о том, что это исключение было вызвано при вызове SaveFileDialog/OpenFileDialog или как его обрабатывать.

Спасибо!

ответ

3

Когда вы используете OpenFileDialog, тогда в ваш процесс загружается лот кода. Не только компонент операционной системы, который реализует диалог, но также оболочки расширения. Плагины, которые программисты пишут, чтобы добавить функциональность в проводник Windows. Они также работают в этом диалоге. Есть много, с которыми вы, несомненно, знакомы, является расширение, которое делает .zip-файл похожим на папку.

Одна вещь, которую Microsoft сделала, когда они спроектировали подключаемый интерфейс, составляет , а не, заставляя расширение быть потокобезопасным. Потому что это очень сложно сделать и часто является основным источником ошибок. Они выразили обещание, что поток, создающий экземпляр плагина, равен также поток, на который сделан любой вызов плагина. Таким образом, убедитесь, что плагин всегда используется поточно-безопасным способом.

Это, однако, требует от вас небольшой помощи. Вы должны сделать обещание, что ваша нить, вызывающая OpenFileDialog :: Show(), соблюдает требования однопоточной квартиры. STA для краткости. Вы выполняете обещание с атрибутом [STAThread] в точке входа Main() вашей программы. Или, если это поток, который вы создали сами, вызывается при вызове Thread :: SetApartmentState() перед его запуском.

Это просто обещание, однако вы также должны реализовать то, что вы обещали. Принимает две вещи: вы обещаете никогда не блокировать нить, и вы обещаете перекачать контур сообщения. Приложение :: Run() в .NET-программе. Небезопасное обещание гарантирует, что вы не будете создавать тупик. И обещание цикла сообщений говорит, что вы реализуете решение для producer-consumer problem.

Это никогда не должно быть проблемой, очень неясно, как это пошатнулось в вашем проекте. Еще одно неявное требование для диалога состоит в том, что он должен иметь владельца. Другое окно, на котором оно может быть сверху.Если у него его нет, тогда есть очень высокие шансы, что пользователь никогда не увидит диалог. Покрытый окном другой программы, пользователь может только когда-либо найти его случайно. Когда вы создаете окна, вы всегда должны вызывать Application :: Run(), чтобы окна могли отвечать на ввод пользователя. Используйте boilerplate code в приложении C++/CLI, чтобы это было сделано правильно.