Что может заставить ShellExecute вернуть SE_ERR_OOM (ошибка 8)?
Я часто вызываю ShellExecute из собственного приложения C++/Win32, чтобы выполнить любой элемент оболочки, выбранный конечным пользователем из GUI. Элементы - это исполняемые файлы / скрипты или ссылки (.lnk). В некоторых условиях, которые остаются для меня неясными, следующая функция иногда возвращает 8
(SE_ERR_OOM
ошибка; только очень кратко задокументировано). В результате элемент не выполняется. Что может вызвать эту ошибку?
int doExecute(LPCTSTR file, LPCTSTR args, LPCTSTR workDir)
{
assert(file && *file);
HRESULT hRes = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
assert(hRes == S_OK || hRes == S_FALSE);
int code = (int)ShellExecute(NULL, NULL, file, args, workDir, SW_SHOWNORMAL);
doLog("ShellExecute returned: %d, %u", code, GetLastError()); // EDIT
CoUninitialize();
return code;
}
Контекст:
- Windows8 64bit, приложение 32bit, не может попробовать на любой другой машине
- Приложение многопоточное
- По замыслу, новый поток всегда создается специально для этого вызова
- Утверждения в этом коде никогда не нарушаются во время моих сеансов отладки
- Само приложение не использует COM напрямую, но может вызвать API-интерфейсы Win32, которые косвенно его используют, поскольку оно довольно часто взаимодействует с оболочкой. В этих случаях COM всегда инициализируется с такими же флагами, как показано выше.
- Флаги переданы
CoInitializeEx
были выбраны вслепую после рекомендации MSDN (см. документацию ShellExecute), а не из-за личного выбора
Наблюдения об ошибке до сих пор:
- Это редкость
- Это произошло только после одной или нескольких спящих (мое приложение всегда работает на моем ноутбуке, и я использую его довольно часто)
- Немедленный вызов GetLastError после вызова
ShellExecute
всегда вернулся0
- Насколько я помню, это всегда происходило при попытке выполнить
.lnk
файл, но не всегда один и тот же файл - Быстрый взгляд на
Process Explorer
(sysinternals.com), запущенный на машине, не показывает пика использования памяти - редактировать: я сделал последний тест перед публикацией здесь, позвонив
doExecute
200 раз подряд. Все процессы были созданы без ошибок.
1 ответ
После довольно продолжительного тестирования эта ошибка больше не возникала после того, как я применил некоторые изменения в коде, следуя советам @DavidHeffernan и @RossRidge. Хотя я не могу считать это окончательным ответом как таковым, поскольку я до сих пор не знаю, что именно произошло под капотом, я до сих пор не смог воспроизвести ошибку.
Примененные модификации:
- Заменил
ShellExecute
позвонить поShellExecuteEx
, - Вызов
CoInitializeEx
раз и навсегда для каждой новой темы, без ееCoUninitialize
Счетчик части. Но сохранил следующее вложенноеCoInitializeEx
-CoUninitialize
пар.
Изменить: В случае, если это кому-то нужно, просто для подтверждения, что проблема больше не возникает, даже после нескольких месяцев испытаний с применением этих изменений.