Текущий поток 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

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

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

Спасибо!

1 ответ

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

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

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

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

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

Другие вопросы по тегам