Name

SafeCall Directive

Syntax

Subroutine declaration; safecall;

Description

The safecall directive tells the compiler to use the safe calling convention for the function or procedure.

Like stdcall, the caller pushes the arguments onto the stack, starting with the rightmost argument. Before the subroutine returns, it pops the arguments from the stack.

If the routine is a function, Delphi passes an extra argument to store its return value. Functions and procedures are converted internally to functions that return an HResult value. If the subroutine is a method, Self and the hidden function result parameter are last, so they are pushed first onto the stack.

The compiler automatically wraps the subroutine body in an exception handler, so Delphi catches all exceptions, and the safecall method never raises an exception that is visible to the caller. If the subroutine returns normally, Delphi stores zero in the hidden HResult return value. If the safecall routine is a method that raises an exception, Delphi calls the object’s SafeCallException method to map the exception to an HResult value. If the safecall routine is a plain function or procedure, Delphi maps every exception to E_Unexpected. Schematically, calling a safecall routine looks like the following:

type
  TSomething = class
    function Divide(I, J: Integer): Integer; safecall;
  end;

// If you write Divide as follows:
function TSomething.Divide(I, J: Integer): Integer;
begin
  Result := I div J;
end;

// Delphi compiles it into something that looks like this:
function TSomething.Divide(I, J: Integer; var Rtn: Integer): HResult;
begin
  try
    Rtn := I div J;
    Result := S_OK;
  except
    Result := Self.SafeCallException(ExceptObject, ExceptAddr);
  end;
end;

The compiler generates the subroutine call using the stdcall calling convention, and also checks the HResult that the function returns. If the status indicates an error, Delphi calls the procedure stored in SafeCallErrorProc. In other words, calling a safecall routine looks like the following:

// If you write this:
X := Something.Divide(10, 2);

// Delphi actually calls the method this way:
ErrorCode := Something.Divide(X, 10, 2));
if Failed(ErrorCode) then
begin
  if SafeCallErrorProc <> nil then
    SafeCallErrorProc(ErrorCode, EIP); // EIP=instruction pointer
  ReportError(24);
end;

Tips and Tricks

  • You must use safecall for dual-dispatch interfaces.

  • Delphi takes care of the safe calling automatically, so you don’t usually need to concern yourself with the details. Write the safecall method the way you would any other method.

See Also

CDecl Directive, Function Keyword, Interface Keyword, Pascal Directive, Procedure Keyword, Register Directive, SafeCallErrorProc Variable, StdCall Directive
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset