Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2017.01.15;
Скачать: CL | DM;

Вниз

Заново переписал Просьба оценить "корявость кода" v2   Найти похожие ветки 

 
AlexeyTG   (2014-12-19 20:25) [0]

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

program Project1;

uses
 Vcl.Forms, Winapi.Windows, System.SysUtils;
Var
StartInf: TStartupInfo;
ProcInf: TProcessInformation;
CmdLine: String;

{$R *.res}

function RunApp (const ProgName, ProgParams: String): boolean;
begin
 ZeroMemory(@StartInf,sizeof(StartInf));
 StartInf.cb:=SizeOf(StartInf);
 CmdLine:=Format(""%s" %s", [ProgName, ProgParams]);
 Result:=CreateProcess(PChar(ProgName),Pchar(CmdLine),nil,nil,False,NORMAL_PRIORI TY_CLASS,nil,nil,StartInf,ProcInf);
end;

begin
 If RunApp("C:\Windows\System32\cmd.exe","/?") then
  begin
    CloseHandle(ProcInf.hThread);
    WaitForSingleObject(ProcInf.hProcess, INFINITE );
    CloseHandle(ProcInf.hProcess);
    RunApp("C:\Windows\System32\notepad.exe","D:\1.txt");
    CloseHandle(ProcInf.hThread);
    CloseHandle(ProcInf.hProcess);
    Application.Terminate;
  end;

end.


 
кгшзх ©   (2014-12-19 20:34) [1]

убрать глобальные переменные
и сделать их праметрами.


 
Rouse_ ©   (2014-12-19 20:48) [2]

1. Первый параметр, передаваемый CreateProcess избыточен.
2. Это все не сработает на экзешниках от сетаперов от InstallShield, т.е. ты дождешся только завершения работы экзешника, а не того кода, который он запустит далее на исполнение.
3.Если файл, который ты хочешь запустить будет не найден, то CloseHandle под отладчиком сгенерирует ошибку (штатоное поведение на невалидный хэндл в процессе отладки).
4. Как я понял коды возврата будет анализировать Пушкин?


 
AlexeyTG   (2014-12-19 20:55) [3]

1. По первому парметру прочитал здесь http://www.gunsmoker.ru/2009/07/createprocess.html  
Application := "C:\Program Files\MySoft\MyApp.exe";
Params      := "-n:6 /p5 "C:\Program Files\MySoft\Data.bin"";
CmdLine     := Format(""%s" %s", [Application, Params]);
CreateProcess(PChar(Application), PChar(CmdLine), ...);
Так ошибок не будет никогда (обратите внимание на расстановку кавычек и пробелов). А если вы его не укажете - у вашей программы могут быть серьёзные проблемы с безопасностью. Особенно, если вы не используете кавычки.
И на другом ресурсе где обсуждали.

2. экзешник не сетапер, простое приложение, именно для него пишется лаунчер, на нем работает вроде нормально.

3, 4 begin
If RunApp("C:\Windows\System32\cmd.exe","/?") then
 begin
   CloseHandle(ProcInf.hThread);
   WaitForSingleObject(ProcInf.hProcess, INFINITE );
   CloseHandle(ProcInf.hProcess);
   RunApp("C:\Windows\System32\notepad.exe","D:\1.txt");
   CloseHandle(ProcInf.hThread);
   CloseHandle(ProcInf.hProcess);
   Application.Terminate;
 end else Application.Terminate

так нормально будет? :)


 
AlexeyTG   (2014-12-19 20:57) [4]

кгшзх вот тут вы меня в тупик поставиили, если их параметрами делать, то какие значения им передавать при вызове функции.


 
Rouse_ ©   (2014-12-19 21:04) [5]


> Так ошибок не будет никогда (обратите внимание на расстановку
> кавычек и пробелов). А если вы его не укажете - у вашей
> программы могут быть серьёзные проблемы с безопасностью.
>  Особенно, если вы не используете кавычки.

Заключи в кавычки путь к ПО, об этом написано как в MSDN так и с приведенной тобой статье.


> так нормально будет? :)

Нет, конечно :)
Да и вообще убери Application.Terminate - зачем он тут тебе?


 
Rouse_ ©   (2014-12-19 21:11) [6]

Лови три варианта запуска, покури над ними:

