Frage

Ich arbeite an der Schaffung eines ActiveX-EXE-VB6, und das einzige Beispiel, das ich habe ist alles in Delphi geschrieben.

den Beispielcode zum Lesen, bemerkte ich, gibt es einige Funktionen, deren Signaturen gefolgt von dem safecall Stichwort. Hier ein Beispiel:

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

Was ist der Zweck dieses Stichwort?

War es hilfreich?

Lösung

Safecall übergibt Parameter von rechts nach links, anstelle des pascal oder registrieren (default) von links nach rechts

Mit Safecall, die Prozedur oder Funktion entfernt Parameter vom Stack bei der Rückkehr (wie pascal, aber nicht cdecl mag, wo es bis zum Anrufer)

Safecall implementiert Ausnahme 'Firewalls'; esp auf Win32, implementiert diese Inter COM Fehlermeldung. Es wäre sonst identisch sein stdcall (die anderen Aufrufkonvention mit dem Sieg api verwendet)

Andere Tipps

Außerdem ist die Ausnahme Firewalls Arbeit durch den Aufruf SetErrorInfo () mit einem Objekt, das IErrorInfo unterstützt, so dass die Anrufer erweiterten Information über die Ausnahme bekommen. Dies wird durch die TObject.SafeCallException Überschreibung erfolgt in beiden TComObject und TAutoIntfObject. Beiden Arten auch ISupportErrorInfo implementieren diese Tatsache zu kennzeichnen.

Im Falle einer Ausnahme des Anrufers Safecall-Methode kann für ISupportErrorInfo abfragen, dann die Abfrage für die Schnittstelle, deren Methode führte zu einem Fehler HRESULT (High-Bit gesetzt), und wenn das S_OK zurückgibt, GetErrorInfo () die Ausnahme info (Beschreibung, Hilfe, etc. in Form der bekommen IErrorInfo Implementierung, die übergeben wurde SetErrorInfo () von der Delphi RTL in der Safecallexception überschreibt).

Was sagte Francois und wenn es nicht für Safecall COM-Methodenaufruf ausgesehen hätte war wie unten, und Sie würden Ihre eigene Fehlerprüfung statt Ausnahmen zu bekommen.

zu tun haben,
function AddSymbol(ASymbol: OleVariant; out Result: WordBool): HResult; stdcall;

In COM, jede Methode ist eine Funktion, die eine HRESULT zurückgibt:

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

Dies ist eine absolute Regel in COM:

  • gibt es keine Ausnahmen in COM
  • alles gibt einen HRESULT
  • negativ HRESULT zeigt einen Fehler
  • in höheren Sprachen, sind Ausfälle Ausnahmen abgebildet

Es war die Absicht der COM-Designer, dass höhere Sprachen automatisch übersetzen würde fehlgeschlagen Methoden in eine Ausnahme.

So in Ihrer eigenen Sprache, der COM-Aufruf wäre ohne die HRESULT vertreten sein. Z.

  • Delphi-like : function AddSymbol(ASymbol: OleVariant): WordBool;
  • C # -ähnliche : WordBool AddSymbol(OleVariant ASymbol);

In Delphi können Sie die RAW-Funktion Signatur verwenden:

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

Und das Anheben von Ausnahmen behandeln sich selbst:

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

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

oder die kürzere äquivalent:

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

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

oder die kürzere äquivalent:

bAdded: WordBool;
thingy: IThingy;

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

COM nicht beabsichtige, für Sie mit HRESULTs

beschäftigen

Sie können aber Delphi bitten, von Ihnen die Sanitär zu verstecken, so können Sie mit der Programmierung erhalten auf:

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

Hinter den Kulissen überprüfen wird der Compiler noch die Rückkehr HRESULT und eine EOleSysError Ausnahme auslösen, wenn das HRESULT einen Fehler angezeigt (das heißt war negativ). Der Compiler generierte Safecall Version ist funktional äquivalent zu:

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

Aber es befreit Sie zu rufen Sie einfach an:

bAdded: WordBool;
thingy: IThingy;

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

tl; dr: Sie können entweder:

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

Doch die ehemalige erfordert, dass Sie die HRESULTs jedes Mal zu behandeln.

Bonus Chatter

Sie wollen so gut wie nie die HRESULTs selbst behandeln; es clutters das Programm mit Lärm, die nichts hinzufügt. Aber manchmal möchten Sie vielleicht die HRESULT überprüfen selbst (zum Beispiel Sie einen Fehler zu handhaben möchten, die nicht sehr außergewöhnlich ist). Nie Versionen von Delphi haben übersetzten Windows-Header-Schnittstellen enthält beginnend in beiden Richtungen deklariert werden:

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;

oder von der RTL Quelle:

  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;

Die SC Suffix steht für Safecall . Beide Schnittstellen sind gleichwertig, und Sie können, die vier COM-Variable zu deklarieren, wie je nach Wunsch:

//thingy: IThingy;
thingy: IThingySC;

Sie können sogar zwischen ihnen werfen:

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;

Extra Bonus Chatter - C #

C # standardmäßig tut das Äquivalent von Delphi Safecall , außer in C #:

  • Sie müssen Opt-out von Safecall-Mapping
  • statt Opt-in

In C # würden Sie die COM-Schnittstelle deklarieren:

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

Sie werden bemerken, dass die COM HRESULT vor Ihnen verborgen. Der C # -Compiler, wie der Delphi-Compiler, die zurückgegeben HRESULT automatisch überprüfen und eine Ausnahme für Sie werfen.

Und in C #, wie in Delphi, können Sie die HRESULTs zu handhaben selbst:

[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);
}

Die [PreserveSig] teilt den Compiler die Methodensignatur genau zu erhalten wie:

  

Gibt an, ob nicht verwalteten Methoden, die haben HRESULT oder Retval Rückgabewerte direkt übersetzt werden, oder ob HRESULT oder Retval Rückgabewerte werden auf Ausnahmen automatisch konvertiert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top