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:
- Этот проблемный CreateProcess...
- Недокументированный CreateProcess
- CreateProcess не ждёт, пока процесс запустится
- Почему функция CreateProcess делает автоисправление командной строки?
- Перенаправление вывода выполняется командным интерпретатором
- Почему вам (никогда) не следует использовать ShellExecute и WinExec
С этой проблемой я столкнулся, когда перешел с D6 на D2010, и достаточно быстро решил ее аналогичным способом. На D6 сей проблемный эффект у меня не наблюдался.
ОтветитьУдалитьподскажите пожалуйста, почему не работает такой вариант:
ОтветитьУдалить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) работает
Потому что операторы перенаправления вывода - это функция командного интерпретатора.
ОтветитьУдалитьЕсли вы хотите запустить консольную программу и получить в переменную её вывод, то вам нужно использовать перенаправление вывода. Это можно сделать двумя способами.
Способ первый описан по ссылке (использовать операторы перенаправления) - не самый красивый способ, т.к. включает в себя "лишний" файл. Но зато очень простой.
Способ второй - использовать перенаправление вывода, предоставляемое самой функцией CreateProcess (см. поля hStdInput и hStdOutput). Это сложнее, но более правильно: вывод попадает к вам напрямую, минуя промежуточный файл. Не сложно найти в интернете и пример - по ключевым словам "delphi перенаправление вывода".
А что случилось с EurekaLog ? Проект живой или нет ?
ОтветитьУдалитьБлог умер. Пичаль...
ОтветитьУдалить"Блог умер. Пичаль... "
ОтветитьУдалитьДа, вроде как нет. Но автор почти год был сильно занят на других проектах и новых статей не выходило. При том, что у автора невероятно высокий уровень статей можно понять причину такой задержки. На написание каждой статья тратится огромное количество времени и усилий.
Автор не совсем прав https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
ОтветитьУдалитьПрошу прощения за некропостинг, но возникла вот такая проблема, не могу понять, почему код не работает.
ОтветитьУдалитьhttp://www.cyberforum.ru/delphi-winapi/thread1872690.html
Цитирую: "Второй параметр не может быть константой".
УдалитьUniqueString своему CmdLine сделайте.
Эээ... я полагал, что передаю переменную, а не константу. UniqueString сделал, все завелось, большое спасибо! =)) Но в чем ошибка была я так и не понял.
УдалитьНу так в том коде по ссылке в переменной записана константа: строковый литерал 'что-то-там'. Это область памяти read only. Когда CreateProcess в неё попробует записать - получит отлуп в виде Access Violation.
УдалитьWindows 7 с почти последними обновами + Delphi XE2.
ОтветитьУдалить"SetLastError(ERROR_INVALID_PARAMETER);" не ставил.
И получаю такой код ошибки:
0x0000010B - Неверно задано имя папки
Да, видимо они подправили.
УдалитьDelphi 7 на Windows 10 x64 - при указании несуществующего каталога в lpCurrentDirectory ошибка ERROR_DIRECTORY (The directory name is invalid, == 267).
Может в "Простая обёртка к CreateProcess, функция-обёртка WinExec" следует поменять SetLastError(ERROR_INVALID_PARAMETER) на SetLastError(ERROR_DIRECTORY), для соответствия?
Хотя зачем там вообще что-либо - там ведь ни в каком виде не предусмотрено указание lpCurrentDirectory, оно прописано строго как "nil".
Я сейчас уже не вспомню, в каком окружении это было.
Удалить> Может в "Простая обёртка к CreateProcess, функция-обёртка WinExec" следует поменять SetLastError(ERROR_INVALID_PARAMETER) на SetLastError(ERROR_DIRECTORY), для соответствия?
Нет, ведь это сделано для "всех прочих, непредусмотренных ситуаций". Т.е. не факт, что именно для этой ситуации. Она - просто одна из возможных (да, она единственная известная мне, но сути это не меняет).