Одна из причин, почему ShellExecute возвращает SE_ERR_ACCESSDENIED, а ShellExecuteEx возвращает ERROR_ACCESS_DENIED
Это перевод One possible reason why ShellExecute returns SE_ERR_ACCESSDENIED and ShellExecuteEx returns ERROR_ACCESS_DENIED. Автор: Реймонд Чен.
(этот странный заголовок написан для поисковой оптимизации)
Один клиент сообщил, что при вызове ShellExecute
эта функция иногда завершалась с ошибкой SE_ERR_ACCESSDENIED
(= 5) — в зависимости от того, что они пытались открыть (а если бы они использовали ShellExecuteEx
, то они получали бы ошибку ERROR_ACCESS_DENIED
(перевод поста)).
После долгой «игры в пинг-понг», проверки файловых ассоциаций и т.п., один из разработчиков из нашей команды использовал свой хрустальный шар и спросил: «А вы случайно не вызываете её из MTA?» (MTA = multi-threaded apartment, многопоточный апартмент).
«Да», — ответил клиент. — «ShellExecute
вызывается из специально выделенного MTA-потока. Проблема в этом?».
Ну, вообще-то, да. И об этом явно сказано в документации к ShellExecute
:
Поскольку
ShellExecute
может делегировать выполнение расширениям Оболочки (источникам данных, обработчикам контекстных меню, реализациям действий), которые активируются через COM, то COM должен быть инициализирован до того, как ваш код вызоветShellExecute
. Некоторые расширения Оболочки требуют, чтобы COM был инициализирован в однопоточном апартменте (STA).
Как правило, функции Оболочки требуют STA. Вспомните, что MTA подразумевает отсутствие интерфейса пользователя. Если вы попытаетесь использовать apartment-threaded объект из MTA-потока, вам потребуется маршаллер, а если такого маршаллера нет, то вызов провалится.
Это также объясняет, почему вызов ShellExecute
завершается неудачей только для некоторых типов файлов: если обработка типа файла не требует создания объекта COM, то ситуация с несовпадением MTA/STA никогда не произойдёт.