Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2005.09.11;
Скачать: [xml.tar.bz2];

Вниз

Редирект консольного вывода   Найти похожие ветки 

 
бывший   (2005-07-18 22:22) [0]

Есть клиент-серверное приложение. сервер сделан в виде консоли. необходим редирект вывода информации из консоли в мое приложение в "реальном масштабе времени" ) понимаю что необходим отдельный поток в котором я и буду совершать действо.

Пробовал создавать пайп и переадресовывать вывод при запуске консоли (createprocess) на этот пайп, постепенно читая из него. во-первых - передается не все, во-вторых в определенный момент консоль виснит. Подобные решения видел на www.sources.ru, к примеру.

В общем, мне нужна именно постепенная передача всего текста, отображаемого в консоле в мое приложение по мере его появления.
Я так понял выхода два - переадресация вывода (к примеру через пайп) - с этим вариантом по непонятным мне причинам облом вышел, чтение из некоего буфера консоли. Мастера, помогите!

Если необходимо привести те коды, что пробовал использовать, приведу. Пока для экономии места оставляю вопрос в таком виде.


 
P.N.P. ©   (2005-07-18 22:33) [1]

Посмотри http://www.renderman.ru/forum/download.php/1,336,24/FoxUtils.txt
Оно?


 
бывший   (2005-07-18 22:55) [2]

спасибо. интересное решение. оно работает, но все равно получает из консоли далеко не весь текст. консоль все время пополняется информацией (идет лог соединений клиентов, обмена данными, ошибок и т.д.) - этим вариантом получаю только 40% лога инициализации сервера и наступает тишина (не из-за таймаута точно).

этож каким макаром надо в этой консоле писать, чтобы редирект вывода не помогал? )

Мастера, жду вашей помощи и совета.


 
Гаврила ©   (2005-07-18 23:43) [3]


> Если необходимо привести те коды, что пробовал использовать,
> приведу


Видимо, пора


 
бывший   (2005-07-19 08:30) [4]

function GetDosOutput(const CommandLine:string): string;
var
 SA: TSecurityAttributes;
 SI: TStartupInfo;
 PI: TProcessInformation;
 StdOutPipeRead, StdOutPipeWrite: THandle;
 WasOK: Boolean;
 Buffer: array[0..255] of Char;
 BytesRead: Cardinal;
 WorkDir, 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_SHOW; //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("Could not execute command line!")
   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;
         uMain.MainForm.richLog.Lines.Add(Line);
       until not WasOK or (BytesRead = 0);
       // ждём, пока завершится консольное приложение
       WaitForSingleObject(PI.hProcess, INFINITE);
     finally
       // Закрываем все оставшиеся дескрипторы
       CloseHandle(PI.hThread);
       CloseHandle(PI.hProcess);
     end;
 finally
     result:=Line;
     CloseHandle(StdOutPipeRead);
 end;
end;


сделано на пайпах. как такового "реал-тайма" нету. мне главное было проверить весь ли текст с консоли будет редиректнут. не весь ( пробовал и много других вариантов, в том числе и предложенный товарищем P.N.P.


 
бывший   (2005-07-19 08:34) [5]

наверняка у многих мастеров есть свои секреты работы с чужой консолью. поделитесь, плиз )


 
Digitman ©   (2005-07-19 08:55) [6]

где-то я этот код уже видел ...

одна и та же ошибка фигурирует


> Buffer[BytesRead] := #0;


а если BytesRead будет равен 256 ?
подумай, что произойдет ..


> Application.ProcessMessages


а это, кстати, зачем ?


 
Digitman ©   (2005-07-19 09:03) [7]


> понимаю что необходим отдельный поток в котором я и буду
> совершать действо


действительно необходим, потому что ReadFile[Ex] в дан.случае не удастся использовать в неблокирующем режиме


 
бывший   (2005-07-19 10:19) [8]

хм...

@Digitman - спасибо за разъяснения. Код был взят в качестве примера с www.sources.ru вроде или с какого-то фака.

application.processmasseges в самом начале затесался случайно )

вы мне скажите одно, данный код с внесением соответствующих исправлений указанных Digitman"ом даст ли 100% редирект?


 
Digitman ©   (2005-07-19 10:39) [9]


> бывший   (19.07.05 10:19) [8]


> вы мне скажите одно


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


 
isasa ©   (2005-07-19 10:52) [10]

да нет, похоже чисто

WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
...
Buffer[BytesRead] := #0;

больше 255 не прочтет


 
бывший   (2005-07-19 10:57) [11]

