سؤال

أنا أعمل على إنشاء ActiveX EXE باستخدام VB6، والمثال الوحيد الذي حصلت عليه هو مكتوب بالكامل في دلفي.

عند قراءة رمز المثال، لاحظت أن هناك بعض الوظائف التي يتبع توقيعها ملف com.safecall الكلمة الرئيسية.هنا مثال:

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

ما هو الغرض من هذه الكلمة الرئيسية؟

هل كانت مفيدة؟

المحلول

يقوم Safecall بتمرير المعلمات من اليمين إلى اليسار، بدلاً من باسكال أو التسجيل (الافتراضي) من اليسار إلى اليمين

باستخدام Safecall، يقوم الإجراء أو الوظيفة بإزالة المعلمات من المكدس عند العودة (مثل باسكال، ولكن ليس مثل cdecl حيث يعود الأمر إلى المتصل)

تطبق Safecall استثناء "جدران الحماية"؛esp على Win32، وهذا يطبق إعلام خطأ COM بين العمليات.سيكون بخلاف ذلك مطابقًا لـ stdcall (اصطلاح الاتصال الآخر المستخدم مع win api)

نصائح أخرى

بالإضافة إلى ذلك، تعمل جدران الحماية الاستثناءية عن طريق استدعاء SetErrorInfo() بكائن يدعم IErrorInfo، بحيث يمكن للمتصل الحصول على معلومات موسعة حول الاستثناء.يتم ذلك عن طريق تجاوز TObject.SafeCallException في كل من TComObject وTAutoIntfObject.يقوم كلا النوعين أيضًا بتطبيق ISupportErrorInfo لتحديد هذه الحقيقة.

في حالة وجود استثناء، يمكن لمستدعي أسلوب Safecall الاستعلام عن ISupportErrorInfo، ثم الاستعلام عن ذلك للواجهة التي أدى أسلوبها إلى فشل HRESULT (مجموعة البت العالية)، وإذا أدى ذلك إلى إرجاع S_OK، GetErrorInfo() يمكنه الحصول على معلومات الاستثناء (الوصف، المساعدة، وما إلى ذلك)، في شكل تطبيق IErrorInfo الذي تم تمريره إلى معلومات_SetError() بواسطة دلفي RTL في تجاوزات SafeCallException).

ماذا قال فرانسوا وإذا لم يكن هناك اتصال آمن، لكان استدعاء أسلوب COM الخاص بك يبدو كما هو موضح أدناه وسيتعين عليك التحقق من الأخطاء بنفسك بدلاً من الحصول على استثناءات.

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

في COM، كل أسلوب هو دالة تقوم بإرجاع ملف HRESULT:

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

هذه قاعدة مطلقة في COM:

  • لا توجد استثناءات في COM
  • كل شيء يُرجع HRESULT
  • تشير HRESULT السلبية إلى فشل
  • في اللغات ذات المستوى الأعلى، يتم تعيين حالات الفشل إلى الاستثناءات

كان نية مصممي COM أن يتم ترجمة اللغات ذات المستوى الأعلى تلقائيًا فشل الأساليب إلى استثناء.

لذا، في لغتك الخاصة، سيتم تمثيل استدعاء COM بدون HRESULT.على سبيل المثال:

  • مثل دلفي: function AddSymbol(ASymbol: OleVariant): WordBool;
  • تشبه لغة C#: WordBool AddSymbol(OleVariant ASymbol);

في دلفي يمكنك اختيار استخدام توقيع الوظيفة الخام:

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

وتعامل مع رفع الاستثناءات بنفسك:

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

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

أو ما يعادلها أقصر:

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

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

أو ما يعادلها أقصر:

bAdded: WordBool;
thingy: IThingy;

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

COM لم يكن ينوي لك التعامل مع HRESULTs

لكن يمكنك أن تطلب من دلفي إخفاء تلك السباكة بعيدًا عنك، حتى تتمكن من الاستمرار في البرمجة:

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

خلف الكواليس، سيستمر المترجم في التحقق من إرجاع HRESULT، ورمي EOleSysError استثناء إذا أشار HRESULT إلى فشل (أي.كانت سلبية).المترجم الذي تم إنشاؤه com.safecall الإصدار يعادل وظيفيًا ما يلي:

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

لكنه يحررك ببساطة للاتصال:

bAdded: WordBool;
thingy: IThingy;

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

ليرة تركية؛دكتور:يمكنك استخدام إما:

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

لكن الأول يتطلب منك التعامل مع HRESULTs في كل مرة.

مكافأة الدردشة

لن ترغب أبدًا في التعامل مع النتائج بنفسك؛إنه يشوش البرنامج بالضوضاء التي لا تضيف شيئًا.لكن في بعض الأحيان قد ترغب في التحقق من HRESULT بنفسك (على سبيل المثال.تريد التعامل مع فشل ليس استثنائيًا جدًا).لم تبدأ إصدارات دلفي مطلقًا في تضمين واجهات رأس Windows المترجمة والتي تم الإعلان عنها في كلا الاتجاهين:

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;

أو من مصدر 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;

ال SC اللاحقة تعني com.safecall.كلتا الواجهتين متكافئتان، ويمكنك اختيار أيهما تريد الإعلان عن متغير COM الخاص بك وفقًا لرغبتك:

//thingy: IThingy;
thingy: IThingySC;

يمكنك حتى أن يلقي بينهما:

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;

الدردشة الإضافية الإضافية - C#

تعمل لغة C# بشكل افتراضي على ما يعادل لغة دلفي com.safecall, باستثناء لغة C#:

  • يجب عليك إلغاء الاشتراك في تعيين Safecall
  • بدلاً من الاشتراك

في C#، ستعلن عن واجهة COM الخاصة بك على النحو التالي:

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

ستلاحظ أن COM HRESULT مخفي عنك.سوف يقوم مترجم C#، مثل مترجم دلفي، تلقائيًا بالتحقق من HRESULT الذي تم إرجاعه ويطرح استثناءً لك.

وفي C#، كما هو الحال في دلفي، يمكنك اختيار التعامل مع HRESULTs بنفسك:

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

ال [حفظ سيج] يخبر المترجم بالحفاظ على توقيع الطريقة تمامًا كما هو:

يشير إلى ما إذا كانت الأساليب غير المُدارة التي لها النتيجة أو retval تتم ترجمة قيم الإرجاع مباشرة أو ما إذا كان النتيجة أو retval يتم تحويل قيم الإرجاع تلقائيًا إلى استثناءات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top