Mostrando entradas con la etiqueta Indy. Mostrar todas las entradas
Mostrando entradas con la etiqueta Indy. Mostrar todas las entradas

Donde están TServerSocket y tClientSocket




En las versiones actuales de Delphi podremos comprobar que no tenemos los componentes TServerSocket y TClientSocket, el motivo es que por diseño el fabricante los ha ocultado de la paleta de componentes, pero hay una forma de hacerlos visibles, ya que ambos son parte de la biblioteca "dclsockets"



Pasos que necesitas:

- Desde el IDE ir a Component--Install Packages

- Clic en Add  en la ventana "Install Packages"

- En la ventana "Add Design Package" localiza la carpeta "RAD Studio\5.0\bin" y selecciona:




  • dclsockets70.bpl for Delphi 7

  • dclsockets90.bpl for Delphi 2005

  • dclsockets100.bpl for Delphi 2006

  • dclsockets100.bpl for Delphi 2007




y clic en Open y después en OK



Ahora TServerSocket y TClientSocket aparecerán en la paleta de herramientas en la categoría de Internet.





Ejemplos idTCPServer idTCPClient con Indy






Aquí tienen cómo se envía un stream o un archivo con Indy10 dentro de una red de ordenadores.

Incluye el procedimiento principal en el Cliente y en el Server, junto con algunas funciones genéricas:



function ReceiveBuffer(AClient: TIdTCPClient; var ABuffer: TBytes): Boolean; 

function SendBuffer(AClient: TIdTCPClient; ABuffer: TBytes): Boolean; 

function SendBuffer(AContext: TIdContext; ABuffer: TBytes): Boolean; 

function ReceiveBuffer(AContext: TIdContext; var ABuffer: TBytes): Boolean;

function ReceiveStream(AContext: TIdContext; var AStream: TStream): Boolean;

function ReceiveStream(AClient: TIdTCPClient; var AStream: TStream): Boolean;

 function SendStream(AContext: TIdContext; AStream: TStream): Boolean;

function SendStream(AClient: TIdTCPClient; AStream: TStream): Boolean;

function ClientSendFile(AClient: TIdTCPClient; Filename: String): Boolean;