хм... ну и в итоге? ) вы мне скажите почему читает не полностью? причем вариант предложенный P.N.P в несколько другом исполнении дает тот же результат ( что за буфер ест me консоли и как обрабатывать его содержимое? какими макаром может случиться так, что информация выводимая на консоль не может быть редиректнута? видел в свое время plugin для Frigate (аналог ТС), где подобная фича была реализована, жаль он без исходных кодов...


 
Digitman ©   (2005-07-19 11:36) [12]


> isasa ©   (19.07.05 10:52) [10]


точно.
255 я прозевал.

но в ориг.коде, откуда это было содрано, было 256, потому и не обратил сразу внимание


> бывший   (18.07.05 22:22)  


http://delphi.about.com/cs/adptips2001/a/bltip0201_2.htm


 
бывший   (2005-07-19 16:05) [13]

в примере Digitman"a есть интересная особенность - как я раньше не допер до этого! Вначале ждем пока отработает целиком программа, потом читаем с пайпа, куда на протяжении работы консоли редиректился вывод. Отлично =) Но как теперь быть мне, когда редирект нужен постепенный. Ждать пока отработает сервер мне никак нельзя - я парсю его логи. Какие есть предложения?


 
Ботвин Дмитрий   (2005-07-19 16:47) [14]

Попробуй такой вариант:

procedure RunDosInMemo(CmdLine: string; AMemo: TMemo);
const
 ReadBuffer = 2400;
var
 Security: TSecurityAttributes;
 ReadPipe, WritePipe: THandle;
 start: TStartUpInfo;
 ProcessInfo: TProcessInformation;
 Buffer: Pchar;
 BytesRead: DWord;
 Apprunning: DWord;
begin
 Screen.Cursor := CrHourGlass;
 Form1.Button1.Enabled := False;
 with Security do
 begin
   nlength := SizeOf(TSecurityAttributes);
   binherithandle := true;
   lpsecuritydescriptor := nil;
 end;
 if Createpipe(ReadPipe, WritePipe,
   @Security, 0) then
 begin
   Buffer := AllocMem(ReadBuffer + 1);
   FillChar(Start, Sizeof(Start), #0);
   start.cb := SizeOf(start);
   start.hStdOutput := WritePipe;
   start.hStdInput := ReadPipe;
   start.dwFlags := STARTF_USESTDHANDLES +
     STARTF_USESHOWWINDOW;
   start.wShowWindow := SW_HIDE;

   if CreateProcess(nil,
     PChar(CmdLine),
     @Security,
     @Security,
     true,
     NORMAL_PRIORITY_CLASS,
     nil,
     nil,
     start,
     ProcessInfo) then
   begin
     repeat
       Apprunning := WaitForSingleObject
         (ProcessInfo.hProcess, 100);
       ReadFile(ReadPipe, Buffer[0],
         ReadBuffer, BytesRead, nil);
       Buffer[BytesRead] := #0;
       OemToAnsi(Buffer, Buffer);
       AMemo.Text := AMemo.text + string(Buffer);

       Application.ProcessMessages;
     until (Apprunning <> WAIT_TIMEOUT);
   end;
   FreeMem(Buffer);
   CloseHandle(ProcessInfo.hProcess);
   CloseHandle(ProcessInfo.hThread);
   CloseHandle(ReadPipe);
   CloseHandle(WritePipe);
 end;
 Screen.Cursor := CrDefault;
 Form1.Button1.Enabled := True;
end;

Пример:
procedure TForm1.Button1Click(Sender: TObject);
begin
 Memo1.Clear;
 RunDosInMemo("ping -t 192.168.28.200", Memo1);
end;


 
Ботвин Дмитрий   (2005-07-19 17:00) [15]

Если ничего не произойдёт, то увеличить таймаут в строке:
Apprunning := WaitForSingleObject(ProcessInfo.hProcess, 200);


 
бывший   (2005-07-19 17:17) [16]

спасибо. щас смотреть буду )


 
бывший   (2005-07-19 17:23) [17]

офигенно ) супер! просто супер! вопрос есть такой еще ) как лучше поступить с таймаутом, если есть вероятность "простоя" сервера пустым в течение часа-двух и более, но в тоже время необходимо продолжать наблюдение? ставить большой таймаут - бессмысленно, т.к. в случае падения серва будем в холостую работать. что можете посоветовать?

@Ботвин Дмитрий: спасибо огромное! вы реально меня выручили! щас буду тестировать непосредственно на сервере. но ваш пример работает идеально )


 
бывший   (2005-07-20 09:07) [18]

в общем на боевом примере - провал.

1. виснит моя программа, не откликается даже после истечения таймаута и умервщленном сервере.

2. судя по task manager"у виснит и сам сервер. обычно он сразу после инициализации начинает жрать порядка 500-600 mb, а тут всего пару метров ест.

в отдельном потоке пока не пробовал.
в чем может быть беда? братцы, помогите!


 
Digitman ©   (2005-07-20 09:15) [19]


> в случае падения серва будем в холостую работать


в этом случае поток, вызвавший ReadFile(), "зависнет" в бесконечном ожидании, ибо пайп по прежнему существует, а процесса уже нет

необходимо принять какие-либо меры по слежению за процессом, и как только будет обнаружен факт его терминирования (неважно почему он был терминирован - завершен по инициативе пользователя или снят системой с выполнения по иным причинам) тут же закрыть хэндл пайпа ... как только пайп будет закрыт, ф-ция ReadFile() немедленно вернет управление с кодом ошибки 6 (неверный дескриптор)


 
Digitman ©   (2005-07-20 09:17) [20]


