Pregunta

Estoy trabajando en la creación de un EXE ActiveX usando VB6 y el único ejemplo que obtuve está escrito en Delphi.

Al leer el código de ejemplo, noté que hay algunas funciones cuyas firmas van seguidas del llamada segura palabra clave.He aquí un ejemplo:

function AddSymbol(ASymbol: OleVariant): WordBool; safecall;

¿Cuál es el propósito de esta palabra clave?

¿Fue útil?

Solución

Safecall pasa parámetros de derecha a izquierda, en lugar del pascal o registro (predeterminado) de izquierda a derecha

Con safecall, el procedimiento o función elimina parámetros de la pila al regresar (como pascal, pero no como cdecl, donde depende de la persona que llama)

Safecall implementa 'cortafuegos' de excepción;Especialmente en Win32, esto implementa la notificación de errores COM entre procesos.De lo contrario, sería idéntico a stdcall (la otra convención de llamada utilizada con win api)

Otros consejos

Además, los cortafuegos de excepciones funcionan llamando a SetErrorInfo() con un objeto que admita IErrorInfo, de modo que quien llama pueda obtener información ampliada sobre la excepción.Esto se realiza mediante la anulación de TObject.SafeCallException tanto en TComObject como en TAutoIntfObject.Ambos tipos también implementan ISuportErrorInfo para marcar este hecho.

En caso de una excepción, la persona que llama al método de llamada segura puede consultar ISupportErrorInfo, luego consultar eso para la interfaz cuyo método resultó en una falla HRESULT (conjunto de bits alto), y si eso devuelve S_OK, Obtener información de error() puede obtener la información de la excepción (descripción, ayuda, etc., en forma de implementación de IErrorInfo que se pasó a Establecer información de error() por Delphi RTL en las anulaciones de SafeCallException).

Lo que dijo Francois y si no fuera por la llamada segura, la llamada al método COM se habría visto como se muestra a continuación y tendría que realizar su propia verificación de errores en lugar de obtener excepciones.

function AddSymbol(ASymbol: OleVariant; out Result: WordBool): HResult; stdcall;

En COM, cada método es una función que devuelve un HRESULT:

