CreateProcess — lpApplicationName против lpCommandLine

Я использовал Win API CreateProcess, и мне было интересно, в чем разница между использованием lpApplicationName и lpCommandLine для аргументов и. только параметр lpCommandLine.

Например:

CreateProcess(NULL, L"C:\Path\To\Notepad.exe", L"C:\Path\To\File\To\Load.txt"... etc
CreateProcess(NULL, NULL, L"C:\Path\To\Notepad.exe C:\Path\To\File\To\Load.txt"... etc

Я предполагаю, что второй вариант, где используется только lpCommandLine, будет похож на открытие cmd.exe и запуск именно этой строки. Но как насчет первой строки, она загружает приложение и указывает аргументы командной строки по-другому?

Я просмотрел документацию MSDN для API, но, похоже, она не очень подробно описывает, что происходит, что могут содержать эти параметры, и это нормально, но я просто не понимаю, что я должен делать, когда есть есть несколько способов сделать это.

Обратите внимание: я знаю, что две строки примера могут не работать, так как для lpCommandLine требуется LPTSTR, а не LPCTSTR. Это просто для простоты понимания.

Большое спасибо за любую помощь!

Энди


person Andy    schedule 18.04.2011    source источник
comment
Что заставляет вас говорить, что MSDN не объясняет подробно, что происходит? Вряд ли можно подробнее. В трех словах, lpApplicationName более или менее делает именно то, о чем вы просите, и ничего более, тогда как lpCommandLine добавляет много интерпретаций и магии (добавление расширений, поиск PATH и т. д.). И, как сказал Джон, часто лучший способ — использовать оба.   -  person Damon    schedule 18.04.2011
comment
Хорошо, может быть, есть какая-то деталь, которую я не понял/пропустил в первый раз, но она все еще кажется мне немного двусмысленной.   -  person Andy    schedule 19.04.2011


Ответы (3)


Рекомендуемый способ - использовать оба параметра. Если вы не укажете lpApplicationName, вы позволите Windows проанализировать lpCommandLine, чтобы определить имя приложения. Поскольку пробел является допустимым символом в именах файлов и каталогов, это может (в редких случаях) привести к запуску неправильного приложения. (например, если у вас есть c:\program.exe и вы запускаете программу из каталога c:\program files в Windows XP).

В обоих случаях вы должны использовать имя приложения в lpCommandLine, так как оно используется для вычисления Argv[0].

person John    schedule 18.04.2011
comment
Рекомендуемый способ — использовать только командную строку и передать NULL в качестве аргумента lpApplicationName. Имя приложения необходимо заключить в кавычки, если оно содержит пробелы. Используйте оба аргумента только в том случае, если вам нужно передать нестандартную командную строку (та, которая не содержит путь к исполняемому образу в качестве первого аргумента) в создаваемый процесс. - person IInspectable; 03.10.2015
comment
@IInspectable, на чем вы основываете свои рекомендации? Прочитайте страницу MSDN для CreateProcess в примечаниях по безопасности, проблема описана затем... Чтобы избежать этой проблемы, не передавайте NULL для lpApplicationName. Если вы передаете NULL для lpApplicationName... Итак, Microsoft рекомендует не передавать NULL, но если вы это сделаете, используйте кавычки. - person John; 07.10.2015
comment
Рекомендация основана на логических рассуждениях. Большинство приложений ожидают исполняемый образ, запустивший процесс, в качестве первого аргумента (argv[0]). В таких случаях передачи lpCommandLine достаточно, и это предотвращает создание повторяющихся, избыточных данных. Передача как lpApplicationName, так и lpCommandLine позволяет построить командную строку, которая не содержит исполняемый образ в качестве первого аргумента. Его следует использовать в тех редких случаях, когда приложение ожидает (нестандартную) командную строку, в которой нет исполняемого образа в качестве первого аргумента. - person IInspectable; 07.10.2015
comment
Если вы используете lpApplicationName, система не будет использовать переменную среды PATH для поиска исполняемого файла, что может быть не тем, что вам нужно. Поэтому я должен поддержать @IInspectable по поводу использования lpCommandLine с правильно указанным путем в качестве предпочтительного варианта. Вы должны использовать lpApplicationName только в том случае, если точный исполняемый файл, который вы собираетесь запустить, известен по его абсолютному пути. - person Yakov Galka; 08.03.2019

Я никогда не использую lpApplicationName и всегда цитирую часть приложения lpCommandLine, в вашем примере я бы выполнил "C:\Path\To\Notepad.exe" "C:\Path\To\File\To\Load.txt" (цитирование всех путей, переданных в CreateProcess, является хорошей идеей). Простое использование lpApplicationName может вызвать проблемы с дочерними процессами, которые обращаются к argv[0], поэтому Я держусь подальше от этого.


<rant> Использование CreateProcess для чего-либо, кроме вас самих, может быть проблематичным, поскольку NT6+ может в любой момент решить, что выполняемая вами вещь требует прав администратора из-за прокладок совместимости приложений и/или обнаружения установщика, и тогда CreateProcess просто не работает. Если вам не нужно использовать отладку или отказаться от флагов задания, я бы предложил просто вызвать ShellExecute[Ex], чтобы быть в безопасности...</rant>

person Anders    schedule 18.04.2011
comment
Последнее замечание, которое вы делаете об использовании ShellExecute, интересно, это то, что мы изначально использовали, но нам пришлось перейти к процессу создания, потому что Adobe Reader нуждается в указанном блоке среды текущего пользователя (поэтому он ищет в папке документов пользователя, а не в системном профиле), и я не думаю, что вы можете сделать это с ShellExecute. Если мы используем выполнение оболочки, а Adobe Reader является обработчиком по умолчанию, он загружается, но просто падает, поскольку он запрещает доступ к папкам системного профиля. Какие-либо предложения? :) - person Andy; 19.04.2011
comment
@Энди: это разглагольствования. Не принимайте это всерьез. Настоящая проблема заключается в выполнении случайных строк, например. из реестра, не зная, на что они указывают. Если вы не знаете, что вы выполняете, тогда да, вы можете попробовать запустить установщики. Что касается запуска Adobe Reader, то это очевидный случай для ShellExecute. Не пытайтесь угадать, что я использую в качестве программы для чтения PDF. Я не использую Adobe, частично из-за того, что он глючит. - person MSalters; 19.04.2011

Согласно MSDN, lpApplicationName является необязательным и может иметь значение NULL. В этом случае имя модуля должно быть первым токеном, разделенным пробелами, в строке lpCommandLine.

Если исполняемый модуль является 16-разрядным приложением, lpApplicationName должно быть NULL, а строка, на которую указывает lpCommandLine, должна указывать исполняемый модуль, а также его аргументы.

person karlphillip    schedule 18.04.2011