Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2017.01.15;
Скачать: [xml.tar.bz2];

Вниз

Заново переписал Просьба оценить "корявость кода" 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.55 MB
Время: 0.066 c
2-1423485605
lewka
2015-02-09 15:40
2017.01.15
Запрос в MS Access


2-1424288600
AndrewAndrey
2015-02-18 22:43
2017.01.15
Связь полей таблиц SQLite


2-1423545320
i2e
2015-02-10 08:15
2017.01.15
VK_ESCAPE и VK_E


15-1456148886
K-1000
2016-02-22 16:48
2017.01.15
TCanvas. Вывести текст с разноцветными буквами


15-1453057828
Кто б сомневался
2016-01-17 22:10
2017.01.15
raise exception до Application.Run НЕ покажет сообщение.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский