Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.09.11;
Скачать: CL | DM;

Вниз

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

 
бывший   (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 вся ветка

Текущий архив: 2005.09.11;
Скачать: CL | DM;

Наверх




Память: 0.69 MB
Время: 0.028 c
1-1124223850
Vadimich
2005-08-17 00:24
2005.09.11
Растёт Page Faults как приостановить?


14-1124086811
lehich
2005-08-15 10:20
2005.09.11
компонент архиватора


8-1114035775
Fedor
2005-04-21 02:22
2005.09.11
Как DSPack соединить с MotionDetector???


14-1124122766
Andy BitOff
2005-08-15 20:19
2005.09.11
Как узнать что это за адреса?


14-1124159977
Думкин
2005-08-16 06:39
2005.09.11
16 августа. С Днем!