الوصول بشكل صحيح إلى SafeArray من vt_unknown مع SafeArraygetElement

StackOverflow https://stackoverflow.com/questions/1609025

  •  05-07-2019
  •  | 
  •  

سؤال

لدينا مكون COM موجود في التنفيذ والواجهة في التعليمات البرمجية المدارة ولكن مدفوعة بمكون أصلي. المكون المدار هو إعادة أ SafeArray العودة إلى الكود الأصلي عبر إعلان الطريقة التالية.

interface IExample {
  <return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_UNKNOWN)>
  object[] DoSomeOperation()
}

يمر التوقيع الأصلي المولد بشكل صحيح هذا مرة أخرى ك SafeArray.

خلال مراجعة التعليمات البرمجية على الرغم من أننا توصلنا إلى بعض الأسئلة حول المكالمات إلى الصفيف الناتج مع SafeArraygetElement. المشكلة هي ما إذا كانت SafeArraygetElement إرجاع أ IUnknown مثيل هو addref'd أم لا. في الأساس يتلخص في أي مما يلي صحيح

مثال 1:

CComPtr<IUnknown> spUnk;
hr = SafeArrayGetElement(pArray, &bounds, reinterpret_cast<void**>(&spUnk));

مثال 2:

IUnknown* pUnk;
hr = SafeArrayGetElement(pArray, &bounds, reinterpret_cast<void**>(&pUnk));

الوثائق رقيقة جدا في هذا الموضوع. ويشمل فقط السطر التالي.

إذا كان عنصر البيانات عبارة عن سلسلة أو كائن أو متغير ، فإن الدالة تقوم بنسخ العنصر بالطريقة الصحيحة.

تعريف الصحيح غامض بعض الشيء.

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

المحلول

يجب أن تكون الطريقة الأولى صحيحة ، وستتماشى مع التعامل مع الكائنات في جميع أنحاء COM ، ويفترض أن التعريف الذي وجدته يجعل الافتراض أن المستهلك يعرف الطريقة الصحيحة.

العناصر الأخرى المذكورة تتطلب ذلك. يحمل نسخ متغير أو SafeArray AddRef () ضمنيًا عندما يحتوي على كائنات. البديل لا يتطلب ذلك عند وجود vt_byref.

variantcopy @ msdn
SafeArraycopy @ msdn

هذا السلوك ليس جوهريًا في المجمعات الصريحة أو المتغيرات لأنه جزء من قواعد التعامل مع المعلمات في COM. لا يوجد أي شيء يمنع شخص ما من محاولة التحايل على القواعد.

بالنسبة لمعلمات الإدخال ، ليس من مسؤولية Callee addref () إلا إذا كانت تنوي الاحتفاظ بمؤشر الواجهة لمزيد من الاستخدام. ومع ذلك ، تتطلب حالات استخدام المعلمة الأخرى.

على سبيل المثال ، يجب أن تحتوي الواجهات الموضوعة في المتغيرات أو الحاويات الأخرى على مكالمة AddRef () على الأقل ، وإلا فإن هذا قد يخلق مشكلات عند استخدام المتغيرات كمعلمات إخراج من طرق COM ، لأن نقل البيانات/المراجع في اتجاه واحد. يمكن أن ينتهي الكائن الأصلي بحلول الوقت الذي تصل فيه المكالمة إلى وجهتها. وبالمثل ، يتطلب تنظيم واجهة في دفق addref () كذلك.

وبالمثل ، يتطلب الاتصال بالرجوع على الأقل مكالمة AddRef واحدة على الأقل. إذا لم يكن هذا هو الحال ، فلا يجوز لأي مكالمة مناسبة طويلة الأمد (على سبيل المثال ، من خلال DCOM) الوصول إلى وجهتها مع ضمان أن الكائن المشار إليه لا يزال على قيد الحياة. يتم تخطي مكالمات AddRef ()/الإصدار () بشكل متكرر هنا ، على الرغم من أن الكائن يجب أن يكون بالفعل 1+ بسبب الإنشاء في نطاق الاتصال أو قبله.

إذا كان من الممكن تعديل المكون ، وكانت مكالماتك قيد التشغيل ، فقد يكون من المستحسن استخدام GIT بدلاً من ذلك. يتيح لك ذلك تمرير رمز الرمز المميز بدلاً من ذلك ، وسيكون من الأسهل حشد الواجهة عبر شقق COM. يصبح عمر الكائنات المعنية بعد ذلك مسؤولية المتصل خلال مدة المكالمة ، وستتمكن من فخ الحالات التي لا يمكن فيها تنظيم كائن.

إنشاء جدول الواجهة العالمية @ msdn

أيضا مثيرة للاهتمام هو الحاشية ل BSTRs.

إذا كان تنفيذ دالة تأخذ معلمة مرجعية BSTR يعين BSTR جديد للمعلمة ، فيجب أن يحرر BSTR المشار إليه مسبقًا.

وظائف معالجة السلسلة (com)

نصائح أخرى

يجب أن يكون addref: ed ، لكن ليس لدي معلومات مباشرة أن هذا هو الحال (على سبيل المثال لم أقرأ المصدر).

أعتقد أن الوثائق واضحة تمامًا ، على الرغم من ذلك - نسخ مؤشر الواجهة "بشكل صحيح" هو addref: ing it.

إذا كنت تريد أن تكون متأكدًا حقًا ، فقم ببناء كائن ATL COM بوسعًا فائقًا ينفذ IUnknown, ، أشياء عددًا منهم في SAFEARRAY ووضع نقطة توقف في CComObjectBase<>::InternalAddRef (إذا كانت ذاكرتي تخدم). ثم تصحيح مكالمة إلى SafeArrayGetElement ومعرفة ما إذا كانت نقطة التوقف الخاصة بك قد ضربت.

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