Недавно добавленные исходники

•  DeLiKaTeS Tetris (Тетрис)  162

•  TDictionary Custom Sort  3 337

•  Fast Watermark Sources  3 089

•  3D Designer  4 847

•  Sik Screen Capture  3 343

•  Patch Maker  3 553

•  Айболит (remote control)  3 659

•  ListBox Drag & Drop  3 015

•  Доска для игры Реверси  81 704

•  Графические эффекты  3 945

•  Рисование по маске  3 249

•  Перетаскивание изображений  2 629

•  Canvas Drawing  2 752

•  Рисование Луны  2 581

•  Поворот изображения  2 189

•  Рисование стержней  2 168

•  Paint on Shape  1 568

•  Генератор кроссвордов  2 236

•  Головоломка Paletto  1 767

•  Теорема Монжа об окружностях  2 230

•  Пазл Numbrix  1 685

•  Заборы и коммивояжеры  2 057

•  Игра HIP  1 282

•  Игра Go (Го)  1 230

•  Симулятор лифта  1 475

•  Программа укладки плитки  1 216

•  Генератор лабиринта  1 548

•  Проверка числового ввода  1 366

•  HEX View  1 497

•  Физический маятник  1 358

 
скрыть


Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Delphi Sources

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



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

Я не профи в 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;
end;

А вот в этом месте и происходит все самое важное!!! Необходимо сделать рукоятку нашего файла НАСЛЕДУЕМОЙ, что и делаем…

 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 куда вам захочется.





Похожие по теме исходники

Чтение PSD файлов

Шифратор файлов

Разбиение файла на части

Поиск файлов

 

FileMan (менеджер файлов)

Поиск открытых файлов

Текст внутри файла

Нейросеть для распознавания образов

 

Механизм станка качалки для нефти

Весы для взвешивания

Кувшины для воды

Доска для игры Реверси

 



Copyright © 2004-2024 "Delphi Sources" by BrokenByte Software. Delphi World FAQ

Группа ВКонтакте