В процессе программирования на Delphi и Pascal иногда возникает необходимость запускать внешние приложения или команды из кода. Для этого в объектно-ориентированном программировании на Паскале часто используется функция CreateProcess. Однако, при работе с окружющими переменными в команде, вставленной в CreateProcess, может возникнуть проблема: окружющие переменные не расширяются, как если бы вы запускали команду напрямую в командной строке Windows.
Рассмотрим пример кода, в котором пытаются запустить блокнот с помощью окружной переменной %APPDATA%:
program TestConsole2;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils;
var
I: Integer;
ProgramName: String;
StartInfo: TStartupInfo;
ProcInfo: TProcessInformation;
CreateOK: Boolean;
begin
try
FillChar(StartInfo, SizeOf(StartInfo), #0);
FillChar(ProcInfo, SizeOf(ProcInfo), #0);
StartInfo.cb := SizeOf(StartInfo);
ProgramName := 'NOTEPAD %APPDATA%\test.txt';
CreateOK := CreateProcess(
nil, PChar(ProgramName), nil, nil, True, 0, nil, nil, StartInfo, ProcInfo);
if CreateOK then WaitForSingleObject(ProcInfo.hProcess, INFINITE);
Readln(ProgramName);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
При запуске этого кода окружная переменная %APPDATA% не будет расширена, в отличие от запуска команды напрямую в командной строке Windows.
Причина проблемы
Функция CreateProcess не расширяет окружные переменные автоматически, в отличие от командной строки Windows. Поэтому, если вы используете окружные переменные в команде, передаваемой в CreateProcess, они не будут расширены.
Решение проблемы
Для решения этой проблемы вы можете использовать функцию ExpandEnvironmentStrings, чтобы расширить окружные переменные перед передачей команды в CreateProcess. Вот пример кода, демонстрирующий это:
program TestConsole2;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils;
var
I: Integer;
ProgramName: String;
ExpandedProgramName: array[0..255] of Char;
StartInfo: TStartupInfo;
ProcInfo: TProcessInformation;
CreateOK: Boolean;
begin
try
FillChar(StartInfo, SizeOf(StartInfo), #0);
FillChar(ProcInfo, SizeOf(ProcInfo), #0);
StartInfo.cb := SizeOf(StartInfo);
ProgramName := 'NOTEPAD %APPDATA%\test.txt';
if ExpandEnvironmentStrings(PChar(ProgramName), ExpandedProgramName[0], 256) > 0 then
begin
CreateOK := CreateProcess(
nil, PChar(ExpandedProgramName), nil, nil, True, 0, nil, nil, StartInfo, ProcInfo);
if CreateOK then WaitForSingleObject(ProcInfo.hProcess, INFINITE);
end;
Readln(ProgramName);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
В этом примере мы используем ExpandEnvironmentStrings для расширения окружной переменной %APPDATA% перед передачей команды в CreateProcess. Это позволяет нам запустить блокнот с файлом, расположенным в папке, указанной окружной переменной %APPDATA%.
Альтернативный ответ
В качестве альтернативы вы можете использовать функцию ShellExecute, которая также может расширять окружные переменные. Однако, как упомянул пользователь в комментариях, ShellExecute может открывать файлы в пользовательском редакторе по умолчанию, что может быть более удобным для пользователя, чем принудительное открытие файла в блокноте.
Подтвержденный ответ
Используйте функцию ExpandEnvironmentStrings, чтобы расширить окружные переменные перед передачей команды в CreateProcess. Это позволит вам запускать внешние приложения и команды из кода с использованием окружных переменных, как если бы вы запускали их напрямую в командной строке Windows.
Вопрос касается проблемы с расширением окружных переменных в функции CreateProcess в языках программирования Delphi и Pascal, а также о том, как ее решить.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.