Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Подземелье Магов
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  18:59[Войти] | [Зарегистрироваться]

Как переназначить StdOut в файл для консольной программы запускаемой по CreateProcess

Алексей Кузнецов
дата публикации 17-12-2001 14:52

Как переназначить StdOut в файл для консольной программы запускаемой по CreateProcess

Я не профи в Win API, просто у меня возникла именно такая проблема. Я нашел решение устраивающее меня. И к тому же решил, поделился с вами.
Если кому-то требуется что-то другое - дерзайте, я с удовольствием прочту на "Королевстве" что и как у вас получилось.
Handle = Хэндл = Рукоятка :)

Хочу предложить 2 способа:
  • 1) Простой, с использованием command.com /c имя_консольной_проги > имя_файла_куда_переназначить_StdOut
  • 2) С использованием Win API (2 штуки)
Вы уж сами выберите, что вам подходит больше. Я использую способ № 2.2.

Рассмотрим их более подробно на примерах.

Способ №1

//…
var StartupInfo: TStartupInfo;
      ProcessInformation: TProcessInformation;
begin
GetStartupInfo(StartupInfo);
with StartupInfo do
 begin
  wShowWindow := SW_HIDE; //не показывать окно
  dwFlags := STARTF_USESHOWWINDOW;
 end;

// для примера будем запускать [c:\program files\Borland\Delphi5\Bin]grep.exe с ключом '?' 
 Win32Check(CreateProcess(nil, 'command.com /c  grep.exe ? > MyStdOut.txt', 
 nil, nil, FALSE, CREATE_NEW_CONSOLE, nil, nil, StartupInfo, ProcessInformation));

// ждем пока наш процесс отработает
 WaitForSingleObject(ProcInfo.hProcess, INFINITE);

 Win32Check(CloseHandle(ProcInfo.hProcess);
end;

Способ №2.1

//…
var ProcInfo: TProcessInformation;
      StartupInfo: TStartupInfo;
      hOut, hOutDup: THandle;
begin
// Создаем файл в который и будем переназначать StdOut 
// Например, с такими настройками, вы можете их изменить под свои нужды
 hOut := CreateFile('MyStdOut.txt', GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
 if (hOut = INVALID_HANDLE_VALUE) then RaiseLastWin32Error;
А вот в этом месте и происходит все самое важное!!!
Необходимо сделать рукоятку нашего файла НАСЛЕДУЕМОЙ, что и делаем…
 Win32Check(DuplicateHandle(GetCurrentProcess, hOut, GetCurrentProcess, @hOutDup, 0, TRUE, DUPLICATE_SAME_ACCESS));
Небольшое замечание
Следует отметить, что если вы пишите прогу ТОЛЬКО под NT/2000, то сделать рукоятку наследуемой можно проще:
 Win32Check(SetHandleInformation (hOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
и не надо будет заводить дубликат рукоятки hOutDup

 // эта рукоятка нам уже не нужна, хотя вы можете ее использовать для своих целей
 Win32Check(CloseHandle(hOut)); 

 GetStartupInfo(StartupInfo);
 with StartupInfo do
  begin
    wShowWindow := SW_HIDE; // не показывать окно
    dwFlags := dwFlags or STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
    hStdOutput  := hOutDup; // присваиваем рукоятку на свой файл
  end;
Для примера будем запускать [c:\program files\Borland\Delphi5\Bin]grep.exe с ключом '?'
Вызов CreateProcess с флагом bInheritHandles = TRUE !!!
 Win32Check(CreateProcess(nil, 'grep.exe ?', nil, nil, TRUE, CREATE_NEW_CONSOLE, nil, nil, StartupInfo, ProcInfo));			

// ждем пока наш процесс отработает
 WaitForSingleObject(ProcInfo.hProcess, INFINITE);

 Win32Check(CloseHandle(ProcInfo.hProcess)); 

//если вы больше ничего не хотите делать с файлом, в который перенаправили StdOut, то закроем его
 Win32Check(CloseHandle(hOutDup));
end;

Способ №2.2

Этот способ мне показал Юрий Зотов (поместив его в разделе "Обсуждение статьи"), спасибо. Оказывается, рукоятку гораздо проще сделать наследуемой, если использовать SECURITY_ATTRIBUTES.
//…
var ProcInfo: TProcessInformation;
      StartupInfo: TStartupInfo;
      SecAtrtrs: TSecurityAttributes;
      hOut: THandle;
begin
 with SecAtrtrs do
  begin
    nLength := SizeOf(TSecurityAttributes);
    lpSecurityDescriptor := nil;
    bInheritHandle := true; // ВОТ ОНО !!! Наша рукоятка будет НАСЛЕДУЕМОЙ
   end;

// Создаем файл в который и будем переназначать StdOut 
// Например, с такими настройками, вы можете их изменить под свои нужды
 hOut := CreateFile('MyStdOut.txt', GENERIC_WRITE, 0, @SecAtrtrs, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
 if (hOut = INVALID_HANDLE_VALUE) then RaiseLastWin32Error;

 GetStartupInfo(StartupInfo);
 with StartupInfo do
  begin
    wShowWindow := SW_HIDE; // не показывать окно
    dwFlags := dwFlags or STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
    hStdOutput  := hOutDup; // присваиваем рукоятку на свой файл
  end;

// для примера будем запускать [c:\program files\Borland\Delphi5\Bin]grep.exe с ключом '?' 
// Вызов CreateProcess с флагом bInheritHandles = TRUE !!!
 Win32Check(CreateProcess(nil, 'grep.exe ?', nil, nil, TRUE, CREATE_NEW_CONSOLE, nil, nil, StartupInfo, ProcInfo));			

// ждем пока наш процесс отработает
 WaitForSingleObject(ProcInfo.hProcess, INFINITE);

 Win32Check(CloseHandle(ProcInfo.hProcess)); 

//если вы больше ничего не хотите делать с файлом, в который перенаправили StdOut, то закроем его
 Win32Check(CloseHandle(hOut));
end;

Заключение

Первый способ проверялся мной под Win98 и Win2k Pro. Второй (обе разновидности) только под Win2k Pro.

Оба способа служат одной и той же цели, но во втором случае программист получает больше контроля над ситуацией. Вызовы Win32Check и RaiseLastWin32Error добавляйте (убирайте) по своему вкусу.

Кстати, кто хочет узнать на эту тему больше - откройте Win32.hlp (поставляется вместе с Делфой) и на закладке "Предметный указатель" наберите "Creating a Child Process with Redirected Input and Output", "Inheritance" и "SECURITY_ATTRIBUTES" и ВНИМАТЕЛЬНО изучите.
Изучив эти (и смежные) разделы вы сможете переназначить StdOut, StdIn и StdErr куда вам захочется.

Алексей Кузнецов
Специально для Королевства Delphi




Смотрите также материалы по темам:
[Ввод/вывод (StdIn/StdOut)]

 Обсуждение материала [ 12-05-2011 04:13 ] 11 сообщений
  
Время на сайте: GMT минус 5 часов

Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования