- - * - WhiteUnicorn - * - -




* #WhiteUnicorn/ StartPage/ Documentation/DelphiFAQ >


TI3331 - Handling Winsock Errors



For any of the following exception handling methods to work,
the VCL must in some way become aware that an error condition
exists.  If a call to the Winsock does not return, or does
not provide information to the TCustomWinSocket descendant
that called it, then there is no mechanism to handle the condition.  
OnError exception handler 

One method for trapping exception conditions in a descendant of
TCustomWinSocket is to use an OnError exception handler.   This
method will only handle a limited set of conditions because the
mechanism provided by the Winsock for event notification only
reacts to a limited list of conditions.  To be notified of an
exception condition within the Winsock, TCustomWinSocket registers
user message CM_SocketMessage to be sent to the component, and the
CMSocketMessage message handler raises an exception.  The message
is registered with the Winsock by an API call to WSASyncSelect.
WSASyncSelect is a request for event notification of socket read,
writes, connect, close, and accept events.  If the exception
condition is not read, write, connect, close or accept, or if the
CM_SocketMessage is not sent by the Winsock for any reason, the
error handler will not fire.

Usage: 

procedure TChatForm.ClientSocketError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
const
  ErrorEvents: array[eeGeneral..eeAccept] of string = (
    'eeGeneral',
    'eeSend',
    'eeReceive',
    'eeConnect',
    'eeDisconnect',
    'eeAccept'
  );
begin
ListBox1.Items.Add('ClientSocketError.   TErrorEvent: ' +
  ErrorEvents[ErrorEvent] + '    ErrorCode: ' + IntToStr(ErrorCode));
  ErrorCode := 0; // don't raise an exception
end;


Definition: 

procedure TCustomWinSocket.CMSocketMessage(var Message: TCMSocketMessage);

  function CheckError: Boolean;
  var
    ErrorEvent: TErrorEvent;
    ErrorCode: Integer;
  begin
    if Message.SelectError <> 0 then
    begin
      Result := False;
      ErrorCode := Message.SelectError;
      case Message.SelectEvent of
        FD_CONNECT: ErrorEvent := eeConnect;
        FD_CLOSE: ErrorEvent := eeDisconnect;
        FD_READ: ErrorEvent := eeReceive;
        FD_WRITE: ErrorEvent := eeSend;
        FD_ACCEPT: ErrorEvent := eeAccept;
      else
        ErrorEvent := eeGeneral;
      end;
      Error(Self, ErrorEvent, ErrorCode);
       if ErrorCode <> 0 then
        raise ESocketError.CreateFmt(sASyncSocketError, [ErrorCode]);
    end else Result := True;
  end;

begin
  with Message do
    if CheckError then
      case SelectEvent of
        FD_CONNECT: Connect(Socket);
        FD_CLOSE: Disconnect(Socket);
        FD_READ: Read(Socket);
        FD_WRITE: Write(Socket);
        FD_ACCEPT: Accept(Socket);
      end;
end;


Object Pascal Exception Handling
You can also wrap a specific call in a try..except block or
setting an application level exception handler.  For this to
work, the component must in some way become aware of the
exception condition and an exception must be raised for the
exception to be trapped here.

Example of Application Exception Handler: 

TChatForm = class(TForm)
.
.
  public
    procedure AppException(Sender: TObject; E: Exception);
  end;
.
.
implementation
.
.
procedure TChatForm.AppException(Sender: TObject; E: Exception);
begin
  ListBox1.Items.Add('AppException: ' + E.Message);
end;

procedure TChatForm.FormCreate(Sender: TObject);
begin
  Application.OnException := AppException;
end;


Example of Try..Except block:

with ClientSocket do
  try
    Active := True;
  except
    on E: Exception do
      ListBox1.Items.Add('Try..except during open: ' + E.Message);
  end;
end;

SocketErrorProc 
For calls that use the CheckSocketResult function to check the
result returned by WSAGetLastError, errors can be handled in a
programmer defined function by setting the SocketErrorProc.

Usage: 

Interface
.
.
procedure MySocketError(ErrorCode: Integer);

implementation
.
.
procedure MySocketError(ErrorCode: Integer);
begin
  ShowMessage('MySocketError: ' + IntToStr(ErrorCode));
end;

procedure TChatForm.FormCreate(Sender: TObject);
begin
  SocketErrorProc := MySocketError;
end;


Defined: 

function CheckSocketResult(ResultCode: Integer; const Op: string):
 Integer;
begin
  if ResultCode <> 0 then
  begin
    Result := WSAGetLastError;
    if Result <> WSAEWOULDBLOCK then
      if Assigned(SocketErrorProc) then
        SocketErrorProc(Result)
      else raise ESocketError.CreateFmt(sWindowsSocketError,
        [SysErrorMessage(Result), Result, Op]);
  end else Result := 0;
end;


Help Text for SocketErrorProc: 

Unit ScktComp

SocketErrorProc handles error messages that are received from a Windows socket
connection.

threadvar SocketErrorProc: procedure (ErrorCode: Integer);

Description:   Assign a value to SocketErrorProc to handle error messages
from Windows socket API calls before the socket component raises an
exception. Setting SocketErrorProc prevents the socket component from
raising an exception.  SocketErrorProc is a thread-local variable. It
only handles errors that arise from the Windows socket API calls made within
a single execution thread.
Exception Handling for TCustomWinSocket Descendants




* #WhiteUnicorn/ StartPage/ Documentation/DelphiFAQ >



- - * - Anastasija aka WhiteUnicorn - * - - LJLiveJournal
PFPhotoFile