hello am doing a program in delphi console, xe2 delphi and indy for using sockets and the problem is that I have all the code done but when I connect to the server I receive no response to the ping pong.
the code is as follows:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, idTCPClient;
var
irc: TIdTCPClient;
code: string;
begin
try
irc := TIdTCPClient.Create(nil);
irc.Host := 'irc.freenode.net';
irc.Port := 6667;
irc.Connect;
irc.Socket.Write('NICK tester');
irc.Socket.Write('USER tester 1 1 1 1');
irc.Socket.Write('JOIN #tester');
if irc.Socket.Connected = True then
begin
Writeln('Yeah');
while (1 = 1) do
begin
code := irc.Socket.ReadString(9999);
if not(code = '') then
begin
Writeln(code);
end;
end;
end
else
begin
Writeln('Nay');
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
anyone can help me?
You are not sending a CRLF after each command you send. Use TIdIOHander.WriteLn() instead of TIdIOHandler.Write().
Also, your call to TIdIOHandler.ReadString() will not exit until exactly 9999 bytes have been received. That is not what you actually want to happen. IRC is a line-based protocol. You should be using TIdIOHandler.ReadLn() instead of TIdIOHandler.ReadString().
Try something more like this instead:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, idTCPClient;
var
irc: TIdTCPClient;
code: string;
begin
try
irc := TIdTCPClient.Create(nil);
try
irc.Host := 'irc.freenode.net';
irc.Port := 6667;
try
irc.Connect;
except
Writeln('Nay');
Exit;
end;
Writeln('Yeah');
irc.IOHandler.WriteLn('NICK tester');
irc.IOHandler.WriteLn('USER tester 1 1 1 1');
irc.IOHandler.WriteLn('JOIN #tester');
repeat
code := irc.IOHandler.ReadLn;
Writeln('[Recv] ' + code);
if TextStartsWith(code, 'PING ') then
begin
Fetch(code);
irc.IOHandler.WriteLn('PONG ' + code);
Writeln('[Sent] PONG ' + code);
end;
until False;
finally
irc.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
With that being said, you should be using the TIdIRC component instead. Try this:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, idIRC, idContext, idGlobal;
procedure IrcRaw(ASelf: Pointer; ASender: TIdContext; AIn: Boolean; const AMessage: String);
begin
Writeln(iif(AIn, '[Recv] ', '[Sent] ') + AMessage);
end;
var
irc: TIdIRC;
m: TMethod;
begin
try
irc := TIdIRC.Create(nil);
try
irc.Host := 'irc.freenode.net';
irc.Port := 6667;
irc.Nickname := 'tester';
irc.Username := 'tester';
m.Code := #IrcRaw;
m.Data := irc;
irc.OnRaw := TIdIRCRawEvent(m);
try
irc.Connect;
except
Writeln('Nay');
Exit;
end;
Writeln('Yeah');
irc.Join('#tester');
repeat
Sleep(10);
until SomeCondition;
finally
irc.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Related
How can I extract domain suffix without entering http:// or https://?
For example, if I enter stackoverflow.com, I want to get the result of com.
I have this function, but I must enter http:// to get the result.
Is there any way to skip entering http:// and https://?
procedure TForm1.Button2Click(Sender: TObject);
function RatChar(S:String; C: Char):Integer;
var
i : Integer;
begin
i := Length(S);
//while (S[i] <> C) and (i > 0) do
while (i > 0) and (S[i] <> C) do
Dec(i);
Result := i;
end;
var
uri: TIdURI;
i: Integer;
begin
uri := TidURI.Create(Edit2.Text);
try
//Memo1.Lines.Add(uri.Protocol);
//Memo1.Lines.Add(uri.Host);
i := RatChar(uri.Host, '.');
Memo1.Lines.Add(Copy(uri.Host, i+1, Length(uri.Host)));
Memo1.Lines.Add(uri.Document);
finally
uri.Free;
end;
end;
uses
System.SysUtils;
var
u : string;
arr: TArray<string>;
begin
try
u := 'https://stackoverflow.com/questions/71166883/how-to-extract-domain-suffix';
arr := u.Split(['://'], TStringSplitOptions.ExcludeEmpty);
u := arr[High(arr)]; //stackoverflow.com/questions/71166883/how-to-extract-domain-suffix';
arr := u.Split(['/'], TStringSplitOptions.ExcludeEmpty);
u := arr[0]; //stackoverflow.com
arr := u.Split(['.'], TStringSplitOptions.ExcludeEmpty);
u := arr[High(arr)]; //com
writeln('Top-Level-Domain: ', u);
readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
According to suggestion Extracting top-level and second-level domain from a URL using regex it should run like this in Delphi:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.RegularExpressions;
var
url,
rePattern: string;
rMatch : TMatch;
rGroup : TGroup;
arr : TArray<string>;
begin
try
url := 'https://www.answers.com/article/1194427/8-habits-of-extraordinarily likeable-people';
//url := 'https://stackoverflow.com/questions/71166883/how-to-extract-domain-suffix';
rePattern := '^(?:https?:\/\/)(?:w{3}\.)?.*?([^.\r\n\/]+\.)([^.\r\n\/]+\.[^.\r\n\/]{2,6}(?:\.[^.\r\n\/]{2,6})?).*$';
rMatch := TRegEx.Match(url, rePattern);
if rMatch.Success then
begin
rGroup := rMatch.Groups.Item[pred(rMatch.Groups.Count)];
arr := rGroup.Value.Split(['.']);
writeln('Top-Level-Domain: ', arr[High(arr)]);
end
else
writeln('Sorry');
readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
However, this regular expression only works when www. is supplied.
Delphi XE8 and SQLServer 2017.
I have a query (TADOQuery) connected to a SQLServer database. After opening the dataset (TADOQuery.Open), if I call TADOQuery.FieldByName('X').AsCurrency it returns 0, but if I call TADOQuery.FieldByName('X').AsFloat it returns 12.65 (correct value). Looking at the specific field in the table, the type is numeric(18,4). What's wrong?
This code runs the otherthing:
with TADOQuery1 do
begin
SQL.Clear;
SQL.Add('select X from Table1');
Open;
if FieldByName('X').AsCurrency > 0 then // <- Here is the problem
do something
else
do otherthing;
end;
This code runs the something:
with TADOQuery1 do
begin
SQL.Clear;
SQL.Add('select X from Table1');
Open;
if FieldByName('X').AsFloat > 0 then // <- Here is the problem
do something
else
do otherthing;
end;
Cannot reproduce this behavior.
here is a MRE, amount is a numeric(18,4) in table Tbl_test :
program SO68004040;
{$APPTYPE CONSOLE}
{$R *.res}
uses
ActiveX,
AdoDb,
System.SysUtils;
var
DbConn : TADOConnection;
Qry : TADOQuery;
begin
Coinitialize(nil);
try
DbConn := TADOConnection.Create(nil);
Qry := TADOQuery.Create(nil);
try
Qry.Connection := DbConn;
DbConn.ConnectionString := 'Provider=SQLOLEDB.1;Persist Security Info=True;Initial Catalog=TestCustomer;Data Source=localhost\SQLEXPRESS;Integrated Security=SSPI; ';
DbConn.Connected := True;
Qry.SQL.Text := 'SELECT * FROM Tbl_test';
Qry.Open;
while not Qry.Eof do
begin
Writeln(Format('AsCurrency: %.4f', [Qry.FieldByName('amount').AsCurrency]));
Writeln(Format('AsFloat: %.4f', [Qry.FieldByName('amount').AsFloat]));
Qry.Next;
end;
finally
Qry.Free;
DbConn.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
CoUninitialize();
Readln;
end.
Is there some way to remove or replace the absolute path of an EAssertionFailed error message? I would like to not include the entire path to not indirectly reveal where the source has been compiled and make the message independent of that location. Preferably the relative path to the project root or to the DPR file, or the source file name only would be included in the error message instead.
Program output:
EAssertionFailed: Assertion failed (C:\Users\User\Documents\
Embarcadero\Studio\Projects\Project3.dpr, line 12)
Project3.dpr
program Project3;
{$AppType Console}
{$R *.res}
uses
System.SysUtils;
begin
try
Assert(False);
except
on E: Exception do
begin
WriteLn(E.ClassName, ': ', E.Message);
ReadLn;
end;
end;
end.
Replace or hook the AssertErrorProc and alter or suppress the filename and line number information.
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysConst,
System.SysUtils;
procedure CustomAssertErrorHandler(const Message, Filename: string; LineNumber: Integer; ErrorAddr: Pointer);
var
FileNameOnly : string;
begin
FileNameOnly := ExtractFileName(FileName);
if Message <> '' then
raise EAssertionFailed.CreateFmt(SAssertError,
[Message, FileNameOnly, LineNumber]) at ErrorAddr
else
raise EAssertionFailed.CreateFmt(SAssertError,
[SAssertionFailed, FileNameOnly, LineNumber]) at ErrorAddr;
end;
begin
AssertErrorProc := CustomAssertErrorHandler;
try
Assert(False);
except
on E: Exception do
begin
WriteLn(E.ClassName, ': ', E.Message);
ReadLn;
end;
end;
end.
Update: Here is the questioner's solution which converts from the full project path to a relative path:
program Project3;
{$AppType Console}
{$R *.res}
uses
System.SysConst,
System.SysUtils;
procedure AssertErrorHandler(const Msg, Filename: String;
LineNumber: Integer; ErrorAddr: Pointer);
{$Region '$Include ProjectRoot.pas.inc'}
const
ProjectRoot = 'C:\Users\';
{$EndRegion}
var
Temp: String;
begin
if (ProjectRoot <> '') and Filename.StartsWith(ProjectRoot) then
Temp := Filename.Remove(0, ProjectRoot.Length)
else
Temp := ExtractFileName(Filename);
if Msg <> '' then
raise EAssertionFailed.CreateResFmt(#SAssertError,
[Msg, Temp, LineNumber]) at ErrorAddr
else
raise EAssertionFailed.CreateResFmt(#SAssertError,
[SAssertionFailed, Temp, LineNumber]) at ErrorAddr;
end;
begin
try
AssertErrorProc := AssertErrorHandler;
// Assert(False);
Assert(False, 'Custom message');
except
on E: Exception do
begin
WriteLn(E.ClassName, ': ', E.Message);
ReadLn;
end;
end;
end.
I have created this unit containing a class derived from TXmlIniFile:
unit PAXMLIniFile;
interface
uses
System.SysUtils,
System.IniFiles,
Xml.XmlDoc,
Xml.XMLIntf,
Xml.XMLIniFile;
type
TMyStandaloneXmlIniFile = class(TXmlIniFile)
strict private
FDocument: IXMLDocument;
FFileName: string;
public
constructor Create(const AFileName: string);
procedure UpdateFile; override;
end;
implementation
constructor TMyStandaloneXmlIniFile.Create(const AFileName: string);
begin
if FileExists(AFileName) then
FDocument := LoadXMLDocument(AFileName)
else
begin
FDocument := NewXMLDocument;
FDocument.Options := FDocument.Options + [doNodeAutoIndent];
end;
if FDocument.DocumentElement = nil then
FDocument.DocumentElement := FDocument.CreateNode('Sections');
TCustomIniFile(Self).Create(AFileName);
FFileName := AFileName;
inherited Create(FDocument.DocumentElement);
end;
procedure TMyStandaloneXmlIniFile.UpdateFile;
begin
FDocument.SaveToFile(FFileName);
end;
end.
Now whenever I call the UpdateFile method I get an error message "Wrong parameter". What is wrong here?
Here is the test program:
program BonkersTest;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, PAXMLIniFile, Winapi.ActiveX;
var
MyStandaloneXmlIniFile: TMyStandaloneXmlIniFile;
MyXmlFile: string;
begin
try
CoInitialize(nil);
MyXmlFile := ChangeFileExt(ParamStr(0), '.xml');
MyStandaloneXmlIniFile := TMyStandaloneXmlIniFile.Create(MyXmlFile);
try
MyStandaloneXmlIniFile.WriteString('Section1', 'Ident1', 'Value1');
MyStandaloneXmlIniFile.UpdateFile;
finally
MyStandaloneXmlIniFile.Free;
end;
CoUninitialize;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
I'm trying to execute this code (this is a minimal sample in order to use CreateOleObject) from inside of a dwscript
function GetFileVersion(const FileName: string): string;
var
V : OleVariant;
begin
V := CreateOleObject('Scripting.FileSystemObject');
Result := V.GetFileVersion(FileName);
end;
So far i tried this
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils,
ComObj,
ActiveX,
dwsComp,
dwsCompiler,
dwsExprs,
dwsCoreExprs;
procedure Execute;
var
LScript: TDelphiWebScript;
LUnit: TdwsUnit;
LProg: IdwsProgram;
LExec: IdwsProgramExecution;
begin
LScript := TDelphiWebScript.Create(NIL);
LUnit := TdwsUnit.Create(NIL);
try
LUnit.UnitName := 'Foo';
LUnit.Script := LScript;
// compile a simple script
LProg := LScript.Compile(
'function GetFileVersion(const FileName: string): string;'+sLineBreak+
'var'+sLineBreak+
' V : Variant;'+sLineBreak+
'begin'+sLineBreak+
' V := CreateOleObject(''Scripting.FileSystemObject'');'+sLineBreak+
' Result := V.GetFileVersion(FileName);'+sLineBreak+
'end;'+sLineBreak+
''+sLineBreak+
'PrintLn(GetFileVersion(''Foo''));'+sLineBreak+
''
);
if LProg.Msgs.HasErrors then begin
Writeln(LProg.Msgs.AsInfo);
Exit;
end;
try
LExec := LProg.Execute;
except
on E: Exception do
WriteLn(E.Message + sLineBreak + LExec.Msgs.AsInfo );
end;
Writeln(LExec.Result.ToString);
finally
LScript.Free;
end;
end;
begin
try
Execute;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
But i'm getting this error message
Syntax Error: Unknown name "CreateOleObject" [line: 5, column: 8]
the question is how i can execute the CreateOleObject function using dwscript?
UPDATE
Following the Linas suggestions I could finally resolve the issue.
This is a sample working application
uses
SysUtils,
ComObj,
ActiveX,
dwsComp,
dwsCompiler,
dwsExprs,
dwsComConnector,
dwsCoreExprs;
procedure Execute;
var
LScript: TDelphiWebScript;
LUnit: TdwsUnit;
LProg: IdwsProgram;
LExec: IdwsProgramExecution;
LdwsComConnector : TdwsComConnector;
begin
LScript := TDelphiWebScript.Create(NIL);
LdwsComConnector:=TdwsComConnector.Create(nil);
LdwsComConnector.Script:=LScript;
LUnit := TdwsUnit.Create(NIL);
try
LUnit.UnitName := 'Foo';
LUnit.Script := LScript;
// compile a simple script
LProg := LScript.Compile(
'function GetFileVersion(const FileName: string): string;'+sLineBreak+
'var'+sLineBreak+
' V : OleVariant;'+sLineBreak+
'begin'+sLineBreak+
' V := CreateOleObject(''Scripting.FileSystemObject'');'+sLineBreak+
' Result := VarToStr(V.GetFileVersion(FileName));'+sLineBreak+
'end;'+sLineBreak+
''+sLineBreak+
'PrintLn(GetFileVersion(''C:\Bar\Foo.exe''));'+sLineBreak+
''
);
if LProg.Msgs.HasErrors then begin
Writeln(LProg.Msgs.AsInfo);
Exit;
end;
try
LExec := LProg.Execute;
except
on E: Exception do
WriteLn(E.Message + sLineBreak + LExec.Msgs.AsInfo );
end;
Writeln(LExec.Result.ToString);
finally
LScript.Free;
LdwsComConnector.Free;
end;
end;
begin
try
CoInitialize(nil);
try
Execute;
Readln;
finally
CoUninitialize;
end;
except
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
end.
This can be accomplished in two ways.
1 way: You must drop TdwsComConnector (from unit dwsComConnector) to your data module or form (or create it manually) and assign your script instance to it. e.g.:
dwsComConnector1.Script := LScript;
2 way:
interface
uses
dwsFunctions, dwsSymbols, dwsExprs;
type
TCreateOleObjectFunc = class(TInternalFunction)
procedure Execute(info : TProgramInfo); override;
end;
implementation
uses
OleAuto;
{ TCreateOleObjectFunc }
procedure TCreateOleObjectFunc.Execute(info : TProgramInfo);
begin
Info.ResultAsVariant := CreateOleObject(Info.ValueAsString['ClassName']);
end;
initialization
RegisterInternalFunction(TCreateOleObjectFunc, 'CreateOleObject', ['ClassName', cString], cVariant, True);
This will expose CreateOleObject function to DWScript so you could use it.
Also you should declare your V as OleVariant instead of Variant and change the line to Result := VarToStr(V.GetFileVersion(FileName)); to make it work properly.