function ServerReceiveFile(AContext: TIdContext; ServerFilename: String;



- ENVIAR UN STREAM

Desde el Server:











var
afS_s,afS_r:tMemoryStream;

PROCEDURE TStreamServerForm.IdTCPServer1Execute(AContext: TIdContext);

BEGIN

afS_s := TmemoryStream.Create;

afS_r := TmemoryStream.Create;

TRY

Memo1.Lines.Add('Server  starting  .... ');

Image1.Picture.Bitmap.SaveToStream(aFS_s);

aFS_s.Seek(0, soFromBeginning);

AContext.Connection.IOHandler.ReadTimeout := 9000;

IF (ReceiveStream(AContext, TStream(aFS_r)) = False) THEN

BEGIN

TIdNotify.NotifyMethod(ShowCannotGetBufferErrorMessage);

Exit;

END;

Memo1.Lines.Add('size received stream ' + IntToStr(aFS_r.Size));

Image1.Picture.Bitmap.LoadFromStream(aFS_R);

aFS_r.Position := 0;

Image1.Picture.Bitmap.LoadFromStream(aFS_r);

TIdNotify.NotifyMethod(StreamReceived);

IF (SendStream(AContext, TStream(aFS_s)) = False) THEN

BEGIN

TIdNotify.NotifyMethod(ShowCannotSendBufferErrorMessage);

Exit;

END;

Memo1.Lines.Add('Stream sent');

Memo1.Lines.Add('Server  done .... ');

FINALLY

aFS_s.Free;

aFS_r.Free;

END;

END;







Desde el cliente:









procedure torm1.Button_SendStreamClick(Sender: TObject);

begin

aFs_s := TmemoryStream.Create;
aFs_r := TmemoryStream.Create;
Image1.Picture.Bitmap.SaveToStream(aFs_s);
aFs_s.Seek(0,soFromBeginning);
Memo1.Lines.Add('Try send stream to server.....');
if (SendStream(IdTCPClient1, TStream(aFs_s)) = False) then
begin
Memo1.Lines.Add('Cannot send STREAM to server, Unknown error occured');
Exit;
end;
Memo1.Lines.Add('Stream successfully sent');
if (ReceiveStream(IdTCPClient1, TStream(aFs_r)) = False) then
begin
Memo1.Lines.Add('Cannot get STREAM from server, Unknown error occured');
Exit;
end;

//Hay que tener en cuenta que tMemo no es threadsafe y puede dar problemas
// quizás seria conveniente quitar la línea de abajo
Memo1.Lines.Add('Stream received: ' + IntToStr(aFs_r.Size));
//SetClientState(False);
aFs_r.Position := 0;
Image1.Picture.Bitmap.LoadFromStream(aFs_r);
aFS_s.Free;
aFS_r.Free;
end;

//al conectar

procedure Tform1.CheckBox1Click(Sender: TObject);

begin

if (CheckBox1.Checked = True) then

begin

IdTCPClient1.Host := '127.0.0.1';

IdTCPClient1.Port := 6000;

IdTCPClient1.Connect;

end

else

IdTCPClient1.Disconnect;

end;








- ENVIAR O RECIBIR UN RECORD/BUFFER/FILE.






En el Server









procedure Tform1.IdTCPServer1Execute(AContext: TIdContext);

var

LSize: LongInt;

file1 :  String;

dummyStr : string;

begin

Memo1.Lines.Add('Server  starting  .... ' );

AContext.Connection.IOHandler.ReadTimeout  := 9000;

dummyStr := AContext.Connection.IOHandler.ReadLn;

file1:= FileNameEdit.Text;

if ( ServerSendFile(AContext, file1) = False ) then

begin

TIdNotify.NotifyMethod(ShowCannotGetFileErrorMessage);

Exit;

end

else

begin

Memo1.Lines.Add('Server  done, client file -> ' + file1);

end;



TIdNotify.NotifyMethod(FileReceived);

end;

procedure Tform1.FileReceived;

begin

Memo1.Lines.Add('File received' );

end;









En el cliente














procedure TForm1.Button_SendStreamClick(Sender: TObject);

var

LSize: LongInt;

begin

LSize := 0;

Memo1.Lines.Add('Try send stream to server.....');

IdTCPClient1.Host := '127.0.0.1';

IdTCPClient1.Port := 6000;

IdTCPClient1.IOHandler.WriteLn('GET FILE NOW');



if (ClientReceiveFile(IdTCPClient1, FileNameEdit.Text) = False) then

begin

 Memo1.Lines.Add('Cannot get record/buffer to server->' +

    FileNameEdit.Text);

 Exit;

end

else

begin

 Memo1.Lines.Add('get record/buffer to server, save as ....' +  FileNameEdit.Text);

end;

SetClientState(false);

end;







FUNCIONES GENÉRICAS PARA ENVIAR O RECIBIR STREAMS/FILES









function ReceiveBuffer(AClient: TIdTCPClient; var ABuffer: TBytes)

: Boolean;

var

LSize: LongInt;

begin

Result := True;

try

LSize := AClient.IOHandler.ReadLongInt();

AClient.IOHandler.ReadBytes(ABuffer, LSize, False);

except

Result := False;

end;

end;

function SendBuffer(AClient: TIdTCPClient; ABuffer: TBytes): Boolean;

begin

try

Result := True;

try

AClient.IOHandler.Write(LongInt(Length(ABuffer)));

AClient.IOHandler.WriteBufferOpen;

AClient.IOHandler.Write(ABuffer, Length(ABuffer));

AClient.IOHandler.WriteBufferFlush;

finally

AClient.IOHandler.WriteBufferClose;

end;

except

Result := False;

end;

end;

function SendBuffer(AContext: TIdContext; ABuffer: TBytes): Boolean;

begin

try

Result := True;

try

AContext.Connection.IOHandler.Write(LongInt(Length(ABuffer)));

AContext.Connection.IOHandler.WriteBufferOpen;

AContext.Connection.IOHandler.Write(ABuffer, Length(ABuffer));

AContext.Connection.IOHandler.WriteBufferFlush;

finally

AContext.Connection.IOHandler.WriteBufferClose;

end;

except

Result := False;

end;

end;

function ReceiveBuffer(AContext: TIdContext; var ABuffer: TBytes)

: Boolean;

var

LSize: LongInt;

begin

Result := True;

try

LSize := AContext.Connection.IOHandler.ReadLongInt();

AContext.Connection.IOHandler.ReadBytes(ABuffer, LSize, False);

except

Result := False;

end;

end;

///

/// ---------------------   HELP FUNCTION FOR STREAM  EXCHANGE  --------------

///

function ReceiveStream(AContext: TIdContext; var AStream: TStream)

: Boolean;

var

LSize: LongInt;

begin

Result := True;

try

LSize := AContext.Connection.IOHandler.ReadLongInt();

AContext.Connection.IOHandler.ReadStream(AStream, LSize, False);

except

Result := False;

end;

end;

function ReceiveStream(AClient: TIdTCPClient; var AStream: TStream)

: Boolean;

var

LSize: LongInt;

begin

Result := True;

try

LSize := AClient.IOHandler.ReadLongInt();

AClient.IOHandler.ReadStream(AStream, LSize, False);

except

Result := False;

end;

end;

function SendStream(AContext: TIdContext; AStream: TStream): Boolean;

var

StreamSize: LongInt;

begin

try

Result := True;

try

StreamSize := (AStream.Size);

// AStream.Seek(0, soFromBeginning);

AContext.Connection.IOHandler.Write(LongInt(StreamSize));

AContext.Connection.IOHandler.WriteBufferOpen;

AContext.Connection.IOHandler.Write(AStream, 0, False);

AContext.Connection.IOHandler.WriteBufferFlush;

finally

AContext.Connection.IOHandler.WriteBufferClose;

end;

except

Result := False;

end;

end;

function SendStream(AClient: TIdTCPClient; AStream: TStream): Boolean;

var

StreamSize: LongInt;

begin

try

Result := True;

try

StreamSize := (AStream.Size);

// AStream.Seek(0, soFromBeginning);

// AClient.IOHandler.LargeStream := True;

// AClient.IOHandler.SendBufferSize := 32768;

AClient.IOHandler.Write(LongInt(StreamSize));

AClient.IOHandler.WriteBufferOpen;

AClient.IOHandler.Write(AStream, 0, False);

AClient.IOHandler.WriteBufferFlush;

finally

AClient.IOHandler.WriteBufferClose;

end;

except

Result := False;

end;

end;

///

/// ---------------      HELPER FUNCTIONS FOR FILES EXCHANGE  ----------------

///

function ClientSendFile(AClient: TIdTCPClient; Filename: String): Boolean;

begin

AClient.IOHandler.LargeStream := True; // fully support large streams

Result := True;

try

AClient.IOHandler.WriteFile(Filename); // send file stream data

except

Result := False;

end;

end;

function ServerReceiveFile(AContext: TIdContext; ServerFilename: String;

var ClientFilename: String): Boolean;

var

// LSize: String;

AStream: TFileStream;

begin

try

Result := True;

AStream := TFileStream.Create(ServerFilename, fmCreate + fmShareDenyNone);

try

AContext.Connection.IOHandler.ReadStream(AStream);

finally

FreeAndNil(AStream);

end;

except

Result := False;

end;

end;
























Cliente / Servidor TCP con Indy I






Programa que desarrolla un ejemplo de un Cliente / Servidor con los componentes Indy utilizando tIdTCPClient y tIdTCPServer.


¿Que lo diferencia de otros parecidos? pues que utiliza un Thread con su respectivo procedimiento Constructor y Execute para evitar los interbloqueos que se producían en otros ejemplos que he visto por la red.

Según mi experiencia la utilización del tIdAntiFreeze en la aplicación no es suficiente.

El componente tIdTCPServer es multithread por definición, y no se necesita procedimientos que manejen los hilos, todo es transparente aunque depende de cómo escribas la aplicación para un cliente. Si usas el evento OnConnect verás que existe un parámetro en tIdContext que te proporciona un TThreadList que incluye la lista de clientes activos.. Se puede usar ese evento para registrar o añadir clientes y en el evento OnDisconnect para eliminarlos o también se puede utilizar un loop que periódicamaente chequee la lista.

El evento onExecute tiene un parámetro llamado Acontext: tIdContext, por lo que si escribes Acontext.Connection tienes un método para enviar datos a un cliente por ejemplo mediante Acontext.Connection.SendCmd, también tienes la propiedad Acontext.Connection.Socket que tiene una subpropiedad para almacenar la Ip del cliente.



Documentación de Indy:

http://www.indyproject.org/downloads/Indy_9_00_14_src.zip 



Libro sobre indy

http://www.atozed.com/Indy/Book/index.EN.aspx



Un tutorial

http://www.devarticles.com/c/a/Delphi-Kylix/Creating-Chat-Application-with-Borland-DelphiIndy-The-Client/





Todos los procedimientos y funciones que a continuación enumero se refieren al lado del cliente.





Cada vez que se conecta un cliente:

procedure TForm1.btnConectaClick(Sender: TObject);
begin
if IdTCPClient1.Connected then
IdTCPClient1.Disconnect
else
begin
IdTCPClient1.Host := lbEdtServidor.Text;
IdTCPClient1.Port := StrToInt(lbEdtPorta.Text);
IdTCPClient1.Connect(5000);
end;
end;










Y en el evento OnConnected:

procedure TForm1.IdTCPClient1Connected(Sender: TObject);
begin

IdTCPClient1.WriteLn('nick='+lbEdtNick.Text); //envia el nick del usuario al server

...

TClientThread.Create(false);  //Hace la llamada al thread



end;




El procedimiento del thread es el siguiente:



type



TClientThread = class(TThread)

protected

procedure Execute; override;

public

constructor Create(CreateSuspended: Boolean);

end;






En la implementation se construye de la siguiente forma:



{ TClientThread }



constructor TClientThread.Create(CreateSuspended: Boolean);

begin

inherited Create(CreateSuspended);

Priority := tpIdle;

FreeOnTerminate:= true;

end;



procedure TClientThread.Execute;

begin

inherited;

with Form1 do

begin

if not IdTCPClient1.Connected then

 exit;

repeat

cmd.text:= IdTCPClient1.ReadLn;

if trim(cmd.text) <> '' then

begin

if VerificaComando(cmd.text,'msg=',true) then

 Synchronize(ShowReceiveMsg)

else if VerificaComando(cmd.text,'list_user=',true) then

 Synchronize(ListUsers)

else if VerificaComando(cmd.text,'nick_existente=',true) then

 Synchronize(NickExistente)

else if VerificaComando(cmd.text,'server_error=',true) then

 Synchronize(ShowServerError)

else Synchronize(UnknowCmd);

end;

until not IdTCPClient1.Connected;

end;

{if not Terminated then

 Terminate;}

end;





Para cerrar la conexión:




procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

IdTCPClient1.Disconnect;

end;






Para enviar un texto al servidor:





procedure TForm1.btnEnviarClick(Sender: TObject);

begin

 IdTCPClient1.WriteLn(FormatChatMessage(lbEdtMsg.Text,lbEdtNick.Text,cmbUsuario.Text,cboxReservado.Checked));

end;




Las siguientes funciones se ejecutan en el TClientThread.Execute.





function VerificaComando(Recebido, Comando: String; Parcial: boolean): Boolean;

begin

recebido:= AnsiLowerCase(trim(recebido));

comando:= AnsiLowerCase(trim(comando));

if not Parcial then

 result:= AnsiSameText(recebido, comando)

else result:= pos(comando, recebido) <> 0;

end;



function ReceiveMsg(Received: String): String;

var

i: integer;

de, para, aux: ShortString;

msg: String;

begin

i:= pos('=',Received);

aux:= copy(Received,i+1,length(Received));



i:= pos('#',aux);

de:= copy(aux,1,i-1);

delete(aux,1,i);



i:= pos('#',aux);

para:= copy(aux,1,i-1);

delete(aux,1,i);

msg:= aux;



i:= pos('#',msg);

if i = 0 then

 result:= de + ' habla con ' + para + ': ' + msg

else

begin

delete(msg,i,length(msg));

result:= de + '  habla reservadamente con ' + para + ': ' + msg

end;

end;



function RemetenteMsg(Received: String): ShortString;

var

i: integer;

begin

i:= pos('=',Received);

received:= copy(Received,i+1,length(Received));



i:= pos('#',received);

result:= copy(received,1,i-1);

end;



function DestinatarioMsg(Received: String): ShortString;

var

i: integer;

begin

i:= pos('=',Received);

Received:= copy(Received,i+1,length(Received));



i:= pos('#',Received);

delete(Received,1,i);



i:= pos('#',Received);

result:= copy(Received,1,i-1);

end;





function FormatChatMessage(Msg, UsuarioOrigem, UsuarioDestino: String; Reservado: Boolean = false): String;

begin

result:= 'msg=' + UsuarioOrigem + '#' + UsuarioDestino + '#' + msg;

if Reservado then

 result:= result + '#reservado';

end;






Próximamente publicaré el código fuente correspondiente al Server (por no hacer más largo este post)  y el programa completo.






 Tienen más información aquí (Idioma holandés)




























Cliente / Servidor TCP con Indy II

Bueno pues aquí tienen la segunda parte del post anterior sobre el establecimiento de una comunicación Cliente / Servidor con Indy.

Lo que voy a postear a continuación es la parte correspondiente al Server.



En la parte Type, se define el siguiente puntero que almacena la información de los clientes y que se liberará cuando se desconecten.



type
PConexao = ^TConexao;
TConexao = record
IP: ShortString;
ThreadID: Cardinal;
Connection: TidTCPServerConnection;
Usuario: ShortString;
end;





En el evento OnCreate :





procedure TForm1.FormCreate(Sender: TObject);

begin

  IdTCPServer1.Active := true;

  cmd:= TStringList.Create; //Almacena los comandos de los clientes

  conn:= TList.Create; //Listado que contiene los usuarios clientes que están conectados al Server

end;




Evento OnClose :





procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

begin

  tag:= conn.Count; //Cuenta el número de clientes conectados

  if tag > 0 then

  begin

    action:= caNone;

    Application.MessageBox('No se puede cerrar el Server ya que hay clientes      conectados','Informacion',mb_iconInformation)

  end

  else

  begin

    cmd.Free;

    Conn.Free;

    IdTCPServer1.Active := false;

  end;

end;




Procedimientos asociados al componente IdTCPServer :



Al conectar:





Procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);

