home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / zkuste / vbasic / Data / Utils / XZipComp.exe / XceedWinsock.Cab / F112694_unHttpServer.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2000-05-16  |  24.5 KB  |  644 lines

  1. unit unHttpServer;
  2.  
  3. {
  4.   Xceed Winsock Library Sample: HTTP Server
  5.   Copyright (c) 2000 Xceed Software Inc.
  6.  
  7.   This is a very basic implementation of an HTTP server. It
  8.   only handles the "GET" HTTP command. When a "GET" command
  9.   is received from a client, the server will send the requested
  10.   file to the client. The path of the "GET" request is relative
  11.   to the server EXE file.
  12.  
  13.   This sample demonstrates how to use a listening socket to
  14.   wait and accept incoming client connections, and how to use
  15.   string and file transfer methods.
  16.  
  17.   It also shows how to receive dispatch events from the event objects, using
  18.   the .PAS files you can find under the "Include" subfolder of the
  19.   Xceed Winsock Library's installation folder.
  20.  
  21.   This file is part of the Xceed Winsock Library Samples.
  22.   The source code in this file is only intended as a supplement
  23.   to Xceed Winsock Library's documentation, and is provided "as is",
  24.   without warranty of any kind, either expressed or implied.
  25. }
  26.  
  27. interface
  28.  
  29. uses
  30.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  31.   StdCtrls, XCEEDWINSOCKlib_TLB,
  32.   { These files are distributed with the Xceed Winsock Library, and are used
  33.     to receive dispatch events triggered by the event objects. The other way
  34.     to receive events involves implementing the IaXWXxxEvents interfaces, but
  35.     this results in slightly different parameter types that can confuse
  36.     someone not used to playing with the many interfaces of a COM object. }
  37.   xwlIncomingConnectionEvents,
  38.   xwlConnectionEvents,
  39.   xwlStringTransferEvents,
  40.   xwlFileTransferEvents;
  41.  
  42. type
  43.   { This class will hold each HTTP request, since these reuqests may not be
  44.     received in a single paquet. }
  45.  
  46.   PHttpRequest = ^THttpRequest;
  47.   THttpRequest = record
  48.     m_sRequest : WideString;
  49.     m_xConnection : ConnectionOrientedSocket;
  50.   end;
  51.  
  52.   { This is our main form }
  53.  
  54.   TfrmMain = class( TForm, 
  55.                     { The following interfaces are declared in the above
  56.                       mentionned files. We need to implement these interfaces
  57.                       to receive events. }
  58.                     IIncomingConnectionEvents,
  59.                     IConnectionEvents,
  60.                     IStringTransferEvents,
  61.                     IFileTransferEvents )
  62.     { Controls on the form }
  63.     Label1           : TLabel;
  64.     lstClients       : TListBox;
  65.     Label2           : TLabel;
  66.     lstLog           : TListBox;
  67.     Label3           : TLabel;
  68.     txtPort          : TEdit;
  69.     btStartListening : TButton;
  70.     btStopListening  : TButton;
  71.     lblStatus        : TLabel;
  72.     lblConnections   : TLabel;
  73.  
  74.     { Standard events }
  75.     procedure btStartListeningClick(Sender: TObject);
  76.     procedure btStopListeningClick(Sender: TObject);
  77.     procedure FormCreate(Sender: TObject);
  78.  
  79.     { IIncomingConnectionEvents }
  80.     procedure OnConnection( const xListeningSocket : IDispatch;
  81.                             const xRemoteAddress : IDispatch;
  82.                             vaCallerData : OleVariant;
  83.                             lExpectedCalleeDataSize : Integer;
  84.                             var vaCalleeData : OleVariant;
  85.                             var xQualityOfService : IdXWQualityOfServiceInfo;
  86.                             var lUserParam : Integer;
  87.                             var bReject : WordBool );
  88.     procedure OnConnectionProcessed( const xListeningSocket : IDispatch;
  89.                                      const xIncomingSocket : IDispatch;
  90.                                      lUserParam : Integer );
  91.     procedure OnListeningError( const xListeningSocket : IDispatch;
  92.                                 lUserParam: Integer;
  93.                                 lResultCode: Integer );
  94.  
  95.     { IConnectionEvents }
  96.     procedure OnDisconnected( const xSocket : IDispatch;
  97.                               vaCallerData : OleVariant;
  98.                               var vaCalleeData : OleVariant );
  99.  
  100.     { IStringTransferEvents }
  101.     procedure OnStringSent( const xSocket : IDispatch;
  102.                             lUserParam : Integer;
  103.                             lResultCode : Integer );
  104.     procedure OnStringReceived( const xSocket : IDispatch;
  105.                                 const sString : WideString;
  106.                                 lUserParam : Integer;
  107.                                 lResultCode: Integer );
  108.     procedure OnStringAvailable( const xSocket : IDispatch;
  109.                                  lCharsReceived : Integer;
  110.                                  lCharsAvailable : Integer );
  111.     procedure OnOutOfBandStringReceived( const xSocket: IDispatch;
  112.                                          const sString: WideString;
  113.                                          lResultCode: Integer );
  114.  
  115.     { IFileTransferEvents }
  116.     procedure OnFileSent( const xSocket : IDispatch;
  117.                           const sFilename : WideString;
  118.                           lStartOffset : Integer;
  119.                           lBytesSent : Integer;
  120.                           lBytesTotal : Integer;
  121.                           lUserParam : Integer;
  122.                           bTransferCompleted : WordBool;
  123.                           lResultCode: Integer );
  124.     procedure OnFileReceived( const xSocket : IDispatch;
  125.                               const sFilename : WideString;
  126.                               lStartOffset : Integer;
  127.                               lBytesReceived : Integer;
  128.                               lBytesTotal : Integer;
  129.                               lUserParam : Integer;
  130.                               bTransferCompleted : WordBool;
  131.                               lResultCode : Integer );
  132.     procedure FormDestroy(Sender: TObject);
  133.   private
  134.     { This member will keep a list of THttpRequest objects, holding requests
  135.       from each connection. We must buffer requests like this since we are not
  136.       guaranteed to receive the HTTP request in one shot. }
  137.  
  138.     m_lstRequests : TList;
  139.  
  140.     { These objects are implemented in the above included files to help you
  141.       receive events throught the dispatch interface. }
  142.  
  143.     m_xIncomingConnectionEvents : TIncomingConnectionEvents;
  144.     m_xConnectionEvents         : TConnectionEvents;
  145.     m_xStringTransferEvents     : TStringTransferEvents;
  146.     m_xFileTransferEvents       : TFileTransferEvents;
  147.  
  148.     { And their associated cookie! }
  149.  
  150.     m_lConnectionCookie     : LongInt;
  151.     m_lStringTransferCookie : LongInt;
  152.     m_lFileTransferCookie   : LongInt;
  153.  
  154.     { Socket used to accept incoming connections. It is held in a form member
  155.       variable because it needs to stay "alive" as long as we want to be
  156.       accepting incoming connections.}
  157.  
  158.     m_xListeningSocket : ListeningSocket;
  159.  
  160.     { Number of connected clients }
  161.     
  162.     m_nClientsCount : Integer;
  163.   public
  164.   end;
  165.  
  166.   { Some global functions for use with THttpRequest items }
  167.   
  168.   procedure AppendRequestString( pItem : PHttpRequest; 
  169.                                  sRequestString : WideString );
  170.   function IsRequestComplete( pItem : PHttpRequest ) : Boolean;
  171.   function GetRelativeFilename( pItem : PHttpRequest ) : WideString;
  172.   function GetAbsoluteFilename( pItem : PHttpRequest ) : WideString;
  173.   
  174. var
  175.   frmMain: TfrmMain;
  176.  
  177. implementation
  178.  
  179. {$R *.DFM}
  180.  
  181. {------------------------------------------------------------------------------}
  182. {              Global procedures for use with THttpRequest items               }
  183. {------------------------------------------------------------------------------}
  184.  
  185. { AppendRequestString: Add a string to the complete HTTP request currently
  186.                        buffered. }
  187.  
  188. procedure AppendRequestString( pItem : PHttpRequest; sRequestString : WideString );
  189. begin
  190.   pItem^.m_sRequest := pItem^.m_sRequest + sRequestString;
  191. end;
  192.  
  193. {------------------------------------------------------------------------------}
  194. { IsRequestCompleted: Tells if all the request is received from the client, by
  195.                       checking for a double linefeed at the end. }
  196.                       
  197. function IsRequestComplete( pItem : PHttpRequest ) : Boolean;
  198. begin
  199.   IsRequestComplete := ( Copy( pItem^.m_sRequest, Length( pItem^.m_sRequest ) - 3, 4)
  200.                        = (#13#10 + #13#10) );
  201. end;
  202.  
  203. {------------------------------------------------------------------------------}
  204. { GetRelativeFilename: Get the filename to asked by the client relative to the
  205.                        root of the web site. }
  206.  
  207. function GetRelativeFilename( pItem : PHttpRequest ) : WideString;
  208. var
  209.   nGetEnd       : Integer;
  210.   sRelativeName : WideString;
  211.   nSlashPos     : Integer;
  212.   sTemp         : WideString;
  213. begin
  214.   GetRelativeFilename := '';
  215.  
  216.   if IsRequestComplete( pItem ) then
  217.   begin
  218.     if Copy( pItem^.m_sRequest, 1, 4 ) = 'GET ' then
  219.     begin
  220.       sTemp := Copy( pItem^.m_sRequest, 5, Length( pItem^.m_sRequest ) - 4 );
  221.       nGetEnd := Pos( ' ', sTemp );
  222.       sRelativeName := Copy( sTemp, 1, nGetEnd - 1 );
  223.  
  224.       if sRelativeName = '/' then
  225.         sRelativeName := '/index.html';
  226.  
  227.       repeat
  228.         nSlashPos := Pos( '/', sRelativeName );
  229.         if nSlashPos > 0 then
  230.           sRelativeName[nSlashPos] := '\';
  231.       until nSlashPos = 0;
  232.  
  233.       GetRelativeFilename := sRelativeName;
  234.     end;
  235.   end;
  236. end;
  237.  
  238. {------------------------------------------------------------------------------}
  239. { GetAbsoluteFilename: Retrieve the relative filename and prepend our local
  240.                        test web site path. }
  241.  
  242. function GetAbsoluteFileName( pItem : PHttpRequest ) : WideString;
  243. var
  244.   sRelativeName : WideString;
  245. begin
  246.   sRelativeName := GetRelativeFilename( pItem );
  247.  
  248.   if Length( sRelativeName ) > 0 then
  249.     sRelativeName := ExtractFilePath( Application.ExeName ) + 'SampleSite' + sRelativeName;
  250.  
  251.   GetAbsoluteFilename := sRelativeName;
  252. end;
  253.  
  254. {------------------------------------------------------------------------------}
  255. {                      Implementation for class TfrmMain                       }
  256. {------------------------------------------------------------------------------}
  257.  
  258. { btStartListeningClick: We create the listening socket using the proper
  259.                          protocol and local address, and enter the "listening"
  260.                          state, in which the socket will be ready to accept
  261.                          incoming client connections. }
  262.  
  263. procedure TfrmMain.btStartListeningClick(Sender: TObject);
  264. var
  265.   xProtocols     : Protocols;
  266.   xProtocolTCP   : Protocol;
  267.   xSocketFactory : SocketFactory;
  268.   xListenAddress : InetAddress;
  269.   xAddress       : Address;
  270. begin
  271.   btStartListening.Enabled := False;
  272.   txtPort.Enabled := False;
  273.  
  274.   lstLog.Items.Add('Creating listening socket...');
  275.  
  276.   { The SocketFactory requires a Protocol to initialize the new socket with.
  277.     We obtain the required Protocol by using the Protocols collection,
  278.     and asking for a specific protocol. We could also have used For-Each to
  279.     iterate through the Protocols collection and find our protocol. }
  280.  
  281.   xProtocols := CoProtocols.Create;
  282.   xProtocolTCP := xProtocols.GetProtocol(wafInet, wstStream, wptIP_TCP);
  283.  
  284.   { Create the listening socket, using a SocketFactory object. }
  285.  
  286.   xSocketFactory := CoSocketFactory.Create;
  287.  
  288.   m_xListeningSocket := xSocketFactory.CreateListeningSocket(xProtocolTCP, 0);
  289.  
  290.   { Provide our event object instances to the listening socket. Those event
  291.     objects will be used by all connected client sockets. The cookies are kept
  292.     to do proper cleanup (Unadvise) when the listening socket will be freed. }
  293.  
  294.   m_lConnectionCookie := m_xListeningSocket.ConnectionAdvise(
  295.                                             m_xConnectionEvents.m_xEventObject,
  296.                                             wcaAdviseDisconnected);
  297.  
  298.   m_lStringTransferCookie := m_xListeningSocket.StringTransferAdvise(
  299.                                         m_xStringTransferEvents.m_xEventObject,
  300.                                         wsaAdviseReceivedAlways,
  301.                                         wnfAnsiStrings);
  302.  
  303.   m_lFileTransferCookie := m_xListeningSocket.FileTransferAdvise(
  304.                                           m_xFileTransferEvents.m_xEventObject,
  305.                                           wfaAdviseFileSentCompleted);
  306.  
  307.   { Create the InetAddress object for the address on which the listening socket
  308.     will wait for incoming connections. We only need to set the port on which
  309.     we want to listen. }
  310.  
  311.   xListenAddress := CoInetAddress.Create;
  312.   xListenAddress.Port := StrToInt(txtPort.text);
  313.  
  314.   { Enter the "listening" state. We provide the address on which we want to
  315.     listen, and the event object that will be used to trigger incoming
  316.     connection events. }
  317.  
  318.   lstLog.Items.Add('Starting to listen...');
  319.  
  320.   m_xListeningSocket.StartListening(xListenAddress,
  321.                                     m_xIncomingConnectionEvents.m_xEventObject,
  322.                                     wifAdviseConnectionProcessed);
  323.  
  324.   xAddress := m_xListeningSocket.LocalAddress As IdXWAddress;
  325.  
  326.   lstLog.Items.Add('Listening on ' + xAddress.GetAddressString());
  327.   lblStatus.Caption := 'Listening on ' + xAddress.GetAddressString();
  328.  
  329.   btStopListening.Enabled := True;
  330. end;
  331.  
  332. {------------------------------------------------------------------------------}
  333. { btStopListeningClick: Stop accepting incoming client connections. }
  334.  
  335. procedure TfrmMain.btStopListeningClick(Sender: TObject);
  336. begin
  337.   btStopListening.Enabled := False;
  338.   lstLog.Items.Add('Stop listening...');
  339.  
  340.   { Stop listening, and free the listening socket object. }
  341.  
  342.   m_xListeningSocket.StopListening;
  343.   m_xListeningSocket.ConnectionUnadvise(m_lConnectionCookie);
  344.   m_xListeningSocket.StringTransferUnadvise(m_lStringTransferCookie);
  345.   m_xListeningSocket.FileTransferUnadvise(m_lFileTransferCookie);
  346.  
  347.   m_xListeningSocket := Nil;
  348.  
  349.   m_lConnectionCookie := 0;
  350.   m_lStringTransferCookie := 0;
  351.   m_lFileTransferCookie := 0;
  352.  
  353.   m_nClientsCount := 0;
  354.  
  355.   lblStatus.Caption := 'Not listening';
  356.   btStartListening.Enabled := True;
  357.   txtPort.Enabled := True;
  358.  
  359.   lstLog.Items.Add('Stopped listening.');
  360. end;
  361.  
  362. {------------------------------------------------------------------------------}
  363. { FormCreate: We create each object we need. }
  364.  
  365. procedure TfrmMain.FormCreate(Sender: TObject);
  366. begin
  367.   { Create the event handler classes. }
  368.  
  369.   m_xIncomingConnectionEvents := TIncomingConnectionEvents.Create( Self );
  370.   m_xConnectionEvents := TConnectionEvents.Create( Self );
  371.   m_xStringTransferEvents := TStringTransferEvents.Create( Self );
  372.   m_xFileTransferEvents := TFileTransferEvents.Create( Self );
  373.  
  374.   { Create the list that will hold THttpRequest items }
  375.  
  376.   m_lstRequests := TList.Create;
  377.  
  378.   { Reset other members }
  379.  
  380.   m_lConnectionCookie := 0;
  381.   m_lStringTransferCookie := 0;
  382.   m_lFileTransferCookie := 0;
  383.  
  384.   m_nClientsCount := 0;
  385. end;
  386.  
  387. {------------------------------------------------------------------------------}
  388. { FormDestroy: The form is being destroyed, we free each instance. }
  389.  
  390. procedure TfrmMain.FormDestroy(Sender: TObject);
  391. var
  392.   pItem : PHttpRequest;
  393. begin
  394.   m_xListeningSocket := Nil;
  395.  
  396.   while m_lstRequests.Count > 0 do
  397.   begin
  398.     pItem := m_lstRequests.Items[0];
  399.     m_lstRequests.Remove( pItem );
  400.     Dispose( pItem );
  401.   end;
  402.  
  403.   m_xIncomingConnectionEvents.Free;
  404.   m_xConnectionEvents.Free;
  405.   m_xStringTransferEvents.Free;
  406.   m_xFileTransferEvents.Free;
  407. end;
  408.  
  409. {------------------------------------------------------------------------------}
  410. { OnConnection: Triggered when a connection is about to be made with a client. }
  411.  
  412. procedure TfrmMain.OnConnection( const xListeningSocket : IDispatch;
  413.                                  const xRemoteAddress : IDispatch;
  414.                                  vaCallerData : OleVariant;
  415.                                  lExpectedCalleeDataSize : Integer;
  416.                                  var vaCalleeData : OleVariant;
  417.                                  var xQualityOfService : IdXWQualityOfServiceInfo;
  418.                                  var lUserParam : Integer;
  419.                                  var bReject : WordBool );
  420. begin
  421.   { We ignore this event. bReject is always false by default. }
  422. end;
  423.  
  424. {------------------------------------------------------------------------------}
  425. { OnConnectionProcessed: Triggered when a new connection was successfully made
  426.                          with a client. }
  427.  
  428. procedure TfrmMain.OnConnectionProcessed( const xListeningSocket : IDispatch;
  429.                                           const xIncomingSocket : IDispatch;
  430.                                           lUserParam : Integer );
  431. var
  432.   xClientSocket : ConnectionOrientedSocket;
  433.   xAddress      : Address;
  434. begin
  435.   { The xIncomingSocket parameter is the connection-oriented socket that is
  436.     associated with this new connected client. Assigning it to a typed
  437.     ConnectionOrientedSocket variable makes it easier to use. }
  438.  
  439.   xClientSocket := xIncomingSocket As ConnectionOrientedSocket;
  440.   xAddress := xClientSocket.RemoteAddress As Address;
  441.  
  442.   { Update information displayed on the form. }
  443.  
  444.   lstLog.Items.Add( 'Client connected: ' + xAddress.GetAddressString );
  445.   lstClients.Items.Add( xAddress.GetAddressString );
  446.  
  447.   m_nClientsCount := m_nClientsCount + 1;
  448.   lblConnections.Caption := IntToStr( m_nClientsCount ) + ' connected clients';
  449. end;
  450.  
  451. {------------------------------------------------------------------------------}
  452. { OnListeningError: Triggered when an error occurs while waiting for incoming
  453.                     connections. }
  454.                     
  455. procedure TfrmMain.OnListeningError( const xListeningSocket : IDispatch;
  456.                                      lUserParam: Integer;
  457.                                      lResultCode: Integer );
  458. begin
  459.   { We ignore this event. }
  460. end;
  461.  
  462. {------------------------------------------------------------------------------}
  463. { OnDisconnected: Event triggered when a client socket has disconnected. We
  464.                   remove this connection from our list of pending requests. }
  465.  
  466. procedure TfrmMain.OnDisconnected( const xSocket : IDispatch;
  467.                                    vaCallerData : OleVariant;
  468.                                    var vaCalleeData : OleVariant );
  469. var
  470.   xClientSocket : ConnectionOrientedSocket;
  471.   xAddress      : Address;
  472.   i             : Integer;
  473.   pItem         : PHttpRequest;
  474. begin
  475.   { The xSocket parameter is the connection-oriented socket that disconnected.
  476.     Assigning it to a typed ConnectionOrientedSocket variable makes it easier
  477.     to use. }
  478.  
  479.   xClientSocket := xSocket As ConnectionOrientedSocket;
  480.   xAddress      := xClientSocket.RemoteAddress As Address;
  481.  
  482.   lstLog.Items.Add('Client disconnected: ' + xAddress.GetAddressString);
  483.  
  484.   { Locate the client's address in the list of connected clients, and remove it. }
  485.  
  486.   For i := 0 To lstClients.Items.Count - 1 do
  487.     If lstClients.Items[i] = xAddress.GetAddressString Then
  488.     begin
  489.       lstClients.Items.Delete(i);
  490.       break;
  491.     end;
  492.  
  493.   { Locate the connection-oriented socket in the list of resquests and remove it. }
  494.  
  495.   For i := 0 To m_lstRequests.Count - 1 do
  496.   begin
  497.     pItem := PHttpRequest( m_lstRequests.Items[i] );
  498.     if xSocket As IUnknown = pItem^.m_xConnection As IUnknown then
  499.     begin
  500.       m_lstRequests.Remove( pItem );
  501.       Dispose( pItem );
  502.       break;
  503.     end;
  504.   end;
  505.  
  506.   m_nClientsCount := m_nClientsCount - 1;
  507.   lblConnections.Caption := IntToStr( m_nClientsCount) + ' connected clients';
  508. end;
  509.  
  510. {------------------------------------------------------------------------------}
  511. { OnStringSent: Triggered when a call to AsyncSendString completes. }
  512.  
  513. procedure TfrmMain.OnStringSent( const xSocket : IDispatch;
  514.                                  lUserParam : Integer;
  515.                                  lResultCode : Integer );
  516. begin
  517.   { We ignore this event. }
  518. end;
  519.  
  520. {------------------------------------------------------------------------------}
  521. { OnStringReceived: Triggered when a call to AsyncReceiveString or
  522.                     AsyncReceiveLine completed, or when you advised to receive
  523.                     all data as it arrives on the wire. This is where we
  524.                     receive HTTP requests. Remember that they may not be
  525.                     complete. }
  526.  
  527. procedure TfrmMain.OnStringReceived( const xSocket : IDispatch;
  528.                                      const sString : WideString;
  529.                                      lUserParam : Integer;
  530.                                      lResultCode: Integer );
  531. var
  532.   xClientSocket : ConnectionOrientedSocket;
  533.   i             : Integer;
  534.   pItem         : PHttpRequest;
  535.   xAddress      : Address;
  536. begin
  537.   { The xSocket parameter is the connection-oriented socket that is associated
  538.     with this connected client. Assigning it to a typed ConnectionOrientedSocket
  539.     variable makes it easier to use. }
  540.  
  541.   xClientSocket := xSocket As ConnectionOrientedSocket;
  542.  
  543.   pItem := Nil;
  544.  
  545.   for i := 0 to m_lstRequests.Count - 1 do
  546.   begin
  547.     pItem := m_lstRequests.Items[i];
  548.  
  549.     if pItem^.m_xConnection As IUnknown = xSocket As IUnknown then
  550.       break;
  551.  
  552.     pItem := Nil;
  553.   end;
  554.  
  555.   If not Assigned( pItem ) Then
  556.   begin
  557.     { Create a new THttpRequest }
  558.     New( pItem );
  559.     pItem^.m_xConnection  := xClientSocket;
  560.     m_lstRequests.Add( pItem );
  561.   end;
  562.  
  563.   AppendRequestString( pItem, sString );
  564.  
  565.   if IsRequestComplete( pItem ) then
  566.   begin
  567.     xAddress := xClientSocket.RemoteAddress As Address;
  568.     lstLog.Items.Add( 'HTTP request received from client ' + xAddress.GetAddressString );
  569.     lstLog.Items.Add( '  --> ' + pItem^.m_sRequest );
  570.  
  571.     lstLog.Items.Add( 'Sending file ' + GetRelativeFilename( pItem ) + ' to ' + xAddress.GetAddressString );
  572.     xClientSocket.AsyncSendFile( GetAbsoluteFilename( pItem ), 0, 0, 0 );
  573.   end;
  574. end;
  575.  
  576. {------------------------------------------------------------------------------}
  577. { OnStringAvailable: Triggered when new data is available in the library's
  578.                      internal buffers. }
  579.  
  580. procedure TfrmMain.OnStringAvailable( const xSocket : IDispatch;
  581.                                       lCharsReceived : Integer;
  582.                                       lCharsAvailable : Integer );
  583. begin
  584.   { We ignore this event. }
  585. end;
  586.  
  587. {------------------------------------------------------------------------------}
  588. { OnOutOfBandStringReceived: Triggered when out-of-band data is received and
  589.                              advised to receive such data with the
  590.                              wsaAdviseOutOfBandReceivedAlways flag. }
  591.  
  592. procedure TfrmMain.OnOutOfBandStringReceived( const xSocket: IDispatch;
  593.                                               const sString: WideString;
  594.                                               lResultCode: Integer );
  595. begin
  596.   { We ignore this event. }
  597. end;
  598.  
  599. {------------------------------------------------------------------------------}
  600. { OnFileSent: Triggered when a portion of a file, or all the file was sent,
  601.               depending if you advised to receive this event only when the
  602.               file is completely sent. }
  603.  
  604. procedure TfrmMain.OnFileSent( const xSocket : IDispatch;
  605.                                const sFilename : WideString;
  606.                                lStartOffset : Integer;
  607.                                lBytesSent : Integer;
  608.                                lBytesTotal : Integer;
  609.                                lUserParam : Integer;
  610.                                bTransferCompleted : WordBool;
  611.                                lResultCode: Integer );
  612. begin
  613.   if bTransferCompleted then
  614.   begin
  615.     { The xSocket parameter is the connection-oriented socket that is associated
  616.       with this connected client. Assigning it to a typed ConnectionOrientedSocket
  617.       variable makes it easier to use. }
  618.  
  619.     { When we're done sending the file, we disconnect.}
  620.  
  621.     ( xSocket As ConnectionOrientedSocket ).Disconnect;
  622.   end;
  623. end;
  624.  
  625. {------------------------------------------------------------------------------}
  626. { OnFileReceived: Triggered when a portion of a file, or all the file was
  627.                   received, depending if you advised to receive this event only
  628.                   when the file is completely received. }
  629.                   
  630. procedure TfrmMain.OnFileReceived( const xSocket : IDispatch;
  631.                                    const sFilename : WideString;
  632.                                    lStartOffset : Integer;
  633.                                    lBytesReceived : Integer;
  634.                                    lBytesTotal : Integer;
  635.                                    lUserParam : Integer;
  636.                                    bTransferCompleted : WordBool;
  637.                                    lResultCode : Integer );
  638. begin
  639.   { We ignore this event. }
  640. end;
  641.  
  642. end.
  643.  
  644.