Delphi 7:在控制台应用程序(TidIRC)中处理事件
我正在尝试基于Indy的IRC组件TIdIRC制作一个控制台应用程序,但我遇到了事件问题。这是我的密码:Delphi 7:在控制台应用程序(TidIRC)中处理事件,delphi,events,delphi-7,console-application,indy,Delphi,Events,Delphi 7,Console Application,Indy,我正在尝试基于Indy的IRC组件TIdIRC制作一个控制台应用程序,但我遇到了事件问题。这是我的密码: program Project1; {$APPTYPE CONSOLE} uses SysUtils, Classes, Math, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdIRC; type TEvents = class public procedur
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.
到目前为止,我已经尝试了我所能想到的一切,但是,尽管应用程序已成功连接,但它不会返回任何原始消息。。。我缺少什么?TdIRC使用内部工作线程来接收数据。OnRaw事件在该线程解析数据时触发。线程使用TThread.Synchronize进行解析。由于主线程没有活动的VCL消息循环,因此可以手动泵送同步队列。连接后,在连接到IRC时,从循环中的类单元调用CheckSynchronize函数,例如:
begin
...
Connect;
try
Join(IrcChan);
do
CheckSynchronize;
Sleep(10);
until SomeCondition;
finally
Disconnect;
end;
...
end.
为了更好地衡量,您可以在Classes单元中为WakeMainThread事件分配一个处理程序,以帮助控制何时应调用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;
begin
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);
begin
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 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;
try
Join(IrcChan);
do
Event.CheckSync;
until SomeCondition;
finally
Disconnect;
end;
end;
finally
Irc.Free;
end;
finally
Event.Free;
end;
end.
TdIRC使用内部工作线程来接收数据。OnRaw事件在该线程解析数据时触发。线程使用TThread.Synchronize进行解析。由于主线程没有活动的VCL消息循环,因此可以手动泵送同步队列。连接后,在连接到IRC时,从循环中的类单元调用CheckSynchronize函数,例如:
begin
...
Connect;
try
Join(IrcChan);
do
CheckSynchronize;
Sleep(10);
until SomeCondition;
finally
Disconnect;
end;
...
end.
为了更好地衡量,您可以在Classes单元中为WakeMainThread事件分配一个处理程序,以帮助控制何时应调用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;
begin
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);
begin
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 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;
try
Join(IrcChan);
do
Event.CheckSync;
until SomeCondition;
finally
Disconnect;
end;
end;
finally
Irc.Free;
end;
finally
Event.Free;
end;
end.
谢谢你的回复,雷米。您是否可以用一些代码解释如何泵送消息队列?我在idirc.pas中找到的唯一线程是TIdIrcReadThread。我试图在project中使用自定义线程捕获它,但没有成功。控制台应用程序是否确实有一个具有ProcessMessages方法的应用程序?@rudy如果项目使用Forms.pas,它会。不过,这太过分了。只需在获取消息时使用。。。开始翻译信息。。。;发送消息。。。;终止为了排起长队。@David:真是太过分了。我从来不会想到在控制台应用程序中使用表单。事实上,现在我想到了一个更简单的解决方案。在D7中,TThread.Synchronize将同步请求放入内存队列,该队列可以使用类单元中的CheckSynchronize函数手动抽取,而不涉及任何消息循环。我已经更新了我的答案来反映这一点。谢谢你的回复,雷米。您是否可以用一些代码解释如何泵送消息队列?我在idirc.pas中找到的唯一线程是TIdIrcReadThread。我试图在project中使用自定义线程捕获它,但没有成功。控制台应用程序是否确实有一个具有ProcessMessages方法的应用程序?@rudy如果项目使用Forms.pas,它会。不过,这太过分了。只需在获取消息时使用。。。开始翻译信息。。。;发送消息。。。;终止为了排起长队。@David:真是太过分了。我从来不会想到在控制台应用程序中使用表单。事实上,现在我想到了一个更简单的解决方案。在D7中,TThread.Synchronize将同步请求放入内存队列,该队列可以使用类单元中的CheckSynchronize函数手动抽取,而不涉及任何消息循环。我更新了我的答案以反映这一点。