var ConAux: PConexao;

begin

 cmd.text:= AThread.Connection.ReadLn;

 if AnsiSameText(Admin,cmd.Values['nick']) then

    AThread.Connection.Writeln('nick existent o es el nick del Administrador.')

 else

 begin

   xUniqueUser := UniqueUser(cmd.Values['nick']);

   if xUniqueUser then

   begin

     AThread.Connection.Writeln('Bienvenido al Servidor'#10);

     GetMem(ConAux,SizeOf(TConexao));

     try

       ConAux.ThreadID := AThread.ThreadID;

       ConAux.Connection:= AThread.Connection;

       ConAux.IP := AThread.Connection.Socket.Binding.PeerIP;

       ConAux.Usuario := cmd.Values['nick'];



       AThread.Data := TObject(ConAux);

       conn.Add(ConAux);

       UsuarioEntrou;

     finally

       //FreeMem(ConAux);

       ShowConnections;

     end;

   end

   else AThread.Connection.Writeln('Nick existente');

 end;

end;






Al Desconectar:





procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);

var

  ConAux: PConexao;

  aux: string;

begin

  if xUniqueUser then

  begin

    ConAux:= PConexao(AThread.Data);

    try

      conn.Remove(ConAux);

      aux:= ConAux.Usuario + ' ha salido de la sala de chat.';

      memo1.lines.add(aux);

      SendMsgToAll(aux);

      AThread.Data := nil;

    finally

      FreeMem(ConAux); //libera el puntero de la información del cliente

    end;

    ListUsers;

    ShowConnections;

  end

  else xUniqueUser:= true;

