I'm working on the creation of an ActiveX EXE using VB6, and the only example I got is all written in Delphi.
Reading the example code, I noticed there are some functions whose signatures are followed by the safecall keyword. Here's an example:
function AddSymbol(ASymbol: OleVariant): WordBool; safecall;
What is the purpose of this keyword?
In COM, every method is a function that returns an
HRESULT
:This is an absolute rule in COM:
It was the intention of the COM designers that higher level languages would automatically translate Failed methods into an exception.
So in your own language, the COM invocation would be represented without the HRESULT. E.g.:
function AddSymbol(ASymbol: OleVariant): WordBool;
WordBool AddSymbol(OleVariant ASymbol);
In Delphi you can choose to use the raw function signature:
And handle the raising of exceptions yourself:
or the shorter equivalent:
or the shorter equivalent:
COM didn't intend for you to deal with HRESULTs
But you can ask Delphi to hide that plumbing away from you, so you can get on with the programming:
Behind the scenes, the compiler will still check the return HRESULT, and throw an
EOleSysError
exception if the HRESULT indicated a failure (i.e. was negative). The compiler-generated safecall version is functionally equivalent to:But it frees you to simply call:
tl;dr: You can use either:
But the former requires you to handle the HRESULTs every time.
Bonus Chatter
You almost never want to handle the HRESULTs yourself; it clutters up the program with noise that adds nothing. But sometimes you might want to check the HRESULT yourself (e.g. you want to handle a failure that isn't very exceptional). Never versions of Delphi have starting included translated Windows header interfaces that are declared both ways:
or from the RTL source:
The SC suffix stands for safecall. Both interfaces are equivalent, and you can choose which to declare your COM variable as depending on your desire:
You can even cast between them:
Extra Bonus Chatter - C#
C# by default does the equivalent of Delphi safecall, except in C#:
In C# you would declare your COM interface as:
You'll notice that the COM
HRESULT
is hidden from you. The C# compiler, like the Delphi compiler, will automatically check the returned HRESULT and throw an exception for you.And in C#, as in Delphi, you can choose to handle the HRESULTs yourself:
The [PreserveSig] tells the compiler to preserve the method signature exactly as is:
Safecall passes parameters from right to left, instead of the pascal or register (default) from left to right
With safecall, the procedure or function removes parameters from the stack upon returning (like pascal, but not like cdecl where it's up to the caller)
Safecall implements exception 'firewalls'; esp on Win32, this implements interprocess COM error notification. It would otherwise be identical to stdcall (the other calling convention used with the win api)
Additionally, the exception firewalls work by calling SetErrorInfo() with an object that supports IErrorInfo, so that the caller can get extended information about the exception. This is done by the TObject.SafeCallException override in both TComObject and TAutoIntfObject. Both of these types also implement ISupportErrorInfo to mark this fact.
In the event of an exception, the safecall method's caller can query for ISupportErrorInfo, then query that for the interface whose method resulted in a failure HRESULT (high bit set), and if that returns S_OK, GetErrorInfo() can get the exception info (description, help, etc., in the form of the IErrorInfo implementation that was passed to SetErrorInfo() by the Delphi RTL in the SafeCallException overrides).
What Francois said and if it wasn't for safecall your COM method call would have looked like below and you would have to do your own error checking instead of getting exceptions.