> в отдельном потоке пока не пробовал


в самую пору попробовать.

придется создать два доп.потока - один будет работать с пайпом, другой будет следить за целевым процессом


 
бывший   (2005-07-20 09:54) [21]

оба ) thnx 2Digitman ) утвердил мою уверенность ) будем кроить дальше. не совсем я понял по поводу второго потока: "следить за целевым процессом" - это как раз и имеется в виду то о чем вы говорили ранее?

я с потоками не на ты ) с ходу слепил нечто подобное:

unit uConsole;

interface

uses
 Controls, Windows, SysUtils, Forms, uMain, Classes, StdCtrls;

type
 TDosCapture = class(TThread)
 private
  CmdRun: String;
  AddLog: String;
  procedure DoChangeLog;
 protected
  procedure Execute; override;
  procedure ChangeLog(Text: String);
  procedure RunDosInMemo(CmdLine: string);
 public
  constructor Create(CmdLine: String);
 end;

implementation

procedure TDosCapture.RunDosInMemo(CmdLine: string);
const
ReadBuffer = 2400;
var
Security: TSecurityAttributes;
ReadPipe, WritePipe: THandle;
start: TStartUpInfo;
ProcessInfo: TProcessInformation;
Buffer: Pchar;
BytesRead: DWord;
Apprunning: DWord;
begin
with Security do
begin
 nlength := SizeOf(TSecurityAttributes);
 binherithandle := true;
 lpsecuritydescriptor := nil;
end;
if Createpipe(ReadPipe, WritePipe,
  @Security, 0) then
begin
 Buffer := AllocMem(ReadBuffer + 1);
 FillChar(Start, Sizeof(Start), #0);
 start.cb := SizeOf(start);
 start.hStdOutput := WritePipe;
 start.hStdInput := ReadPipe;
 start.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
 start.wShowWindow := SW_HIDE;

 if CreateProcess(nil,
    PChar(CmdLine),
    @Security,
    @Security,
    true,
    NORMAL_PRIORITY_CLASS,
    nil,
    nil,
    start,
    ProcessInfo) then
  begin
    repeat
      Apprunning := WaitForSingleObject
        (ProcessInfo.hProcess, 100);
      ReadFile(ReadPipe, Buffer[0],
        ReadBuffer, BytesRead, nil);
      Buffer[BytesRead] := #0;
      OemToAnsi(Buffer, Buffer);
      ChangeLog(String(Buffer));
    until (Apprunning <> WAIT_TIMEOUT);
  end;
  FreeMem(Buffer);
  CloseHandle(ProcessInfo.hProcess);
  CloseHandle(ProcessInfo.hThread);
  CloseHandle(ReadPipe);
  CloseHandle(WritePipe);
end;
end;

{ TDosCapture }

procedure TDosCapture.ChangeLog(Text: String);
begin
AddLog:=Text;
Synchronize(DoChangeLog);
end;

constructor TDosCapture.Create(CmdLine: String);
begin
CmdRun:=CmdLine;
FreeOnTerminate:=True;
inherited Create(False);
end;

procedure TDosCapture.DoChangeLog;
begin
with uMain.MainForm.richLog do
 text:=text+AddLog;
end;

procedure TDosCapture.Execute;
begin
RunDosInMemo(CmdRun);
end;

end.


Использую соответственно:
DCapture:=TDosCapture.Create("server.exe");

Что происходит - пока жива моя прога - загрузка сервера не трогается с места ) понимаю что виноват я, т.к. что-то упустил в RunDosInMemo применимо к потоку. Натолкните меня на мысль, господа. Плиз.


 
Digitman ©   (2005-07-20 10:06) [22]


> совсем я понял по поводу второго потока: "следить за целевым
> процессом" - это как раз и имеется в виду то о чем вы говорили
> ранее?


да, в [19]


> пока жива моя прога - загрузка сервера не трогается с места


не понял ..

что есть "загрузка с сервера" ?

речь идет о пайпе, а не о "серверах" и "загрузках" ...


> что-то упустил в RunDosInMemo применимо к потоку


да нет, все вроде бы выглядит вполне благопристойно ..

а что по этому поводу говорит отладчик ?


 
Ботвин Дмитрий   (2005-07-20 10:29) [23]

Для начала проверь свою прогу с потоками на примере того же
пинга, тока без параметра -t. Если всё работает и второй поток
отслеживает завершение создаваемого процесса, тогда переходи
на свой сервер. А без уверенности, что код рабочий к серверу
вообще прикасаться не надо....


 
alpet ©   (2005-07-20 10:30) [24]

А если указать start.wShowWindow := SW_SHOW консоль появляется?


 
бывший   (2005-07-20 10:41) [25]

@aplet. во-первых консоль и так (SW_HIDE) иногжа почему-то появлялась ))) но не суть. с SW_SHOW всегда видна точно ) но она пустая, понятно почему.

@Ботвин Дмитрий: ща попробую