end;




On Execute :





procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);

begin

  try

    cmd.Text:= AThread.Connection.ReadLn;

    if VerificaComando(cmd.text,'msg=',true) then

    begin

       SendMsg;

       memo1.lines.add(ReceiveMsg(cmd.text));

    end;

  except

    on e: Exception do

    begin

      AThread.Connection.WriteLn('server_error='+e.message);

    end;

  end;

end;




Probado para Indy 9 (delphi 7)

Si quiere utilizar Indy10  (delphi 2009 o superior) hay que cambiar:

- AThread : TIdPeerThread    por    AContext: TIdContext

- AThread     por    AContext

- AThread.connection.readln     por   AContext.Connection.iohandler.ReadLn;

- AThread.connection.writeln (XXX)   por AContext.Connection.iohandler.Writeln (XXX);



En el record:



  TConexao = record

    IP: ShortString;

    ThreadID: Cardinal;

    Connection: TidTCPConnection;   <----hay a="" adiendo="" cambiar="" el="" en="" esto="" idtcpconnection="" nbsp="" p="" que="" uses="">    Usuario: ShortString;

  end;







enlace | Codigo fuente





Autor: Manoel Campos da Silva Filho

           Professor da Escola Técnica Federal de Palmas

           E-Mail: mcampos@etfto.gov.br













