5 марта 2014 г.

Когда CreateProcess завершается с ошибкой ERROR_SUCCESS

Не в первый раз с этим сталкиваюсь и всё время чешу голову. Решил сделать заметку, чтобы не забыть.

CreateProcess возвращает True, если она успешно запустила программу, и False в случае ошибки. Когда CreateProcess возвращает False, вы можете вызвать GetLastError, чтобы узнать причину неудачи.

Типичный код может выглядеть так:
Win32Check(CreateProcess(...));

Проблема, с которой я столкнулся, заключалась в том, что CreateProcess возвращала False, но GetLastError возвращала 0 (ERROR_SUCCESS). В результате программа выкидывала исключение с сообщением "Операция успешно завершена" ("The operation completed successfully").

Обычно, когда происходит такое, я в первую очередь ищу подводные камни, которые могли бы испортить код ошибки, например. Во вторую очередь я анализирую функцию: быть может я неверно обрабатываю код ошибки, не все функции сообщают коды через LastError. Тем не менее, в нашем случае код никто не портит и CreateProcess его использует.

Как оказалось, причина такого поведения CreateProcess - неверный аргумент. А именно: текущий каталог для программы (lpCurrentDirectory). Если вы указываете этот параметр, но при этом он не содержит допустимый (корректный) путь, то CreateProcess завершится с ошибкой, но не установит причину ошибки. Исправить это можно так:
SetLastError(ERROR_INVALID_PARAMETER);
Win32Check(CreateProcess(...));

P.S. Другие не очевидные моменты с CreateProcess:
1. Если вы указываете первый параметр (имя программы), то программа должна указываться дважды: в первом и во втором параметрах. Иными словами, второй параметр - это полная командная строка, передаваемая в программу "как есть", а не "параметры программы", как ошибочно трактует его 80% людей.
2. Второй параметр не может быть константой.
3. Правильная расстановка кавычек - ещё один больной вопрос.
4. CreateProcess пытается исправлять неверные параметры, что означает что ваш (неверный) код может работать "почти всегда".

P.P.S. Добавьте кто-нибудь описание этого поведения в MSDN, мне не даёт писать, выкидывает ошибку "Error occurred while saving your data".

Читать ещё по CreateProcess:

7 комментариев :

  1. С этой проблемой я столкнулся, когда перешел с D6 на D2010, и достаточно быстро решил ее аналогичным способом. На D6 сей проблемный эффект у меня не наблюдался.

    ОтветитьУдалить
  2. подскажите пожалуйста, почему не работает такой вариант:
    CreateProcess(nil, 'ping -a 11.111.12.38 > D:\file.txt', 0, 0, false, CREATE_NO_WINDOW, 0, 0, SI, PI), выдает ошибку: неверный параметр >. А вариант CreateProcess(nil, 'ping -a 11.111.12.38', 0, 0, false, CREATE_NO_WINDOW, 0, 0, SI, PI) работает

    ОтветитьУдалить
  3. Потому что операторы перенаправления вывода - это функция командного интерпретатора.

    Если вы хотите запустить консольную программу и получить в переменную её вывод, то вам нужно использовать перенаправление вывода. Это можно сделать двумя способами.

    Способ первый описан по ссылке (использовать операторы перенаправления) - не самый красивый способ, т.к. включает в себя "лишний" файл. Но зато очень простой.

    Способ второй - использовать перенаправление вывода, предоставляемое самой функцией CreateProcess (см. поля hStdInput и hStdOutput). Это сложнее, но более правильно: вывод попадает к вам напрямую, минуя промежуточный файл. Не сложно найти в интернете и пример - по ключевым словам "delphi перенаправление вывода".

    ОтветитьУдалить
  4. А что случилось с EurekaLog ? Проект живой или нет ?

    ОтветитьУдалить
  5. Блог умер. Пичаль...

    ОтветитьУдалить
  6. "Блог умер. Пичаль... "

    Да, вроде как нет. Но автор почти год был сильно занят на других проектах и новых статей не выходило. При том, что у автора невероятно высокий уровень статей можно понять причину такой задержки. На написание каждой статья тратится огромное количество времени и усилий.

    ОтветитьУдалить
  7. Анонимный23 июля 2015 г., 21:32

    Автор не совсем прав https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и (опционально) ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.