@Digitman [22]: я про загрузку сервера говорю по той причине, что когда слепил thread-пример сервер перестал загружаться вообще. Редиректа тоже нету. Т.е.: 1. моя программа работает нормально, основной поток жив ) 2. сервер запускается, но не начинает инициализацию (по какой-то неведомой причине), пока жива моя программа. Как только я вырубаю мое ПО - работа сервера возобновляется. Складывается ощущение, что созданный поток держит и противится загрузке сервера. Бред... В коде ничего лишнего.

Вот такие вот пироги с капустой и луком...


 
Ботвин Дмитрий   (2005-07-20 10:56) [26]

Ну чё, с пингом работает?


 
бывший   (2005-07-20 10:57) [27]

господа, будите смеяться ) используя thread с ping -t все работает нормально. вопрос дня: каким образом редирект консоли может влиять на работоспособность сервера? сервер запущенный без моего ПО работает нормально. как можно отладить и разобраться в чем траблы?

на данный момент использую только 1 поток (см. пример [21]), как я уже говорил работает с пингом, не работает с сервером - держит сервер, не дает ему грузиться, пока не завершу поток/приложение.

жду ваших советов, Мастера.


 
Ботвин Дмитрий   (2005-07-20 10:59) [28]

Попробуй задать своему потоку приоритет Idle...


 
Digitman ©   (2005-07-20 11:01) [29]


> бывший   (20.07.05 10:41) [25]


отладчик-то что говорит ?!

ставь брейкпойнт на первую же строчку в теле Execute() и пройди пошагово весь код .. убедись что в ходе работы Execute() исключений не возникает


 
alpet ©   (2005-07-20 11:02) [30]

Ботвин Дмитрий   (20.07.05 10:59) [28]
WaitForSingleObject вроде выполняет роль своеобразного Sleep, сомнительно что здесь дело в приоритетах.

бывший   (20.07.05 10:57) [27]
Можно узнать на чем и с какой библиотекой написан злополучный сервер?


 
Ботвин Дмитрий   (2005-07-20 11:07) [31]

> бывший

А ты не пробывал изменить таймаут у WaitForSingleObject? Это я в примере поставил 100. Реально с таким значением может и не работать...


 
alpet ©   (2005-07-20 11:09) [32]

Попробуй также для начала обойтись без перехвата пайпов. Я тут посмотрел одну рабочую программу ориентированную на Dos приложение - там   start.hStdInput используется для передачи в буфер консоли данных (эмуляции клавиатурного ввода), а в твоем случае производится попытка читать из этого дескриптора. Если судить по логике моей программы должно быть так:

ReadFile(WritePipe, Buffer[0],
       ReadBuffer, BytesRead, nil);

...или я чего-то не понял.


 
Ботвин Дмитрий   (2005-07-20 11:10) [33]

> alpet

Дело, конечно, может быть и не в приоритете, просто для подобных
утилит рекомендуется именно простаивающий приоритет, что-бы не
нагружать излишне проц. Хотя это дело каждого...


 
бывший   (2005-07-20 11:10) [34]

alpet ©   (20.07.05 11:02) [30]
сервер... э... а хто его знает ) написан на C++ но с какой библиотекой сходу не скажу - надо копаться. исходников нету ) самое главное, что до потока - редирект был, хотя и 20% текста.

Digitman ©   (20.07.05 11:01) [29]
исключений точно не возникает. щас еще перепроверю всяко разно.

Ботвин Дмитрий   (20.07.05 10:59) [28]
можно попытаться. как задать приоритет потоку если он создан не через CreateThread? я просто в потоках не особо бум-бум. я так понимаю нужен идентификатор потока для этого?


 
бывший   (2005-07-20 11:13) [35]

alpet ©   (20.07.05 11:09) [32]
простите, я вас не до конца понял. как без пайпов то? куда редиректить? или вы имеете в виду что достаточно read-пайпа?

еще раз акцентирую: самое главное, что до потока - редирект был, хотя и 20% текста.

предлагаю вначале разобраться почему поток мешает корректной работоспособности сервера )

з.ы. спасибо вам всем, я рад что вы со мной в трудную минуту =)


 
alpet ©   (2005-07-20 11:14) [36]

бывший   (20.07.05 11:10) [34]
1. SetThreadPriority - метод класса TThread + F1.
2. Посмотрел сейчас в MSDN - походу в моей программе правильно юзается hStdInput для записи (см. пост [32]). Непонятно тогда почему у тебя пинг с таким кодом работал...


 
Ботвин Дмитрий   (2005-07-20 11:15) [37]

Установка приоритета:

constructor TDosCapture.Create(CmdLine: String);
begin
 CmdRun:=CmdLine;
 FreeOnTerminate:=True;
 Priority := tpIdle;
 inherited Create(False);
end;


 
alpet ©   (2005-07-20 11:15) [38]

Блин, точнее метод называется SetPriority. Отвык я от TThread :)


 
alpet ©   (2005-07-20 11:17) [39]

бывший   (20.07.05 11:13) [35]
В смысле не без пайпов, замени код инициации структуры:

start.hStdOutput := WritePipe;
start.hStdInput := ReadPipe;

на