Detección de colisiones 2D



El componente TRSCollisionMap implementa las clases necesarias para la detección de colisiones en objetos 2D, así que si se animan a programar un juego aquí tienen parte del trabajo hecho.


Por lo que he visto en la documentación es útil en el caso de que no existan muchos objetos moviéndose en pantalla.



Código fuente y ejecutable:

http://www.riversoftavg.com/Files/RSCollisionDetection.zip









How to Get NS, MX, SOA of a Domain with Indy

if you want to get the name server, mail server and SOA of a IP with the indy vcl try this:

Put a TidDnsResolver Component an a tTMemo in a Form


PROCEDURE TForm1.CheckDNS(Dominio:ansistring);
VAR
i, j: integer;

BEGIN
memoresult.clear;
idDNSResolver.Active := False;
idDNSResolver.QueryResult.Clear;
idDNSResolver.host := eddns.text; // your dns-server

WITH idDNSResolver DO //qtNS
BEGIN
Active := true;
QueryResult.Clear;
QueryRecords := [qtNS];
resolve(dominio);
memoresult.lines.add('========== NS ');
FOR i := 0 TO QueryResult.Count - 1 DO
BEGIN
IF QueryResult[i].RecType = qtNS THEN
BEGIN
memoResult.Lines.Append(' Host : ' + (QueryResult[i] AS tNSRecord).HostName);
memoResult.Lines.Append(' Name : ' + (QueryResult[i] AS tNSRecord).Name);
memoResult.Lines.Append(' TTL : ' + IntToStr((QueryResult[i] AS tNSRecord).TTL));
END;
END;
Active := False;
END;


