سؤال

لقد قمت بإنشاء كائن COM (DLL) قيد التشغيل باستخدام ATL.لاحظ أن هذا كائن وليس عنصر تحكم (لذلك لا يحتوي على نافذة أو واجهة مستخدم.) مشكلتي هي أنني أحاول إطلاق حدث من سلسلة رسائل ثانية وأتلقى "فشل ذريع" (0x8000FFFF).إذا قمت بتنشيط الحدث من موضوعي الرئيسي، فلن أتلقى الخطأ.الخيط الثاني يدعو CoInitializeEx ولكن هذا لا يشكل فرقا.أنا أستخدم نموذج ترابط الشقة ولكن التبديل إلى Free Threaded لا يساعد.

من الواضح أن حقيقة أنني أحاول القيام بذلك من موضوع ثانٍ أمر بالغ الأهمية.هل هناك طريقة سهلة للقيام بذلك أم سأضطر إلى تنفيذ بعض أشكال الرسائل ذات النافذة المخفية؟

على سبيل المثال، في الملف المصدر لكائني الرئيسي:

STDMETHODIMP MyObject::SomeMethod(...)
{
  CreateThread(NULL, 0, ThreadProc, this, 0, NULL);
  // Succeeds with S_OK
  FireEvent(L"Hello, world!");
  return S_OK;
}

DWORD WINAPI ThreadProc(LPVOID param)
{
  CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  MyObject* comObject = reinterpret_cast<MyObject*>(param);
  // Fails with 0x8000FFFF
  comObject->FireEvent(L"Hello, world!");
}

void MyObject::FireEvent(BSTR str)
{
  ...
  // Returns 0x8000FFFF if called from ThreadProc
  // Returns S_OK if called from SomeMethod
  pConnection->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
}
هل كانت مفيدة؟

المحلول

أساسيات كوم

في STA، يعيش كائنك على خيط واحد (الخيط).هذا الموضوع هو الذي تم إنشاؤه عليه، ويتم تنفيذ أساليبه وأحداثه.يتأكد STA من عدم تنفيذ طريقتين للكائن الخاص بك في وقت واحد (لأنه يجب تنفيذهما على The Thread، لذا فهذه نتيجة جيدة).

هذا لا يعني أنه لا يمكن الوصول إلى الكائن الخاص بك من خلال سلاسل رسائل أخرى.يتم ذلك عن طريق إنشاء وكلاء للكائن الخاص بك لكل مؤشر ترابط آخر غير The Thread.في The Thread، تقوم بتعبئة IUnknown مع CoMarshalInterThreadInterfaceInStream وعلى الخيط الآخر الذي قمت بفكه CoGetInterfaceAndReleaseStream الذي يقوم بالفعل بإنشاء الوكيل على مؤشر الترابط الآخر.يستخدم هذا الوكيل مضخة الرسائل لمزامنة المكالمات إلى كائنك، والمكالمات التي لا تزال قيد التنفيذ على مؤشر الترابط، لذلك يجب أن يكون مؤشر الترابط حرًا (غير مشغول) لتنفيذ مكالمة من مؤشر ترابط آخر.

في حالتك، تريد أن يكون كائنك قادرًا على تنفيذ الأساليب على مؤشر ترابط واحد ورفع الأحداث على مؤشر ترابط آخر.إذا هذا لديه ليحدث في MTA، لذلك يجب أن يعيش الكائن الخاص بك في MTA، لذلك يجب أن يكون الفصل الدراسي الخاص بك مترابطة.مؤشرات الترابط تنتمي إلى شقة واحدة بالضبط، لذلك لا يمكن أن يكون مؤشر الترابط في MTA وSTA في نفس الوقت.إذا كان الكائن الخاص بك موجودًا في MTA كلما حاول كائن STA استخدامه، فسيتعين عليه إنشاء وكيل.حتى تحصل على النفقات العامة طفيفة.

ما أعتقده هو أنك تفكر في بعض "التقنيات" الذكية جدًا لتفريغ سلسلة المحادثات الرئيسية الخاصة بك، وإجراء بعض الأحداث "غير المتزامنة"، والتي لن تطير في النهاية :-)) إذا فكرت في الأمر، فلا بد من وجود مستمع في هذا الموضوع الثاني [العامل] ...

راجع للشغل، هذا الخط

MyObject* comObject = reinterpret_cast<MyObject*>(param);

يمكن القيام به في MTA فقط.

نصائح أخرى

أعتقد أن المشكلة الحقيقية ليست في ما تم تكوين المكون الخاص بك به، ولكن في عملية المضيف.يعيش العديد من المضيفين، مثل مضيفي Office Object Model، في شقة مترابطة واحدة، وفي هذه الحالة لا يُسمح باستدعاءهم من أي شيء سوى السلسلة الرئيسية.
إذا كانت هذه هي الحالة، فيمكنك السماح لـ COM بالقيام بالعمل باستخدام نموذج الشقة المترابطة المفرد ونقل المكالمة الفعلية إلى وظيفة في CoClass واستدعاء تلك الوظيفة من مؤشر الترابط الخاص بك.
يؤدي ذلك فقط إلى تمرير رسائل النافذة خلف الكواليس أيضًا، ولكنه يوفر عليك تنفيذ ذلك بنفسك.

خيوط في COM (ويكيبيديا):
يعد نموذج الشقة ذات الخيوط المفردة (STA) نموذجًا شائع الاستخدام.هنا، يقف كائن COM في موضع مشابه لواجهة مستخدم تطبيق سطح المكتب.في نموذج STA، يتم تخصيص خيط واحد لتوجيه أساليب الكائن، أي.يتم دائمًا استخدام مؤشر ترابط واحد لتنفيذ أساليب الكائن.في مثل هذا الترتيب، يتم تنظيم استدعاءات الأسلوب من سلاسل العمليات خارج المجموعة وإدراجها في قائمة الانتظار تلقائيًا بواسطة النظام (عبر قائمة انتظار رسائل Windows القياسية).وبالتالي، ليس هناك ما يدعو للقلق بشأن ظروف السباق أو عدم التزامن لأن كل استدعاء أسلوب لكائن ما يتم دائمًا تنفيذه حتى اكتماله قبل استدعاء كائن آخر.

أنظر أيضا ضخ الرسائل في نفس المادة.

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