Вопрос по console-application, events, indy, delphi-7, delphi – Delphi 7: Обработка событий в консольном приложении (TidIRC)

1

Я пытаюсь создать консольное приложение на основе IRC-компонента Indy (TIdIRC), но у меня возникают проблемы с событиями. Вот мой код:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Classes,
  Math,
  IdBaseComponent,
  IdComponent,
  IdTCPConnection,
  IdTCPClient,
  IdIRC;

type
  TEvents = class
  public
    procedure Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);
  end;

const
  IrcServ = 'gr.irc.gr';
  IrcPort = 6667;
  IrcChan = '#lalala';

var
  Irc: TidIRC;
  Event: TEvents;
  uName, rName: string;

function Log(s: string): string;
var now: TDateTime;
begin
  now := Time;
  result := FormatDateTime('[hh:nn:ss] ', now) + s;
end;

procedure TEvents.Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);
begin
  Log(AUser.Nick+' '+ACommand+' '+AContent);
end;

begin
  Event := TEvents.Create;
  Irc := TidIRC.Create(nil);
  Irc.OnRaw := Event.Raw;
  Randomize;
  Write('Nickname: ');
  ReadLn(uName);
  rName := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
  with Irc do begin
    AltNick := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
    Nick := rName;
    Username := rName;
    RealName := 'I.D.M.';
    Host := IrcHost;
    Port := IrcPort;
    //MaxLineAction := maException;  <-- [ERROR] Undeclared identifier: 'maException'
    ReadTimeout := 0;
    UserMode := [];
    Connect();
    Join(IrcChan);
  end;
  ReadLn;

end.

Я до сих пор пробовал все, что мог придумать, но, хотя приложение успешно подключено, оно не возвращает никакого необработанного сообщения ... Что мне не хватает?

Ваш Ответ

1   ответ
4

TdIRC использует внутренний рабочий поток для получения данных.OnRaw событие инициируется, когда этот поток анализирует данные. Нить используетTThread.Synchronize() сделать этот анализ. Так как ваш основной поток не имеет активного цикла сообщений VCL, вы можете качатьSynchronize() очередь вручную. После подключения позвонитеCheckSynchronize() функция отClasses блок в цикле, когда вы подключены к IRC, например:

  ...
  Connect; 
  try
    Join(IrcChan); 
    do
      CheckSynchronize;
      Sleep(10);
    until SomeCondition;
  finally
    Disconnect;
  end;
  ...  
end. 

Для правильной оценки вы можете назначить обработчикWakeMainThread событие вClasses блок, чтобы помочь контролировать, когдаCheckSynchronize() должен быть вызван, чтобы основной поток мог перейти в спящий режим, пока IRC-соединение не используется, например:

program Project1;     

{$APPTYPE CONSOLE}     

uses     
  SysUtils,     
  Classes,     
  Math,     
  IdBaseComponent,     
  IdComponent,     
  IdTCPConnection,     
  IdTCPClient,     
  IdIRC;     

type     
  TEvents = class     
  private
    FSyncEvent: TEvent;
  public     
    constructor Create;
    destructor Destroy; override;
    procedure Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);     
    procedure Wake(Sender: TObject);
    procedure CheckSync;
  end;     

function Log(s: string): string;      
     
  result := FormatDateTime('[hh:nn:ss] ', Time) + s;      
end;      

constructor TEvents.Create;
begin
  inherited;
  FSyncEvent := TEvent.Create(nil, False, False, '');
end;

destructor TEvents.Destroy;
begin
  FSyncEvent.Free;
  inherited;
end;

procedure TEvents.Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);      
     
  Log(AUser.Nick+' '+ACommand+' '+AContent);      
end;      

procedure TEvents.Wake(Sender: TObject);
begin
  FSyncEvent.SetEvent;
end;

procedure TEvents.CheckSync;
begin
  FSyncEvent.WaitFor(Infinite);
  CheckSynchronize;
end;

const     
  IrcServ = 'gr.irc.gr';     
  IrcPort = 6667;     
  IrcChan = '#lalala';     

var      
  Irc: TidIRC;      
  Event: TEvents;      
  uName, rName: string;      

begin
  Event := TEvents.Create;       
  try
    WakeMainThread := Event.Wake;
    Irc := TIdIRC.Create(nil);       
    try
      Irc.OnRaw := Event.Raw;       
      Randomize;       
      Write('Nickname: ');       
      ReadLn(uName);       
      rName := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;       
      with Irc do       
        AltNick := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
        Nick := rName;       
        Username := rName;       
        RealName := 'I.D.M.';       
        Host := IrcHost;       
        Port := IrcPort;       
        //MaxLineAction := maException;  <-- [ERROR] Undeclared identifier: 'maException'       
        ReadTimeout := 0;       
        UserMode := [];       
        Connect;       
        try
          Join(IrcChan);       
          do
            Event.CheckSync;
          until SomeCondition;
        finally
          Disconnect;
        end;
      end;       
    finally
      Irc.Free;
    end;
  finally
    Event.Free;
  end;
end.
@ Дэвид: Избыток действительно. Мне никогда не пришло бы в голову использовать Forms в консольном приложении.
Есть ли на самом деле в консольном приложении приложение с методом ProcessMessages ()?
На самом деле, теперь, когда я думаю об этом, есть более простое решение. В D7TThread.Synchronize() помещает запросы синхронизации в очередь в памяти, которую можно перекачать вручную, используяCheckSynchronize() функция в блоке классов, без какого-либо цикла сообщений вообще. Я обновил свой ответ, чтобы отразить это.
@rudy Это делает, если проект использует Forms.pas. Это чудовищное излишество, хотя. Просто используйте пока GetMessage (...) действительно начните TranslateMessage (...); DispatchMessage (...); конец; прокачать очередь.
Спасибо за твой ответ, Реми. Можно ли было бы объяснить с помощью некоторого кода, как «прокачать очередь сообщений»? Единственный поток, который я нашел в idirc.pas, этоTIdIrcReadThread, Я пытался поймать его с помощью собственного потока в проекте, но не повезло Dimitris Nats

Похожие вопросы