WITH idDNSResolver DO //qtSOA
BEGIN
Active := true;
QueryResult.Clear;
QueryRecords := [qtSOA];
resolve(dominio);
memoresult.lines.add('========== SOA ');
FOR i := 0 TO QueryResult.Count - 1 DO
BEGIN
IF QueryResult[i].RecType = qtSOA THEN
BEGIN
memoResult.Lines.Append(' Domain Name: ' + (QueryResult[i] AS TSOARecord).Primary);
memoResult.Lines.Append(' Responsable: ' + (QueryResult[i] AS TSOARecord).REsponsiblePerson);
memoResult.Lines.Append(' Serial : ' + IntToStr((QueryResult[i] AS TSOARecord).Serial));
memoResult.Lines.Append(' Refresh : ' + IntToStr((QueryResult[i] AS TSOARecord).Refresh));
memoResult.Lines.Append(' Retry : ' + IntToStr((QueryResult[i] AS TSOARecord).Retry));
memoResult.Lines.Append(' Expire : ' + IntToStr((QueryResult[i] AS TSOARecord).Expire));
memoResult.Lines.Append(' MinimunTTL : ' + IntToStr((QueryResult[i] AS TSOARecord).MinimumTTL));
END;
END;
Active := False;
END;

WITH idDNSResolver DO //qtMX
BEGIN
Active := true;
QueryResult.Clear;
QueryRecords := [qtMX];
resolve(dominio);
memoresult.lines.add('========== MX ');
FOR i := 0 TO QueryResult.Count - 1 DO
BEGIN
IF QueryResult[i].RecType = qtMX THEN
BEGIN
memoResult.Lines.Append(' Domain Name: ' + (QueryResult[i] AS TMXRecord).ExchangeServer);
memoResult.Lines.Append(' Preferencia: ' + IntToStr((QueryResult[i] AS TMXRecord).Preference));
END;
END;
Active := False;
END;

