Форум: "Прочее";
Текущий архив: 2013.06.02;
Скачать: [xml.tar.bz2];
ВнизРабота с внешним консольным приложением Найти похожие ветки
← →
ES (2013-01-14 19:31) [0]Есть общеизвестный пример: http://www.sources.ru/delphi/system/capturing_output_from_console.shtml
Есть также общеизвестная программа openssl.exe
Как бы доработать пример так, что сначала вызывается программа с параметрами "openssl.exe -a -b -c ...", далее она ожидает ввода с клавиатуры (если бы её запускать с cmd), нужно её подсунуть содержимое на сотню другую байт (контент), который она зашифрует и выдаст ответ, который и надо считать.
Вот считывание в примере и реализовано, но как бы сделать запись в консоль?
← →
брат Птибурдукова (2013-01-14 19:40) [1]Создавай два пайпа. Второй запуздыривай сюда: hStdInput := GetStdHandle(STD_INPUT_HANDLE); // стандартный ввод не перенаправляем
← →
Rouse_ © (2013-01-14 19:40) [2]Вон тут Пашка Голубь доделывал этот пример: http://forum.sources.ru/index.php?showtopic=83650
← →
Игорь Шевченко © (2013-01-14 19:52) [3]if not WasOK then
raise Exception.Create( "Ошибка выполнения или компиляции: " +
Chr( 10 ) + Chr( 13 ) + CommandLine )
Для интернетов самое то
← →
Игорь Шевченко © (2013-01-14 20:01) [4]http://www.gunsmoker.ru/2010/05/90.html
← →
ES (2013-01-14 21:57) [5]
> Вон тут Пашка Голубь доделывал этот пример
в принципе, я как-то так и делал.
Только для тестов использовал конструкцию - сначала запускал процесс "ftp", в консоль передавалWriteFile(StdinPipeWrite,"-help",5,Written,nil);
Ничего не получалось. Это приводило к тому, что консоль отображалась на экране, программа ничего не считывала (после данного кода шло считывание ReadFile).
Возможно, управление до WriteFile доходило раньше, чем консоль успевала инициализироваться или типа того... Но дело в том, что вроде бы в ответ на команда OpenSSL ничего не выдает, запускаешь - а просто курсор мигает и все. Как понять когда начать программно вводить команды?...
← →
ES (2013-01-15 11:10) [6]Я ошибся в том, что забыл писать Enter! то есть, перевод строки: #13#10
Возник другой вопрос, почему я запускаю команду "ftp":WasOK := CreateProcess( nil,
"ftp",
nil,
...
дальше стандартный код, подходим к считыванию данных из консоли:>WasOK := ReadFile( StdOutPipeRead, Buffer, 255, BytesRead, nil );
на этом месте исполнение зависает навсегда. Хотя если в консоле набрать ftp, то мы видим приглашение:
C:\Users\Admin>ftp
ftp>
Почему это приглашение "ftp>" не считывается?
Хотя писать можно, да...
← →
ES (2013-01-18 20:30) [7]Камрады, измучился весь с этим Openssl.exe
Есть такая команда:> openssl.exe smime -sign -signer public.pem -inkey private.pem -nochain -nocerts -outform PEM -nodetach
Формирует криптоконтейнер PKCS#7, где:
public.pem - публичный ключ
private.pem - приватный 2048-битный ключ
После такого запроса openssl.exe переходит в режим ввода текста с консоли для упаковки в контейнер. Если эту операцию делать ручками, то набираешь текст (при этом Enter - всего лишь перевод строки), далее я знаю что можно нажать [Enter], [CTRL]+[Z], далее Enter - после чего openssl.exe набранный текст упаковывает в контейнер. Вот как это выглядит:C:\MySSL>openssl
.exe smime -sign -signer public.pem -inkey private.pem -nochain -nocerts
-outform PEM -nodetach
Loading "screen" into random state - done
Вводим любой текст типа
Только что до этого нажал Enter... сейчас еше раз нажму
вот..
^Z
-----BEGIN PKCS7-----
MIIC7QYJKoZIhvcNAQcCoIIC3jCCAtoCAQExCzAJBgUrDgMCGgUAMGsGCSqGSIb3
DQEHAaBeBFyCoq6kqKwgq+6hrqkg4qWq4eIg4qivoA0Kkq6r7KquIOfiriCkriDt
4q6jriCtoKagqyBFbnRlci4uLiDhpannoOEgpeilIOCgpyCtoKas4w0Koq7iLi4a
DQoNCjGCAlkwggJVAgEBMFcwSTELMAkGA1UEBhMCUlUxGDAWBgNVBAoTD1BTIFlh
bmRleC5Nb25leTEgMB4GA1UEAxMXWWFuZGV4IE1vbmV5IElzc3VpbmcgQ0ECCh4/
wpMAAAAALeYwCQYFKw4DAhoFAKCB2DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcB
MBwGCSqGSIb3DQEJBTEPFw0xMzAxMTgxNjIxNTlaMCMGCSqGSIb3DQEJBDEWBBTy
0giOb5OyNlgHLQcU/GrIl6G4UzB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQB
KjALBglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3
DQMCAgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDAN
BgkqhkiG9w0BAQEFAASCAQBTARbvY0i+2iXk/c0BuE83V7lFhXFFgu68NQ+87Xq+
eRcwoPBFp8gfuHj+QLOP4Lz9qI99Uqg0jv4i1rjUQpQ/9kSqrc6jnd/DNn4+IovZ
cVZyWFNEWC5qe8qVMRS98zhYynJfqgpQz97J7A9ZryjYedp8iud0gLwGnbT+mP7U
q9cecoJoad1kLNvDPIcn3W0PX1lzMekG7ALeaIkosE8GyNKnAlYMS1sjZPoh+6eX
lKZUuf+CAdR2XWDgETGhPt9voNAM562bLnTWUqDVxr9MUI+5gvqd3fqVlqVWw9sU
XPvUgVl/Tkv1E4RHQBP6EbEW2n3SpfMSFaado2ek5FSx
-----END PKCS7-----
Вот как переделать пример: http://forum.sources.ru/index.php?showtopic=83650
Чтобы все сработало? Там передается [Enter] - и для внешней программы это событие, но для openssl это нифига не событие. У меня все подвисает, что логично, видимо openssl продолжает дальше ждать ввода текста.
Я пробовал после WriteFile делать:SetEndOfFile(StdinPipeWrite)
Но ответом идет False с кодом GetLastError = 87, что означает:
"Параметр задан неверно".
После WriteFile делать CloseHandle(StdinPipeWrite) тоже пробовал.
Что делать? Как запустить openssl и передать в него текст, сообщив о конце передачи текста?! (
← →
Игорь Шевченко © (2013-01-18 20:39) [8]А записать в StdinPipeWrite #$1A ?
← →
ES (2013-01-19 00:37) [9]
> А записать в StdinPipeWrite #$1A ?
попробовал... ничего не вышло, такое же зависание...
← →
ES (2013-01-19 00:38) [10]читал: http://en.wikipedia.org/wiki/End-of-file
от безысходности писал также:
#04
#26
#13#17
тоже не получилось.
← →
брат Птибурдукова (2013-01-19 00:43) [11]Попробуй в командной строке выполнить openssl.exe smime -sign -signer public.pem -inkey private.pem -nochain -nocerts -outform PEM -nodetach < stdin , где в файле stdin будут лежать все твои ответы. Когда заработает, тогда и начинай программу мучить. Потому что похоже, что ошибка не в твоей программе, а во входных данных.
← →
ES (2013-01-19 11:51) [12]
> Попробуй в командной строке выполнить openssl.exe smime
> -sign -signer public.pem -inkey private.pem -nochain -nocerts
> -outform PEM -nodetach < stdin
конечно, все работает. Только в openssl это указывается доп. командой:-in InFile.content
все ок.
← →
брат Птибурдукова (2013-01-19 13:21) [13]
> Только в openssl это указывается доп. командой
Так ты уверен, что с перенаправлением вывода всё работает так же корректно, как с дополнительным параметром?
← →
ES (2013-01-20 23:55) [14]
> Так ты уверен, что с перенаправлением вывода всё работает
> так же корректно, как с дополнительным параметром?
да, попробовал сейчас команду:> openssl.exe smime -sign -signer public.pem -inkey private.pem -nochain -nocerts -outform PEM -nodetach < req.xml
отработало просто на ура, тут же выдало ответ и вышло из программы openssl.
← →
ES (2013-01-21 00:07) [15]Причем, для openssl вроде как есть оттестированный рабочий код для PHP, его структура вроде бы понятна и на дельфи нечто такое же получается:
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w")); // stderr is a file to write to
$process = proc_open(
"openssl smime -sign -signer " . $certificate .
" -inkey " . $privkey .
" -nochain -nocerts -outform PEM -nodetach",
$descriptorspec, $pipes);
if (is_resource($process)) {
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
fwrite($pipes[0], $source);
fclose($pipes[0]);
$pkcs7 = stream_get_contents($pipes[1]);
...
но тем не менее на дельфи изобразить не получается ((
← →
Игорь Шевченко © (2013-01-21 00:21) [16]уже код пора выкладывать
← →
ES (2013-01-21 11:35) [17]Код вот:
procedure TExternalProgRunner.Execute;
var
CommandLine: string;
StdOutPipeRead, StdOutPipeWrite, StdInPipeRead, StdInPipeWrite: THandle;
SA : TSecurityAttributes;
SI : TStartupInfo;
PI : TProcessInformation;
WasOK : BOOL;
Buffer : array[0..255] of Char;
BytesRead, Written : Cardinal;
WaitRes: Cardinal;
hArray: array[0..1] of THandle;
sCurDir: string;
aaa: integer;
begin
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;
CommandLine := """ + FAppPath + "" " + FParam ;
sCurDir := ExtractFileDir(FAppPath);
WasOK := CreateProcess( nil,
PChar( CommandLine ),
nil,
nil,
True,
0,
nil,
PChar(sCurDir),
SI,
PI );
FhProcess := PI.hProcess ;
// если процесс может быть создан, то дескриптор, это его вывод
CloseHandle( StdOutPipeWrite );
if not WasOK then
begin
FStatus := prsEnd ;
end
else
begin
FStatus := prsRun ;
FisSuccessRun := true ;
try
// если указано - пишем в консоль текст
if FConsoleInput <> "" then
begin
WriteFile(StdinPipeWrite, FConsoleInput[1], length(FConsoleInput),
Written, nil);
end;
// получаем весь вывод до тех пор, пока DOS-приложение не будет завершено
Repeat
// читаем блок символов (могут содержать возвраты каретки и переводы строки)
WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil );
// есть ли что-нибудь ещё для чтения?
if BytesRead > 0 then
Begin
// завершаем буфер PChar-ом
Buffer[BytesRead] := #0;
// добавляем буфер в общий вывод
FcsData.Enter;
try
FAllRead := FAllRead + Buffer;
finally
FcsData.Leave;
end;
end;
Until not WasOK or ( BytesRead = 0 ) or (Terminated);
{SetLength(FAllRead, Length(Line));
if Line <> "" then
OemToChar(PChar(Line), PChar(FAllRead)) ;}
SetEvent(FeventFinishRead) ;
// ждём, пока завершится консольное приложение
hArray[0] := pi.hProcess;
hArray[1] := FeventTerminate ;
WaitRes := WaitForMultipleObjects(2, @hArray, false, INFINITE);
if WaitRes = WAIT_OBJECT_0 then // значит, терминировался именно процесс запущенный
FStatus := prsEnd ;
FExitCode := 0;
GetExitCodeProcess( pi.hProcess, FExitCode );
finally
// Закрываем все оставшиеся дескрипторы
CloseHandle( PI.hThread );
CloseHandle( pi.hProcess );
end;
end;
finally
SetEvent(FeventFinishRead) ;
CloseHandle( StdOutPipeRead );
if StdInPipeWrite <> 0 then
CloseHandle( StdInPipeWrite );
if StdInPipeRead <> 0 then
CloseHandle(StdInPipeRead);
end;
end;
На строчке:
> WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil );
поток зависает.
← →
Игорь Шевченко © (2013-01-21 15:34) [18]WaitForInputIdle вставить не поможет перед началом работы с вводом-выводом?
← →
Юрий Зотов © (2013-01-21 17:47) [19]Я делал иначе, без пайпов. В своей программе создаю консоль и запускаю чужое консольное приложение, как дочерний процесс с наследуемыми дескрипторами ввода-вывода. В результате чужая программа разделяет с моей одну и ту же консоль - то есть, моя программа может в консоль писать, а та читает.
← →
ES (2013-01-22 11:28) [20]
> WaitForInputIdle вставить не поможет перед началом работы
> с вводом-выводом?
вставил перед WriteFile.
WaitForInputIdle(pi.hProcess, INFINITE) возвращает 0xFFFFFFFF.
GetLastError = 18: "Больше файлов не осталось"
Результата не дало.
← →
Игорь Шевченко © (2013-01-22 14:41) [21]
> // если процесс может быть создан, то дескриптор, это его
> вывод
> CloseHandle( StdOutPipeWrite );
Зачем этот вызов ?
← →
Игорь Шевченко © (2013-01-22 14:57) [22]надо закрыть описатели записи в stdout и чтения stdin
Win32Check(CloseHandle(StdInPipeRead));
Win32Check(CloseHandle(StdOutPipeWrite));
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2013.06.02;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.003 c