// Обычный запуск процесса и ожидание его завершения
function ExecAndWait(const ExeName, Params: string; out ExitCode: Cardinal; Timeout: Cardinal = MaxInt): boolean;
var
 sui: TStartupInfo;
 pi: TProcessInformation;
begin
 ZeroMemory(@sui, SizeOf(sui));
 sui.cb := SizeOf(sui);
 Win32Check(CreateProcess(nil, PChar(""" + ExeName + "" " + Params), nil, nil, False, 0, nil,
   nil, sui, pi));
 try
   CloseHandle(pi.hThread);
   Result := WaitForSingleObject(pi.hProcess, Timeout) = WAIT_OBJECT_0;
   if Result and (@ExitCode <> nil) then
     Win32Check(GetExitCodeProcess(pi.hProcess, ExitCode));
 finally
   CloseHandle(pi.hProcess);
 end;
end;

// Запуск и ожидание с поддержкой процессов с админским манифестом
function ExecAndWaitElevate(const ExeName, Params: string; out ExitCode: Cardinal; Timeout: Cardinal = MaxInt): boolean;
var
 SEI: TShellExecuteInfo;
begin
 ZeroMemory(@SEI, SizeOf(TShellExecuteInfo));
 SEI.cbSize := SizeOf(TShellExecuteInfo);
 SEI.lpFile := PChar(ExeName);
 SEI.lpParameters := PChar(Params);
 SEI.fMask := SEE_MASK_NOCLOSEPROCESS;
 SEI.nShow := SW_SHOWNORMAL;
 Win32Check(ShellExecuteEx(@SEI));
 try
   Result := WaitForSingleObject(SEI.hProcess, Timeout) = WAIT_OBJECT_0;
   if Result and (@ExitCode <> nil) then
     Win32Check(GetExitCodeProcess(SEI.hProcess, ExitCode));
 finally
   CloseHandle(SEI.hProcess);
 end;
end;

// Запуск процесса с поднятием прав до админа
function ExecAndWaitElevate2(const ExeName, Params: string; out ExitCode: Cardinal; Timeout: Cardinal = MaxInt): boolean;
var
 SEI: TShellExecuteInfo;
begin
 ZeroMemory(@SEI, SizeOf(TShellExecuteInfo));
 SEI.cbSize := SizeOf(TShellExecuteInfo);
 SEI.lpFile := PChar(ExeName);
 SEI.lpDirectory := PChar(ExtractFilePath(ExeName));
 SEI.lpParameters := PChar(Params);
 SEI.lpVerb := PChar("runas");
 SEI.fMask := SEE_MASK_NOCLOSEPROCESS;
 SEI.nShow := SW_SHOWNORMAL;
 Win32Check(ShellExecuteEx(@SEI));
 try
   Result := WaitForSingleObject(SEI.hProcess, Timeout) = WAIT_OBJECT_0;
   if Result and (@ExitCode <> nil) then
     Win32Check(GetExitCodeProcess(SEI.hProcess, ExitCode));
 finally
   CloseHandle(SEI.hProcess);
 end;
end;


 
AlexeyTG   (2014-12-19 21:15) [7]

Rouse_ ©
Заключи в кавычки путь к ПО, об этом написано как в MSDN так и с приведенной тобой статье


> Забываем про кавычки или ставим лишние. Кавычки нужны в
> командной строке (второй параметр CreateProcess) и не нужны
> в имени модуля (первый параметр).


If RunApp("C:\Windows\System32\cmd.exe",""/?"") then
RunApp("C:\Windows\System32\notepad.exe",""D:\1.txt"");
Получается так?

Да и вообще убери Application.Terminate - зачем он тут тебе? -> опять же прочитал, что после нее высвобождает ресурсы из памяти.


> > так нормально будет? :)
>
> Нет, конечно :)

а как тогда? :(


 
Rouse_ ©   (2014-12-19 21:21) [8]


> Получается так?

Не так - кавычки не там стоят.


> опять же прочитал, что после нее высвобождает ресурсы из
> памяти.

Она и так освободится - не надо настолько грубо управлять работой приложения.


> а как тогда? :(

Возьму любую из приведенных мной функций и используй ее для вызова.


 
AlexeyTG   (2014-12-19 21:34) [9]

if ExecAndWait("C:\Windows\System32\cmd.exe","/?",
а остальные параметры что указать? :(


 
Rouse_ ©   (2014-12-19 21:37) [10]

Ну и ExitCode: Cardinal задекларируй, его и передавай.


 
AlexeyTG   (2014-12-19 21:45) [11]

Прочитал что такое Cardinal :) Не могу разобраться. Можете ткнуть прямые строки кода пример вызова и что дописать :(


 
AlexeyTG   (2014-12-19 21:51) [12]

var
ExitCode: Cardinal;
if ExecAndWait("CMD.EXE","/?",ExitCode)then


 
AlexeyTG   (2014-12-19 21:55) [13]

program Project1;

uses
 Vcl.Forms, Winapi.Windows, System.SysUtils;
Var
StartInf: TStartupInfo;
ProcInf: TProcessInformation;
CmdLine: String;
Timeout:Cardinal;

{$R *.res}

// Обычный запуск процесса и ожидание его завершения

function ExecAndWait(const ExeName, Params: string; out ExitCode: Cardinal; Timeout: Cardinal = MaxInt): boolean;
var
 sui: TStartupInfo;
 pi: TProcessInformation;
begin
 ZeroMemory(@sui, SizeOf(sui));
 sui.cb := SizeOf(sui);
 Win32Check(CreateProcess(nil, PChar(""" + ExeName + "" " + Params), nil, nil, False, 0, nil,
   nil, sui, pi));
 try
   CloseHandle(pi.hThread);
   Result := WaitForSingleObject(pi.hProcess, Timeout) = WAIT_OBJECT_0;
   if Result and (@ExitCode <> nil) then
     Win32Check(GetExitCodeProcess(pi.hProcess, ExitCode));
 finally
   CloseHandle(pi.hProcess);
 end;
end;

begin

 If ExecAndWait ("C:\Windows\System32\cmd.exe","/?", Timeout) then
    ExecAndWait ("C:\Windows\System32\notepad.exe","D:\1.txt", Timeout) else
    Application.Terminate;

end.


 
AlexeyTG   (2014-12-19 21:56) [14]

Такой вариант правильный?


 
Rouse_ ©   (2014-12-19 22:04) [15]

Не правильный :)
Делай так:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
 Windows,
 SysUtils;

function ExecAndWait(const ExeName, Params: string; out ExitCode: Cardinal; Timeout: Cardinal = MaxInt): boolean;
var
sui: TStartupInfo;
pi: TProcessInformation;
begin
ZeroMemory(@sui, SizeOf(sui));
sui.cb := SizeOf(sui);
Win32Check(CreateProcess(nil, PChar(""" + ExeName + "" " + Params), nil, nil, False, 0, nil,
  nil, sui, pi));
try
  CloseHandle(pi.hThread);
  Result := WaitForSingleObject(pi.hProcess, Timeout) = WAIT_OBJECT_0;
  if Result and (@ExitCode <> nil) then
    Win32Check(GetExitCodeProcess(pi.hProcess, ExitCode));
finally
  CloseHandle(pi.hProcess);
end;
end;

var
 ExitCode: Cardinal;
begin
 try
   if not ExecAndWait("C:\Windows\System32\cmd.exe","/?", ExitCode) then
     RaiseLastOSError;
   if ExitCode <> 0 then
     Writeln("Wrong exit code: ", ExitCode);
   if not ExecAndWait("C:\Windows\System32\notepad.exe","D:\1.txt", ExitCode) then
     RaiseLastOSError;
   if ExitCode <> 0 then
     Writeln("Wrong exit code: ", ExitCode);
 except
   on E: Exception do
     Writeln(E.ClassName, ": ", E.Message);
 end;
 Readln;
end.


 
AlexeyTG   (2014-12-19 22:11) [16]

Rouse_ ©  Выстрадал готовый исходник называется :D

Что-то при запуске этого варианта проблемка. Он прям в себе открывает CMD, и после нескольких нажатий клавиши (прокрутка текста справки) в этом же окошке пишет
Специальные символы, которые требуют обязательного заключения в кавычки:
    <пробел>
    &()[]{}^=;!"+,`~

Wrong exit code: 1

и запускает блокнот


 
AlexeyTG   (2014-12-19 22:13) [17]

Сорри, дошло :) поменял cmd на другой ЕХЕшник


 
AlexeyTG   (2014-12-19 22:16) [18]

Единственно мне же не нужно консольное приложение. Просто нужен ЕХЕшник запускающий два других. Без собственного окошка и вывода данных :) Как писал здесь
http://delphimaster.net/view/2-1418843283/


 
Rouse_ ©   (2014-12-19 22:17) [19]

Конечно - это же консолька :)
Отключи генерацию консоли в настройках линкера и закоментируй директиву {$APPTYPE CONSOLE}, тогда в случае попытки вывода текста в консоль получишь вот такое исключение:

---------------------------
Debugger Exception Notification
---------------------------
Project Project7.exe raised exception class EInOutError with message "I/O error 105".
---------------------------
Break   Continue   Help  
---------------------------


 
Rouse_ ©   (2014-12-19 22:19) [20]

Ну тогда перепиши код запуска вот так (анализ кода возврата как я понял тебе не нужен):

program Project1;

{$R *.res}

uses
 Windows,
 SysUtils;

function ExecAndWait(const ExeName, Params: string; out ExitCode: Cardinal; Timeout: Cardinal = MaxInt): boolean;
var
sui: TStartupInfo;
pi: TProcessInformation;
begin
ZeroMemory(@sui, SizeOf(sui));
sui.cb := SizeOf(sui);
Win32Check(CreateProcess(nil, PChar(""" + ExeName + "" " + Params), nil, nil, False, 0, nil,
  nil, sui, pi));
try
  CloseHandle(pi.hThread);
  Result := WaitForSingleObject(pi.hProcess, Timeout) = WAIT_OBJECT_0;
  if Result and (@ExitCode <> nil) then
    Win32Check(GetExitCodeProcess(pi.hProcess, ExitCode));
finally
  CloseHandle(pi.hProcess);
end;
end;

begin
 if not ExecAndWait("C:\Windows\System32\cmd.exe","/?", PCardinal(nil)^) then
   RaiseLastOSError;
 if not ExecAndWait("C:\Windows\System32\notepad.exe","D:\1.txt", PCardinal(nil)^) then
   RaiseLastOSError;
end.


 
Rouse_ ©   (2014-12-19 22:25) [21]

Ну надеюсь все понятно?
А то хочется уже расслабится в пятницу то :)


 
AlexeyTG   (2014-12-19 22:32) [22]

Rouse_ Да, спасибо ОГРОМНОЕ за Вашу помощь.
Просто уже для общего развития, получается почти тот же код, что я в первом сообщении написал, только CloseHandle перенесены в функцию?
и второй вопрос RaiseLastOSError что делает? :)


 
AlexeyTG   (2014-12-19 22:35) [23]

Ну и CreateProcess по другому вызывается.

А Win32Check что такое?


 
Rouse_ ©   (2014-12-19 22:42) [24]


> только CloseHandle перенесены в функцию?

Угу.


> и второй вопрос RaiseLastOSError что делает? :)

Поднимает исключение на основе кода последней ошибки


> А Win32Check что такое?

проверяет код возврата и если что-то не так, вызывает RaiseLastOSError.

Усе - убежал, по остальным вопросам читай справку, там все есть :)


 
AlexeyTG   (2014-12-19 22:58) [25]

Rouse_ ОК, спаисбо большое за заве ВРЕМЯ прежде всего :)

___ Постараюсь на основе этого кода переписать свой, т.к. по этому в случае если файл не найдет, то ошибка приложения, а не просто выход :)



Страницы: 1 вся ветка

Текущий архив: 2017.01.15;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.027 c
4-1279284463
POP
2010-07-16 16:47
2017.01.15
Есть ли смысл (сейчас) в Win_Inet_API?


1-1343890489
rioko
2012-08-02 10:54
2017.01.15
Stream.Seek Stream.Position возвращает ноль.


2-1431020136
Zheksonz
2015-05-07 20:35
2017.01.15
Можно ли в поля Blob Graphic загружать jpg файлы?


3-1310463935
walm
2011-07-12 13:45
2017.01.15
Распределенный запрос


15-1448919001
Юрий
2015-12-01 00:30
2017.01.15
С днем рождения ! 1 декабря 2015 вторник