memoresult.lines.append(' ===== fin ==== ');

END;


Retrieve all image links from an HTML document

uses mshtml, ActiveX, COMObj, IdHTTP, idURI;

{ .... }

procedure GetImageLinks(AURL: string; AList: TStrings);
var
IDoc: IHTMLDocument2;
strHTML: string;
v: Variant;
x: Integer;
ovLinks: OleVariant;
DocURL: string;
URI: TidURI;
ImgURL: string;
idHTTP: TidHTTP;
begin
AList.Clear;
URI := TidURI.Create(AURL);
try
DocURL := 'http://' + URI.Host;
if URI.Path <> '/' then
DocURL := DocURL + URI.Path;
finally
URI.Free;
end;
Idoc := CreateComObject(Class_HTMLDocument) as IHTMLDocument2;
try
IDoc.designMode := 'on';
while IDoc.readyState <> 'complete' do
Application.ProcessMessages;
v := VarArrayCreate([0, 0], VarVariant);
idHTTP := TidHTTP.Create(nil);
try
strHTML := idHTTP.Get(AURL);
finally
idHTTP.Free;
end;
v[0] := strHTML;
IDoc.Write(PSafeArray(System.TVarData(v).VArray));
IDoc.designMode := 'off';
while IDoc.readyState <> 'complete' do
Application.ProcessMessages;
ovLinks := IDoc.all.tags('IMG');
if ovLinks.Length > 0 then
begin
for x := 0 to ovLinks.Length - 1 do
begin
ImgURL := ovLinks.Item(x).src;
// The stuff below will probably need a little tweaking
// Deteriming and turning realtive URLs into absolute URLs
// is not that difficult but this is all I could come up with
// in such a short notice.
if (ImgURL[1] = '/') then
begin
// more than likely a relative URL so
// append the DocURL
ImgURL := DocURL + ImgUrl;
end
else
begin
if (Copy(ImgURL, 1, 11) = 'about:blank') then
begin
ImgURL := DocURL + Copy(ImgUrl, 12, Length(ImgURL));
end;
end;
AList.Add(ImgURL);
end;
end;
finally
IDoc := nil;
end;
end;


// Beispiel:
// Example:
procedure TForm1.Button1Click(Sender: TObject);
begin
GetImageLinks('http://delphimagic.blogspot.com', Memo1.Lines);
end;

Simulación del movimiento de los electrones en un campo electrico

Espectacular simulación realizada con OpenGL del movimiento de los electrones cuando atraviesan un campo eléctrico. Como muestra la image...