
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.198] |
![]() |
|
![]() |
|
|
Уважаемые программисты! Есть такая беда: я выполняю функцией WinExec() (понимаю, что можно через Pipe, но как?
![]() WinExec('cmd /c SystemInfo', 1); В результате данная командная строка выводит кучу полезных даных о компе. Как получить эти данные в своей программе и поместить их, например, в Мемо? |
![]() |
Сообщ.
#2
,
|
|
Цитата Jetus @ что можно через Pipe, но как? Переопределением stdin,stdout. Добавлено Использование anonymous pipes для перехвата StdIn/StdOut дочернего процесса Как получить содержимое DOS окна? Добавлено Цитата Jetus @ В результате данная командная строка выводит кучу полезных даных о компе Эти данные можно получить и другими способами. |
Сообщ.
#3
,
|
|
|
То, что надо переопределять stdout, то это ясно.
Я имел в виду, что ищу НОРМАЛЬНО РАБОТОСПОСОБНЫЙ пример на ДЕЛЬФИ, как это все осуществить. Есть такой вот пример: ![]() ![]() Function GetDosOutput( const CommandLine, WorkDir: String; var ResultCode: Cardinal ): String; var StdOutPipeRead, StdOutPipeWrite: THandle; SA : TSecurityAttributes; SI : TStartupInfo; PI : TProcessInformation; WasOK : Boolean; Buffer : array[0..255] of Char; BytesRead : Cardinal; Line : String; Begin //Application.ProcessMessages; With SA do Begin nLength := SizeOf( SA ); bInheritHandle := True; lpSecurityDescriptor := nil; end; // создаём пайп для перенаправления стандартного вывода CreatePipe( StdOutPipeRead, // дескриптор чтения StdOutPipeWrite, // дескриптор записи @SA, // аттрибуты безопасности 0 // количество байт принятых для пайпа - 0 по умолчанию ); try // Создаём дочерний процесс, используя StdOutPipeWrite в качестве стандартного вывода, // а так же проверяем, чтобы он не показывался на экране. with SI do Begin FillChar( SI, SizeOf( SI ), 0 ); cb := SizeOf( SI ); dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; wShowWindow := SW_HIDE; hStdInput := GetStdHandle( STD_INPUT_HANDLE ); // стандартный ввод не перенаправляем hStdOutput := StdOutPipeWrite; hStdError := StdOutPipeWrite; end; //Запускаем компилятор из командной строки //WorkDir := ExtractFilePath(CommandLine); WasOK := CreateProcess( nil, PChar( CommandLine ), nil, nil, True, 0, nil, PChar( WorkDir ), SI, PI ); // Теперь, когда дескриптор получен, для безопасности закрываем запись. // Нам не нужно, чтобы произошло случайное чтение или запись. CloseHandle( StdOutPipeWrite ); // если процесс может быть создан, то дескриптор, это его вывод if not WasOK then raise Exception.Create( 'Ошибка выполнения или компиляции: ' + Chr( 10 ) + Chr( 13 ) + CommandLine ) else try // получаем весь вывод до тех пор, пока DOS-приложение не будет завершено Line := ''; Repeat // читаем блок символов (могут содержать возвраты каретки и переводы строки) WasOK := ReadFile( StdOutPipeRead, Buffer, 255, BytesRead, nil ); // есть ли что-нибудь ещё для чтения? if BytesRead > 0 then Begin // завершаем буфер PChar-ом Buffer[BytesRead] := #0; // добавляем буфер в общий вывод Line := Line + Buffer; end; //Application.ProcessMessages; Until not WasOK or ( BytesRead = 0 ); // ждём, пока завершится консольное приложение WaitForSingleObject( PI.hProcess, INFINITE ); ResultCode := 0; GetExitCodeProcess( PI.hProcess, ResultCode ); finally // Закрываем все оставшиеся дескрипторы CloseHandle( PI.hThread ); CloseHandle( PI.hProcess ); end; finally Result := Line; CloseHandle( StdOutPipeRead ); end; end; Использовать так: ![]() ![]() Memo1.Lines.Text := GetDosOutput( 'del c:\*.*', 'c:\', Rc ); Код, к сожалению, выдает ошибку в строке: ![]() ![]() if not WasOK then raise Exception.Create( 'Ошибка выполнения или компиляции: ' + Chr( 10 ) + Chr( 13 ) + CommandLine ) |
![]() |
Сообщ.
#4
,
|
|
Цитата Jetus @ WinExec('cmd /c SystemInfo', 1); выполняй то же самое тем же WinExec(), если хочется, но напиши команду вот так: ![]() ![]() cmd /c SystemInfo > C:\123.txt и полюбуйся на содержимое файла C:\123.txt - будет тебе счастье (в DOS-кодировке) |
Сообщ.
#5
,
|
|
|
Mischka, я не настолько тупой, как ты думаешь!
![]() cmd /c SystemInfo > C:\123.txt - это давно всем известно, а вот как обойтись без файла, создаваемого на винчестере? |
![]() |
Сообщ.
#6
,
|
|
Цитата Jetus @ Mischka, я не настолько тупой, как ты думаешь! я и не считаю тебя тупым. Но в задаче не было сказано, что нужно обойтись без файла ![]() |
![]() |
Сообщ.
#7
,
|
|
Вот именно этот пример у меня нормально абсолютно отработал.
А ошибка простая - не правильно передаешь параметры в функцию. К примеру вот правильный вариант: ![]() ![]() procedure TForm1.Button1Click(Sender: TObject); var RC: Cardinal; begin Memo1.Lines.Text := GetDosOutput( 'cmd /c SystemInfo', 'c:\', Rc ); end; а вот вариант с ошибкой: ![]() ![]() procedure TForm1.Button1Click(Sender: TObject); var RC: Cardinal; begin Memo1.Lines.Text := GetDosOutput( 'cmd /c SystemInfo', '', Rc ); end; |
Сообщ.
#8
,
|
|
|
Огромное спасибо, Rouse! Теперь все тип-топ!
![]() Тебе, Mischka, тоже спасибо! |
Сообщ.
#9
,
|
|
|
Мужики, а я попробовал, но у меня все исполняется, но консоль создается, разворачивается на весь экран и пофигу ей SW_HIDE
![]() |
Сообщ.
#10
,
|
|
|
Короче, если поставить вот такие параметры то стопроцентно все пучком:
![]() ![]() with SI do ... wShowWindow := SW_HIDE or SW_SHOWMINNOACTIVE; ... end; |
Сообщ.
#11
,
|
|
|
А у тебя какая опреационная система стоит? Потому что я на ХР Pro пробовал и там все "пряталось"
![]() И ещё. Кому єта тема ещё интересна. Есть еще такой вот вариант выполнить ту же задачу: ![]() ![]() const H_IN_READ = 1; H_IN_WRITE = 2; H_OUT_READ = 3; H_OUT_WRITE = 4; H_ERR_READ = 5; H_ERR_WRITE = 6; type TPipeHandles = array [1..6] of THandle; var hPipes: TPipeHandles; ProcessInfo: TProcessInformation; Form1: TForm1; . . . . . (************CREATE HIDDEN CONSOLE PROCESS************) function CreateHiddenConsoleProcess(szChildName: string; ProcPriority: DWORD; ThreadPriority: integer): Boolean; label error; var fCreated: Boolean; si: TStartupInfo; sa: TSecurityAttributes; begin // Initialize handles hPipes[ H_IN_READ ] := INVALID_HANDLE_VALUE; hPipes[ H_IN_WRITE ] := INVALID_HANDLE_VALUE; hPipes[ H_OUT_READ ] := INVALID_HANDLE_VALUE; hPipes[ H_OUT_WRITE ] := INVALID_HANDLE_VALUE; hPipes[ H_ERR_READ ] := INVALID_HANDLE_VALUE; hPipes[ H_ERR_WRITE ] := INVALID_HANDLE_VALUE; ProcessInfo.hProcess := INVALID_HANDLE_VALUE; ProcessInfo.hThread := INVALID_HANDLE_VALUE; // Create pipes // initialize security attributes for handle inheritance (for WinNT) sa.nLength := sizeof(sa); sa.bInheritHandle := TRUE; sa.lpSecurityDescriptor := nil; // create STDIN pipe if not CreatePipe( hPipes[ H_IN_READ ], hPipes[ H_IN_WRITE ], @sa, 0 ) then goto error; // create STDOUT pipe if not CreatePipe( hPipes[ H_OUT_READ ], hPipes[ H_OUT_WRITE ], @sa, 0 ) then goto error; // create STDERR pipe if not CreatePipe( hPipes[ H_ERR_READ ], hPipes[ H_ERR_WRITE ], @sa, 0 ) then goto error; // process startup information ZeroMemory(Pointer(@si), sizeof(si)); si.cb := sizeof(si); si.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; si.wShowWindow := SW_SHOW; // assign "other" sides of pipes si.hStdInput := hPipes[ H_IN_READ ]; si.hStdOutput := hPipes[ H_OUT_WRITE ]; si.hStdError := hPipes[ H_ERR_WRITE ]; // Create a child process try fCreated := CreateProcess( nil, PChar(szChildName), nil, nil, True, ProcPriority, // CREATE_SUSPENDED, nil, nil, si, ProcessInfo ); except fCreated := False; end; if not fCreated then goto error; Result := True; CloseHandle(hPipes[ H_OUT_WRITE ]); CloseHandle(hPipes[ H_ERR_WRITE ]); // ResumeThread( pi.hThread ); SetThreadPriority(ProcessInfo.hThread, ThreadPriority); CloseHandle( ProcessInfo.hThread ); Exit; //----------------------------------------------------- error: //ClosePipes( hPipes ); CloseHandle( ProcessInfo.hProcess ); CloseHandle( ProcessInfo.hThread ); ProcessInfo.hProcess := INVALID_HANDLE_VALUE; ProcessInfo.hThread := INVALID_HANDLE_VALUE; Result := False; end; А вот как запускать: ![]() ![]() procedure TForm1.Button1Click(Sender: TObject); var OutputStr: TFileStream; OutText : TStringList; begin CreateHiddenConsoleProcess('cmd /c systeminfo', NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS); Sleep(8000); OutputStr := TFileStream.Create(hPipes[H_OUT_READ]); OutText := TStringList.Create; OutText.LoadFromStream(OutputStr); OutputStr.Free; Memo1.Lines := OutText; end; Понимаю, что испольовать вот так Sleep(8000) - это очень плохой тон, но мне было просто лень дорабатывать программу ![]() |
Сообщ.
#12
,
|
|
|
Цитата Jetus @ Newbie Профиль · PM А у тебя какая опреационная система стоит? Дык ХР... Видимо просто где-то есть какие-то настройки по запуску консолей, ну типа фулскрин, цвета, размеры буфферов и т.д. По примеру. Ну, а как, например, в консоль, передать строку каку-нить? Например, консоль спрашивает пароль... ЗЫ Вообщем, это мне надо, но раз уж ты разобрался может мне ленивому кинешь примерчик? ![]() Добавлено Все, не надо ![]() |
Сообщ.
#13
,
|
|
|
Короче, если кому-то надо. Примерчик с проходом авторизации, если консоль спрашивает пароль:
![]() ![]() Function GetDosOutput( CommandLine, Pass: String; var ResultCode: Cardinal ): String; var StdOutPipeRead, StdOutPipeWrite, StdInPipeRead, StdInPipeWrite: THandle; SA : TSecurityAttributes; SI : TStartupInfo; PI : TProcessInformation; WasOK : Boolean; Buffer : array[0..255] of Char; PassA : array[0..255] of Char; BytesRead : Cardinal; Line : String; Written : DWORD; Passed : boolean; Begin //Application.ProcessMessages; With SA do Begin nLength := SizeOf( SA ); bInheritHandle := True; lpSecurityDescriptor := nil; end; // создаём пайп для перенаправления стандартного вывода CreatePipe( StdOutPipeRead, // дескриптор чтения StdOutPipeWrite, // дескриптор записи @SA, // аттрибуты безопасности 0 // количество байт принятых для пайпа - 0 по умолчанию ); // создаём пайп для перенаправления стандартного ввода CreatePipe( StdInPipeRead, // дескриптор чтения StdInPipeWrite, // дескриптор записи @SA, // аттрибуты безопасности 0 // количество байт принятых для пайпа - 0 по умолчанию ); try // Создаём дочерний процесс, используя StdOutPipeWrite в качестве стандартного вывода, // а так же проверяем, чтобы он не показывался на экране. with SI do Begin FillChar( SI, SizeOf( SI ), 0 ); cb := SizeOf( SI ); dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; wShowWindow := SW_HIDE or SW_SHOWMINNOACTIVE; hStdInput := StdInPipeRead; //GetStdHandle(STD_INPUT_HANDLE); hStdOutput := StdOutPipeWrite; hStdError := StdOutPipeWrite; end; Passed := false; //Запускаем компилятор из командной строки //WorkDir := ExtractFilePath(CommandLine); WasOK := CreateProcess( nil, PChar( CommandLine ), nil, nil, True, 0, nil, nil, SI, PI ); // если процесс может быть создан, то дескриптор, это его вывод CloseHandle( StdOutPipeWrite ); if not WasOK then raise Exception.Create( 'Ошибка выполнения или компиляции: ' + Chr( 10 ) + Chr( 13 ) + CommandLine ) else try // получаем весь вывод до тех пор, пока DOS-приложение не будет завершено Line := ''; Repeat // читаем блок символов (могут содержать возвраты каретки и переводы строки) WasOK := ReadFile( StdOutPipeRead, Buffer, 255, BytesRead, nil ); // есть ли что-нибудь ещё для чтения? if BytesRead > 0 then Begin // завершаем буфер PChar-ом Buffer[BytesRead] := #0; // добавляем буфер в общий вывод Line := Line + Buffer; end; If not Passed AND (Pos('PASSWORD',AnsiUpperCase(Line)) > 0) then begin Pass := Pass + #13#10; //добавляем ввод WasOk := WriteFile(StdinPipeWrite,Pass[1],length(Pass),Written,nil); Passed := true; //прошли авторизацию end; //Application.ProcessMessages; Until not WasOK or ( BytesRead = 0 ); // ждём, пока завершится консольное приложение WaitForSingleObject( pi.hProcess, INFINITE ); ResultCode := 0; GetExitCodeProcess( pi.hProcess, ResultCode ); finally // Закрываем все оставшиеся дескрипторы CloseHandle( PI.hThread ); CloseHandle( pi.hProcess ); end; finally Result := Line; CloseHandle( StdOutPipeRead ); CloseHandle( StdInPipeRead ); CloseHandle( StdInPipeWrite ); end; end; procedure TForm1.Button1Click(Sender: TObject); Var RC: cardinal; begin Memo1.Text := GetDosOutPut('commandline','password', Rc); end; |
![]() |
Сообщ.
#14
,
|
|
Как функция поведет себя если надо ввести 2 параметра , ответить на вопросы Y/N и в зависимости от них еще несколько параметров или чегото еще? Например архиватор спрашивает - создать папку,файл уже есть удалить добавить , нет места на диске..... Я не вижу тут диалога , куда выводяться сообщения dos окна? |
![]() |
Сообщ.
#15
,
|
|
Ну скажем, это основа от которой будет плясать тот, кто заинтересовался данным вопросом, хотя можно и доработать пример
![]() |
Сообщ.
#16
,
|
|
|
Цитата Bas @ Как функция поведет себя если надо ввести 2 параметра , ответить на вопросы Y/N и в зависимости от них еще несколько параметров или чегото еще? Например архиватор спрашивает - создать папку,файл уже есть удалить добавить , нет места на диске..... Я не вижу тут диалога , куда выводяться сообщения dos окна? Я где-то обещал что-нить подобное? ![]() |
Сообщ.
#17
,
|
|
|
Ребята
Bas, задал тот же самый вопрос что и я вам, ведь приведенный тут код не работает по этому принципу "Как функция поведет себя если надо ввести 2 параметра , ответить на вопросы Y/N и в зависимости от них еще несколько параметров или чегото еще?" |
![]() |
Сообщ.
#18
,
|
|
Цитата LuckyDevil @ "Как функция поведет себя если надо ввести 2 параметра , ответить на вопросы Y/N и в зависимости от них еще несколько параметров или чегото еще?" Я так понял, прога должна обладать искуственным интеллектом ![]() |