Что может заставить 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 пар.

Изменить: В случае, если это кому-то нужно, просто для подтверждения, что проблема больше не возникает, даже после нескольких месяцев испытаний с применением этих изменений.

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