IThingy = interface
   ['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
   function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
end;

Esta es una regla absoluta en COM:

  • no hay excepciones en COM
  • todo devuelve un HRESULT
  • HRESULT negativo indica una falla
  • en lenguajes de nivel superior, las fallas se asignan a excepciones

La intención de los diseñadores de COM era que los idiomas de nivel superior se tradujeran automáticamente Fallido métodos en una excepción.

Entonces, en su propio idioma, la invocación COM se representaría sin HRESULT.P.ej.:

  • tipo Delfos: function AddSymbol(ASymbol: OleVariant): WordBool;
  • tipo C#: WordBool AddSymbol(OleVariant ASymbol);

En Delphi puede optar por utilizar la firma de función sin formato:

IThingy = interface
   ['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
   function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
end;

Y maneje usted mismo la generación de excepciones:

bAdded: WordBool;
thingy: IThingy;
hr: HRESULT;

hr := thingy.AddSymbol('Seven', {out}bAdded);
if Failed(hr) then
    OleError(hr);

o el equivalente más corto:

bAdded: WordBool;
thingy: IThingy;
hr: HRESULT;

hr := thingy.AddSymbol('Seven', {out}bAdded);
OleCheck(hr);

o el equivalente más corto:

bAdded: WordBool;
thingy: IThingy;

OleCheck(thingy.AddSymbol('Seven'), {out}bAdded);

COM no tenía la intención de que usted tratara con HRESULT

Pero puedes pedirle a Delphi que te oculte esas tuberías para que puedas continuar con la programación:

IThingy = interface
   ['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
   function AddSymbol(ASymbol: OleVariant): WordBool); safecall;
end;

Detrás de escena, el compilador aún verificará el retorno HRESULT y arrojará un EOleSysError excepción si el HRESULT indicó una falla (es decir,fue negativo).El compilador generado llamada segura La versión es funcionalmente equivalente a:

function AddSymbol(ASymbol: OleVariant): WordBool; safecall;
var
   hr: HRESULT;
begin
   hr := AddSymbol(ASymbol, {out}Result);
   OleCheck(hr);
end;

Pero te libera para simplemente llamar:

bAdded: WordBool;
thingy: IThingy;

bAdded := thingy.AddSymbol('Seven');

tl;dr:Puedes usar cualquiera de las dos:

function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
function AddSymbol(ASymbol: OleVariant): WordBool; safecall;

Pero el primero requiere que usted maneje los HRESULT cada vez.

Charla adicional

Casi nunca querrás manejar los HRESULT tú mismo;satura el programa con ruido que no aporta nada.Pero a veces es posible que desee comprobar el HRESULT usted mismo (p. ej.quiere gestionar un fallo que no es muy excepcional).Nunca las versiones de Delphi han incluido interfaces de encabezado de Windows traducidas que se declaran en ambos sentidos:

IThingy = interface
   ['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
   function AddSymbol(ASymbol: OleVariant; out RetValue: WordBool): HRESULT; stdcall;
end;

IThingySC = interface
   ['{357D8D61-0504-446F-BE13-4A3BBE699B05}']
   function AddSymbol(ASymbol: OleVariant): WordBool); safecall;
end;

o de la fuente RTL:

  ITransaction = interface(IUnknown)
    ['{0FB15084-AF41-11CE-BD2B-204C4F4F5020}']
    function Commit(fRetaining: BOOL; grfTC: UINT; grfRM: UINT): HResult; stdcall;
    function Abort(pboidReason: PBOID; fRetaining: BOOL; fAsync: BOOL): HResult; stdcall;
    function GetTransactionInfo(out pinfo: XACTTRANSINFO): HResult; stdcall;
  end;

  { Safecall Version }
  ITransactionSC = interface(IUnknown)
    ['{0FB15084-AF41-11CE-BD2B-204C4F4F5020}']
    procedure Commit(fRetaining: BOOL; grfTC: UINT; grfRM: UINT); safecall;
    procedure Abort(pboidReason: PBOID; fRetaining: BOOL; fAsync: BOOL); safecall;
    procedure GetTransactionInfo(out pinfo: XACTTRANSINFO); safecall;
  end;

El CAROLINA DEL SUR el sufijo significa llamada segura.Ambas interfaces son equivalentes y puede elegir cuál declarar su variable COM según su deseo:

//thingy: IThingy;
thingy: IThingySC;

Incluso puedes transmitir entre ellos:

thingy: IThingSC;
bAdded: WordBool;

thingy := CreateOleObject('Supercool.Thingy') as TThingySC;

if Failed(IThingy(thingy).AddSymbol('Seven', {out}bAdded) then
begin
   //Couldn't seven? No sixty-nine for you
   thingy.SubtractSymbol('Sixty-nine');
end;

Charla extra adicional - C#

C# por defecto hace el equivalente a Delphi llamada segura, excepto en C#:

  • tienes que optar por no participar en el mapeo de llamadas seguras
  • en lugar de optar por

En C# declararías tu interfaz COM como:

[ComImport]
[Guid("{357D8D61-0504-446F-BE13-4A3BBE699B05}")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IThingy
{
   WordBool AddSymbol(OleVariant ASymbol);
   WordBool SubtractSymbol(OleVariant ASymbol);
}

Notarás que el COM HRESULT está oculto para ti.El compilador de C#, al igual que el compilador de Delphi, verificará automáticamente el HRESULT devuelto y generará una excepción.

Y en C#, como en Delphi, puedes elegir manejar los HRESULT tú mismo:

[ComImport]
[Guid("{357D8D61-0504-446F-BE13-4A3BBE699B05}")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IThingy
{
   [PreserveSig]
   HRESULT AddSymbol(OleVariant ASymbol, out WordBool RetValue);

   WordBool SubtractSymbol(OleVariant ASymbol);
}

El [PreservarSig] le dice al compilador que conserve la firma del método exactamente como está:

Indica si los métodos no administrados que tienen HRESULTADO o recuperación los valores de retorno se traducen directamente o si HRESULTADO o recuperación los valores de retorno se convierten automáticamente en excepciones.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top