start.hStdOutput := ReadPipe; // output - source
start.hStdInput := WritePipe; // keyboard simulation handle


 
бывший   (2005-07-20 11:22) [40]

ага, ща изменю приоритет и попробую поменять пайпы местами...


 
Ботвин Дмитрий   (2005-07-20 11:24) [41]

Таймаут на всякий случай увеличь со 100 для начала до 500


 
бывший   (2005-07-20 11:28) [42]

priority = idle - получил наверный дескриптор 6, о котором говорил Digitman. бррр... я запутался.

смена пайпов местами, как я и ожидал - не дала результатов. редиректа нету.


 
Digitman ©   (2005-07-20 11:29) [43]


> бывший   (20.07.05 11:22) [40]
> ага, ща изменю приоритет и попробую поменять пайпы местами...


это уже становится анекдотичным - попробую то, попробую сё, попробую третье , пятое, десятое .. авось, мол, заработает ..

"А Вы их дустом не пробовали ?"(с)

нет бы поставить точку останова в теле поточной ф-ции да пройти пошагово - давным-давно уж причину нашел бы)


 
бывший   (2005-07-20 11:31) [44]

поставил таймаут в 1000 - заработало (not idle приоритет) =) но редиректит реально 20% от всей информации и то только в период инициализации сервера. дальше перестает редиректить =(


 
бывший   (2005-07-20 11:33) [45]

Digitman ©   (20.07.05 11:29) [43]
гы ) да ладно, уже нашли траблу вроде... щас бы понять кто кому и почему мешает...


 
Ботвин Дмитрий   (2005-07-20 11:34) [46]

Тогда Priority := tpIdle засунь в Execute первой строкой.
Быть не может, что бы это вызывало исключение.


 
Digitman ©   (2005-07-20 11:40) [47]


> поставил таймаут в 1000 - заработало


вот дался тебе этот тайм-аут !

не нужны тут никакие тайм-авуты вообще)

стартуешь первый поток, в нем :

- создаешь пайп,
- стартуешь свой сервер,
- стартуешь второй поток c параметром - хэндлом пайпа
- следишь за сервером
- как только сервер завершится (или будет принудительно снят) закрываешь пайп

второй поток, получив параметром хэндл пайпа, просто в цикле читает из пайпа, пока не получит 6-й ошибки


 
бывший   (2005-07-20 11:43) [48]

ага, ща засуну =) самому уже смешно. короче привожу сравнительный анализ:

лог сервера без моего редиректа:

14:34:17:M:Loading address cache ... skipped.
OS version 5.1.2600 (Service Pack 2) platform 2
14:34:18:U: *** ****** win32 console release multithread
14:34:18:M:Config file scripts/defines.scp loaded, 0 sections done.
14:34:18:M:Config file scripts/***.conf loaded, 5 sections done.
14:34:18:M:Spells loaded, max=23702
14:34:18:M:WorldSafeLocs loaded, total=99
14:34:18:M:AreaTable loaded, total=1043
14:34:18:M:WorldMapArea loaded, total=50
14:34:18:M:Talents loaded, total=430
14:34:18:M:Taxinodes loaded, total=76
14:34:18:M:Taxipathes loaded, total=223
14:34:18:M:Taxipathnodes loaded, total=8400
14:34:18:M:EmotesText loaded, total=169
14:34:18:M:Factions loaded, total=175
14:34:18:M:FactionTemplates loaded, total=274
14:34:18:M:DurabilityCosts loaded, total=100
14:34:18:M:MapCache inited, 41 maps.
14:34:18:M:water.dat loaded, 19241 recs.
14:34:18:M:Config file scripts/classes.scp loaded, 58 sections done.
14:34:18:M:classes.scp stat tables loaded.
14:34:18:M:File scripts/items.scp, max 19326, total 11809 sections.
14:34:18:M:Config file scripts/gameobjects.scp loaded, 7608 sections done.
14:34:18:M:Config file scripts/specific_loots.scp loaded, 6 sections done.
14:34:18:M:Config file scripts/loottemplates.scp loaded, 4191 sections done.
14:34:18:M:Config file scripts/creatures_missing_models.scp loaded, 533 sections
done.
14:34:18:M:Config file scripts/creatures.scp loaded, 7887 sections done.
14:34:18:M:File scripts/spellcost.scp, max 117925, total 18352 sections.
14:34:18:M:File scripts/area/area_gm.scp, max 802004, total 215 sections.
14:34:18:M:File scripts/area/area_poi.scp, max 802004, total 69 sections.
14:34:18:M:File scripts/area/area_quest.scp, max 802004, total 7 sections.
14:34:18:M:File scripts/areatriggers.scp, max 802004, total 618 sections.
14:34:18:M:File scripts/quests.scp, max 13131312, total 3234 sections.
14:34:18:M:File scripts/pages.scp, max 2606, total 671 sections.
14:34:18:M:File scripts/qdbtexts.scp, max 13101560, total 5298 sections.
14:34:18:M:File scripts/npctext.scp, max 13101560, total 6726 sections.
14:34:23:M:Patching ... #569 ... #56E ... #568 ... <WS> ... <SN> ... <MOTD> ...
<FCKSTF> ... #57 ... #61 ... #63 ... #62 ... #67 ... done.
14:34:23:M:Saving address cache ... done.
[*** Plugin] v0.6.2 Loading database ...
[*** Plugin] TCLTool : Loading Quests Definitions ...
[*** Plugin] TCLTool : Loading Quests Definitions ... OK
[*** Plugin] TCLTool : Loading NPC Definitions ...
[*** Plugin] TCLTool : Loading NPC Definitions ... OK
[*** Plugin] TCLTool : Compiling NPCs ...
[*** Plugin] TCLTool : Compiling NPCs ... OK
[*** Plugin] Loading frase Database ...
[*** Plugin] Loading frase Database ... OK
[*** Plugin] Loading Spell Database  ...
[*** Plugin] Loading Spell Database ... OK
[*** Plugin] Loading Global configuration  ...
[*** Plugin] Loading Global configuration ... OK
[*** Plugin] Loading User configuration  ...
[*** Plugin] User configuration not found ! (It"s OK)
[*** Plugin] Loading Temporary Pool  ...
[*** Plugin] Temporary Pool not found ! (It"s OK)
[*** Plugin] Loaded OK
14:34:18:M:TCL:Init... done. 726 files loaded.( If error occured ->  )
14:34:18:M:Main thread started.
14:34:18:M:Loading guilds...
14:34:18:M:done.
14:34:18:M:Loading world...
14:34:18:M:Rehashing.
14:34:18:M:done.
14:34:18:M:Loading PP...
14:34:18:M:done, 328995 ppoints.
14:34:49:M:WS:Socket opened TCP port 8085
14:34:49:M:HS:Socket opened TCP port 8080
14:34:49:M:RS:Socket opened TCP port 3724

а вот редирект полученный мною:

14:37:30:M:Loading config file wel_server.conf ... done.
14:37:30:M:Loading address cache ... skipped.
14:37:34:M:Patching ... #569 ... #56E ... #568 ... <WS> ... <SN> ... <MOTD> ... <FCKSTF> ... #57 ... #61 ... #63 ... #62 ... #67 ... done.
14:37:34:M:[PavkaM Plugin] v0.6.2 Loading database ...
[*** Plugin] TCLTool : Loading Quests Definitions ...
[*** Plugin] TCLTool : Loading Quests Definitions ... OK
[*** Plugin] TCLTool : Loading NPC Definitions ...
[*** Plugin] TCLTool : Loading NPC Definitions ... OK
[*** Plugin] TCLTool : Compiling NPCs ...
[*** Plugin] TCLTool : Compiling NPCs ... OK
[*** Plugin] Loading frase Database ...
[*** Plugin] Loading frase Database ... OK
[*** Plugin] Loading Spell Database  ...
[*** Plugin] Loading Spell Database ... OK
[*** Plugin] Loading Global configuration  ...
[*** Plugin] Loading Global configuration ... OK
[*** Plugin] Loading User configuration  ...
[*** Plugin] User configuration not found ! (It"s OK)
[*** Plugin] Loading Temporary Pool  ...
[*** Plugin] Temporary Pool not found ! (It"s OK)
[*** Plugin] Loaded OK


 
Digitman ©   (2005-07-20 12:00) [49]


> короче привожу сравнительный анализ


мог бы и еще короче

мне, к примеру, этот "анализ" ни о чем не говорит, да и не анализ это никакой, а просто констатация фактов


 
бывший   (2005-07-20 12:03) [50]

сорри, ну я констатацию фактов и имел в виду. извините, ей богу. (


 
alpet ©   (2005-07-20 12:07) [51]

бывший   (20.07.05 12:03) [50]
1. Какой статус выполнения ReadFile (GetLastError) в случаях считывания и не считывания данных.
2. Может попробывать ReadConsoleOutput?


 
бывший   (2005-07-20 12:11) [52]

alpet ©   (20.07.05 12:07) [51]

2. ReadConsoleOutput? енто что? F1 не помог (
1. гляну ща...

что можете сказать относительно столь кривого редиректа? каким образом сервер может выводить на консоль минуя редирект? странно все это очень (


 
Ботвин Дмитрий   (2005-07-20 12:20) [53]

Если тебе нужна эта непонятная инфа, может проще перенаправить
консоль в файл, например:

ping 192.168.28.200 > c:\123.txt

и непарится с редиректом :-)))


 
alpet ©   (2005-07-20 12:24) [54]

бывший   (20.07.05 12:11) [52]

The ReadConsoleOutput function reads character and color attribute data from a rectangular block of character cells in a console screen buffer, and the function writes the data to a rectangular block at a specified location in the destination buffer.

Прототип есть в Delphi/Source/Rtl/Win/Windows.pas.

Я для эмуляции ввода с клавиатуры использую подобную ей функцию WriteConsoleInput (si.hStdInput...) Работает нормально с консольными и DOS прогами. Эта функция соотвественно должна работать с STARTUPINFO.hStdOutput.


 
бывший   (2005-07-20 13:15) [55]

Ботвин Дмитрий   (20.07.05 12:20) [53]
=) нужен real-time )ибо то что я показал - есть всего лишь  процесс инициализации сервера (загрузка данных, открытие портов), далее следует коннект клиентов, работа с ними и т.д. - все это надо парсить в real-time и определенным образом реагировать на события.

alpet ©   (20.07.05 12:24) [54]
спасибо. буду смотреть.

Digitman ©   (20.07.05 11:40) [47]
спасибо, буду иметь в виду.

и все-таки кто как думает - почему редирект не полный? это остался последний вопрос )


 
alpet ©   (2005-07-20 13:21) [56]

бывший   (20.07.05 13:15) [55]
Неполный видимо потому, что твоя программа считывает не все данные из пайпа, что может быть следствием того что они туда не все попадают, или какой-нибудь ошибки в программе. Статус выполнения ReadFile мы так и неувидели.


 
alpet ©   (2005-07-20 13:35) [57]

Потом добавление результата у тебя происходит как-то странно на мой взгляд:
   
Line := "";
...
Line := Line + Buffer;
...
uMain.MainForm.richLog.Lines.Add(Line);

Это по идее приводит к разбиению строк.
Попробуй так (строки должны получаться нормально):

with uMain.MainForm.richLog do
 Text := Text + Buffer;


 
Ботвин Дмитрий   (2005-07-20 13:36) [58]

Через перенаправление тоже будет реалтайм. Запускаешь в основном
потоке перенаправление, а во втором читаешь. Попробуй с тем же
пингом с параметром -t, а текстовым редактором открывай созданный файл и смотри как в него добавляются строки :-)))


 
alpet ©   (2005-07-20 13:41) [59]

В MSDN приведен пример с пайпами. Вот кусочек его (чтение из пайпа в stdout):

for (;;)
  {
     if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead,
        NULL) || dwRead == 0) break;
     if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL))
        break;
  }

Единственно что заметно в отличии от предлагаемых программ - размер буфера (BUFSIZE) = 4096.


 
Slym ©   (2005-07-20 14:02) [60]

А где start.hStdError?
у консоли 1 вход и 2! выхода
Без перенаправления выходы указывают в одно место, перенаправляешь ты только hStdOutput, а hStdError?
Перенаправь hStdError тудаже (в hStdOutput)


 
Slym ©   (2005-07-20 14:04) [61]

А прога у тебя не запускаться может от того что hStdError=0


 
Slym ©   (2005-07-20 14:09) [62]

Коряво но работает:

type
 TConsoleThread=class(TThread)
 private
   FCMD:string;
   FCloseHandles:boolean;
   FStdIn:TStrings;
   FStdOut:TStrings;
   FExitCode:DWord;
 protected
   procedure Execute;override;
 public
   constructor Create(const CMD:string;Commands:TStrings;CloseHandles:boolean=false);reintroduce;
   destructor Destroy; override;
   property ExitCode:DWord read FExitCode;
   property StdOut:TStrings read FStdOut;
 end;

implementation
uses SysUtils;

{ TConsole }

constructor TConsoleThread.Create(const CMD:string;Commands:TStrings;CloseHandles:boolean=false);
var i:integer;
begin
 FCMD:=CMD;
 FCloseHandles:=CloseHandles;
 FStdIn:=TStringList.Create;
 FStdOut:=TStringList.Create;
 if assigned(Commands) then
 begin
   FStdIn.BeginUpdate;
   try
     for I:= 0 to Commands.Count - 1 do
       FStdIn.AddObject(Commands[I]+#13#10, Commands.Objects[I]);
   finally
     FStdIn.EndUpdate;
   end;
 end;

 inherited Create(false);
end;

destructor TConsoleThread.Destroy;
begin
 FStdIn.Free;
 FStdOut.Free;
 inherited;
end;

procedure TConsoleThread.Execute;
var
 sa:TSecurityAttributes;
 si:TStartupInfo;
 pi:TProcessInformation;
 ChildStdInWr,ChildStdoutRd:THandle;
 ChildStdoutWr,ChildStdInRd:THandle;
 Tmp1,Tmp2:THandle;
 buffer:Pointer;
 bytesRead:DWORD;
 p:PChar;
begin
 ChildStdInWr:=0;ChildStdoutRd:=0;
 ChildStdoutWr:=0;ChildStdInRd:=0;
 Tmp1:=0;Tmp2:=0;
 sa.nLength:=sizeof(TSecurityAttributes);
 sa.bInheritHandle:=true;
 sa.lpSecurityDescriptor:=nil;
 try
   if not CreatePipe(ChildStdoutRd,ChildStdoutWr,@sa,0) then
     RaiseLastOSError;
   if not CreatePipe(ChildStdinRd,ChildStdinWr,@sa,0) then
     RaiseLastOSError;
   if not DuplicateHandle(GetCurrentProcess(),ChildStdoutRd,GetCurrentProcess(),@Tmp1,0,False,DUPLICATE_SAME_ACCESS) then
     RaiseLastOSError;
   if not DuplicateHandle(GetCurrentProcess(),ChildStdinWr,GetCurrentProcess(),@Tmp2,0,False,DUPLICATE_SAME_ACCESS) then
     RaiseLastOSError;
   if ChildStdoutRd<>0 then
     if CloseHandle(ChildStdoutRd) then
       ChildStdoutRd:=0;
   if ChildStdinWr<>0 then
     if CloseHandle(ChildStdinWr) then
       ChildStdinWr:=0;
   ChildStdoutRd:=Tmp1;Tmp1:=0;
   ChildStdinWr:=Tmp2;Tmp2:=0;

   GetStartupInfo(si);
   si.cb:=sizeof(TStartupInfo);
   si.dwFlags:=STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
   si.hStdInput:=ChildStdInRd;
   si.hStdOutput:=ChildStdOutWr;
   si.hStdError:=ChildStdOutWr;
   si.wShowWindow:=SW_HIDE;
   if not CreateProcess(nil,PChar(FCMD),nil,nil,true,CREATE_NEW_CONSOLE,nil,nil,si,pi) then
     RaiseLastOSError;
   while not Terminated do
   begin
     if WaitForSingleObject(pi.hProcess,0)=WAIT_OBJECT_0 then
     begin
       GetExitCodeProcess(pi.hProcess,FExitCode);
       CloseHandle(pi.hProcess);
       CloseHandle(pi.hThread);
       Terminate;
     end;
     PeekNamedPipe(ChildStdoutRd,nil,0,nil,@bytesRead,nil);
     if bytesRead>0 then
     begin
       GetMem(buffer,bytesRead+1);
       try
         if not ReadFile(ChildStdoutRd,buffer^,bytesRead,bytesRead,nil) then
           RaiseLastOSError;
         PChar(buffer)[bytesRead]:=#0;
         OemToChar(buffer,buffer);
         FStdOut.Append(PChar(buffer));
       finally
         FreeMem(buffer);
       end;
     end;
     while FStdIn.Count>0 do
     begin
       p:=PChar(FStdIn[0]);
       CharToOem(p,p);
       if not WriteFile(ChildStdinWr,p^,Length(FStdIn[0]),bytesRead,nil) then
         RaiseLastOSError;
       FStdIn.Delete(0);
     end;
     if FCloseHandles and (ChildStdinWr<>0) then
       if CloseHandle(ChildStdinWr) then
         ChildStdinWr:=0;
   end;
 finally
   if ChildStdoutRd<>0 then CloseHandle(ChildStdoutRd);
   if ChildStdoutWr<>0 then CloseHandle(ChildStdoutWr);
   if ChildStdinRd<>0 then CloseHandle(ChildStdinRd);
   if ChildStdinWr<>0 then CloseHandle(ChildStdinWr);
   if Tmp1<>0 then CloseHandle(Tmp1);
   if Tmp2<>0 then CloseHandle(Tmp2);
 end;
end;


 
бывший   (2005-07-21 10:12) [63]

проверил пример Slym"a: результат тот же! редирект не полностью. значит дело не в StdError (

@alpet ©   (20.07.05 12:07) [51]
по поводу статуса ReadFile - везде все путем. проверка сама собой получилась (см. пример Slym"a):
if not ReadFile(ChildStdoutRd,buffer^,bytesRead,bytesRead,nil) then
          RaiseLastOSError;

исключения не было.


 
Ботвин Дмитрий   (2005-07-21 10:48) [64]

Последнее, что могу предложить:
1. Задать ReadBuffer = 4096;

2. Поправь цикл:
repeat
  Apprunning := WaitForSingleObject(ProcessInfo.hProcess, 30000);
  ReadFile(ReadPipe, Buffer[0],
  ReadBuffer, BytesRead, nil);
  Buffer[BytesRead] := #0;
  OemToAnsi(Buffer, Buffer);
  AMemo.Text := AMemo.text + string(Buffer);
  Application.ProcessMessages;
until (Apprunning <> WAIT_TIMEOUT) or (Apprunning <>WAIT_OBJECT_0);


 
бывший   (2005-07-21 15:26) [65]

буду смотреть, спасибо.

еще остался вариант с редиректом в файл (хотя думаю будет тоже самое), кстати, вопрос относительно console.exe > 1.txt - разве такое на всех консолях срабатывает? по-моему консоль должна "уметь" обрабатывать сей ключ. он же не универсален?

ну и вариант с ReadConsoleOutput [alpet]



Страницы: 1 2 вся ветка

Форум: "WinAPI";
Текущий архив: 2005.09.11;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.67 MB
Время: 0.014 c
14-1122358525
Juice
2005-07-26 10:15
2005.09.11
Серьезная книжка по Delphi


14-1124394320
SergProger
2005-08-18 23:45
2005.09.11
Хочу скачать книжку


8-1114415663
NorthMan
2005-04-25 11:54
2005.09.11
получение bmp-заголовка из jpeg


14-1124362119
kyn66
2005-08-18 14:48
2005.09.11
Программа для защиты CD от копирования и виртуализации


6-1116844341
Alen
2005-05-23 14:32
2005.09.11
передача звука по сети





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский