No Image

Консольным приложением не был создан файл

8 просмотров
05 мая 2020

Есть общеизвестный пример: 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]


ES ( 2013-01-14 21:57 ) [5]


> Вон тут Пашка Голубь доделывал этот пример

в принципе, я как-то так и делал.
Только для тестов использовал конструкцию – сначала запускал процесс "ftp", в консоль передавал

Ничего не получалось. Это приводило к тому, что консоль отображалась на экране, программа ничего не считывала (после данного кода шло считывание 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, то мы видим приглашение:

Почему это приглашение "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 делать:

Но ответом идет 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]

от безысходности писал также:

тоже не получилось.


брат Птибурдукова ( 2013-01-19 00:43 ) [11]

Попробуй в командной строке выполнить openssl.exe smime -sign -signer public.pem -inkey private.pem -nochain -nocerts -outform PEM -nodetach


ES ( 2013-01-19 11:51 ) [12]


> Попробуй в командной строке выполнить openssl.exe smime
> -sign -signer public.pem -inkey private.pem -nochain -nocerts
> -outform PEM -nodetach -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

отработало просто на ура, тут же выдало ответ и вышло из программы 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]);

но тем не менее на дельфи изобразить не получается ((


Игорь Шевченко © ( 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);

Читайте также:  Как удалить vmware workstation pro

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

Для того чтобы создать консольное приложение, надо в меню File выбрать команду New Project , в появившемся окне New Project выбрать CLR Console Application , в поле Name ввести имя проекта (рис. 6.2) и нажать кнопку OK . В результате этих действий станет доступным окно редактора кода, в котором можно набирать текст программы.

Рис. 6.2. Начало работы над консольным приложением

В качестве примера в листинге 6.2 приведен текст консольного приложения — утилиты clear, которая удаляет из каталога, указанного при запуске утилиты, и всех его подкаталогов tmp-файлы. Также, если при запуске утилиты указан ключ –CLEARDEBUG , утилита удаляет все файлы из всех подкаталогов Debug. Так как операция удаления является потенциально опасной, то утилита запрашивает у пользователя подтверждение на выполнение. Причем, чтобы операция очистки была начата, необходимо ввести Y , ввод любого другого символа, в том числе y , отменяет операцию. Основную работу — удаление файлов выполняет рекурсивная функция сlear. Сначала она обрабатывает (удаляет tmp-файлы) текущий каталог, затем формирует список подкаталогов

Часть II. Практикум программирования

текущего каталога, делает текущим первый (по номеру элементов списка) подкаталог и вызывает себя (рекурсия) для обработки этого подкаталога.

Листинг 6.2. Очистка диска (консольное приложение)

// clear.cpp : main project file.

Читайте также:  Fiio d03k taishan обзор

using namespace System;

using namespace System::IO;

кол-во удаленных файлов

bool debug = true ;

true — только сообщение о выполнении

bool clearDebug = false ; //

очистка каталогов Debug

// Очистка текущего каталога и всех его подкаталогов.

// подкаталоги текущего каталога

// файлы, которые надо удалить

int p = System::IO::Directory::GetCurrentDirectory()->

ToString()->LastIndexOf(‘\’); String^ aFolder =

if (aFolder == "Debug")

// удалить все файлы из каталога Debug

Files = Directory::GetFiles (System::IO::Directory::GetCurrentDirectory(),"*.*");

Глава 6. Консольное приложение

Files = Directory::GetFiles (System::IO::Directory::GetCurrentDirectory(),"*.tmp");

// удалить tmp-файлы из текущего каталога

Files = Directory::GetFiles (System::IO::Directory::GetCurrentDirectory(),"*.tmp");

int nf = Files->Length; for (i = 0; i if (! debug)

Console::WriteLine(Files[i] + " — удален"); nDel = nDel +1;

// обработать подкаталоги if (debug)

n = Directories->Length; for (i = 0; i if (debug) Console::WriteLine(Directories[i]);

Часть II. Практикум программирования

int main( array ^args)

char r; // ответ пользователя: Y или N

// проверим, указано ли имя файла теста if (args->Length == 0)

Console::WriteLine("Ошибка: Надо задать каталог."); Console::WriteLine("Команда: clear [-CLEARDEBUG]"); Console::WriteLine("-CLEARDEBUG — очистка каталогов Debug
");

Console::ReadLine(); return -1;

// проверим, существует ли указанный каталог try

catch (System::IO::DirectoryNotFoundException^ ex)

Console::WriteLine("Каталог " + path +" не найден");

Console::ReadLine(); return -1;

("Программа удалит все файлы из подкаталогов Debug");

Глава 6. Консольное приложение

Console::WriteLine("каталога "+ path+ " и всех его подкаталогов.");

Console::WriteLine("Программа удалит tmp-файлы");

Console::WriteLine("из каталога "+ path+

" и всех его подкаталогов.");

Console::ReadLine(); // дочитать из буфера ввода if (r != ‘Y’)

Console::ReadLine(); return -1;

Console::WriteLine("Удалено файлов: "+ nDel.ToString()); Console::WriteLine("Работа выполнена!"); Console::Write("Нажмите ");

Console::ReadLine(); return 0;

Построение консольного приложения выполняется обычным образом, т. е. выбором в меню Build команды Build Solution .

После успешной компиляции программу можно запустить. Для этого надо в меню Debug выбрать команду Start Debugging или Start Without Debugging .

Если программа должна получать параметры из командной строки, то при ее запуске из среды разработки параметры надо ввести в поле Command Arguments раздела Configuration Properties Debugging окна Property Page

(рис. 6.3), которое становится доступным в результате выбора в меню Project команды Properties . Следует обратить внимание: если в строке-параметре есть пробелы, то ее надо заключить в двойные кавычки.

У меня есть решение, которое имеет 3 проектов. Одним из них является консольным приложением и другие 2 являются окно приложения. Оба окна приложение использует консольное приложение, поэтому я добавил ссылку на консольном приложении в обеих окнах приложений проектов. Теперь, когда я строю окна проектов, консольное приложение копируется в выходной каталог, но проблема в том, что его конфигурационный файл «consoleapp.exe.config» не копируется!

Если бы я использовал библиотеку (сборки) вместо консольного приложения, он будет создан конфигурационный файл этой сборки в папке вывода.

Как решить эту проблему?

Выберите consoleapp.exe.config в дереве решений.

Выберите « Содержимое » для сборки Действие опции в собственности сетки.

Выберите Копировать всегда для копирования в каталог вывода опции.

Надеюсь, что это помогает 🙂

Быстрое создание консольного проекта в VS2008 и добавив « App.config », он имеет параметры:

Строить Действие: Нет
Скопировать в каталог Ouput: Не копировать
пользовательский инструмент:
Пользовательский инструмент Пространство имен:

Однако я не уверен, что эффект добавление ссылки на проект консоли будет иметь, как проект консоли представляет собой приложение, а не библиотеки классов.

Если вы хотите, чтобы консольное приложение для запуска с приложениями Windows, для отладки, то лучше, чем подход ссылок проекта будет установить решение для запуска нескольких приложений. Щелкните правой кнопкой мыши на решения, выберите свойства и на узле Start Project, выберите несколько проектов. (И удалить ссылки на консольное приложение.)

Ваши приложения используют значение по умолчанию для параметров из скомпилированного кода ссылочного проекта.

Комментировать
8 просмотров
Комментариев нет, будьте первым кто его оставит

Это интересно
No Image Компьютеры
0 комментариев
No Image Компьютеры
0 комментариев
No Image Компьютеры
0 комментариев
Adblock
detector