WinRT هو COM ── IInspectable و.winmd وإسقاط اللغات، ولماذا لا يزال WinUI يركب عقداً ثنائياً

· آخر تحديث: · · Windows, WinRT, COM, WinUI, Windows App SDK, تطوير Windows

سجل التعديلات (النسخة الأولى، نُشرت في 29 Aug، 2026)
النشر الأول

تريد إضافة وظائف Windows جديدة إلى تطبيق WPF أو WinForms. لكن استدعاء ملتقط WinRT يرمي استثناء. وقراءة حديث WinUI تجعلك تظنّ أنك تحتاج إعادة بناء الواجهة. يُرتَّب هذا الحيرة بـ فصل آلية WinRT عن اختيار إطار الواجهة.

نقطة انطلاق هذه المقالة أن WinRT أيضاً يقوم على العقد الثنائي لـ COM. تنصّ Microsoft نفسها على «The Windows Runtime is based on COM (Windows Runtime قائم على COM)».1 تضمين جدول Excel في Word الذي رأيناه في مقالة كائن OLE السابقة، وWinRT وWinUI الحاليان، في الجذر IUnknown نفسه.

هنا نمسك أوّلاً العناصر الثلاثة التي تكوّن WinRT، ثم نقاط الانتباه عند الاستخدام من تطبيق سطح مكتب، وأخيراً كيف نعامل الأصول القائمة. القرّاء المستهدفون مطوّرون بخبرة COM أو تطوير سطح مكتب Windows، البيئة المفترضة Windows 10/11 و.NET 6 فما بعده (C#) أو C++17 (C++/WinRT)، الصعوبة متوسّطة.

1. الخلاصة أوّلاً

ثلاث خلاصات تُمسَك.

  • WinRT ليس وقت تشغيل مُداراً؛ بل ABI (عقد ثنائي) قائم على COM. أُضيف إلى ذلك العقد .winmd الذي ينقل معلومات النوع، وإسقاط لغات للاستدعاء الطبيعي من كلّ لغة.1234
  • معظم واجهات WinRT يمكن استخدامها من تطبيقات WPF وWinForms وWin32 القائمة. لكن يلزم تأكيد ثلاث فرضيات: تمرير HWND، وpackage identity، وتهيئة الخيط.5678
  • الترحيل الشامل للواجهة إلى WinUI والاستخدام الجزئي لواجهات WinRT حكمان مختلفان. WinUI أيضاً يقوم على ABI الخاص بـ WinRT، ويمكن لأصول COM/ActiveX القائمة وWinRT التعايش على الأساس نفسه.921

فيما يلي يسهل تتبّع الصلة بهذا الترتيب.

ما تريد معرفته الفصل الذي تقرؤه
لماذا يمكن القول «WinRT هو COM» الفصلان 2–3: المشترك مع COM وIInspectable
لماذا يمكن الاستدعاء الطبيعي من C# وC++ الفصلان 4–5: .winmd وإسقاط اللغات
ما تؤكّده للاستخدام من تطبيق قائم الفصل 6: HWND وpackage identity والشقّة
هل ينبغي الترحيل إلى WinUI الفصول 7–9: أساس WinUI، حكم الترحيل، شروط تسجيل الإشعار

خريطة المعرفة التالية لمراجعة علاقة العناصر. إن أردت القراءة أوّلاً فامضِ من الفصل 2 بالترتيب.

في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 20، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle

2. OLE وWinRT أيضاً، الجذر العقد الثنائي نفسه

تتبّع هذا المدوّنة حتّى الآن عالم COM الكلاسيكي: فكر تصميم COM، ونموذج خيوط STA/MTA، ومعاملة ActiveX/OCX، والمستند المركَّب OLE. هذه كلّها تقنيات من التسعينيات.

أمّا WinRT فأساس واجهة أُدخل في Windows 8 (2012). يقدّم حالياً إشعارات التوست والمشاركة وBluetooth وOCR كمجموعة واجهات في فضاء الأسماء Windows.*، ويصير أيضاً أساس WinUI وWindows App SDK.10 يبدوان عالمين قديم وجديد منفصلين تماماً، لكن الكيان متّصل.

المشترك الوعد بالاستدعاء عبر واجهة

مكوّن COM وصنف WinRT كلاهما يكشف الوظائف عبر واجهة. بمقارنة الواجهة الأساس تصير العلاقة كما يلي.1

COM الكلاسيكي WinRT
أساس الواجهة IUnknown أساس الواجهة IInspectable. وأساسه IUnknown

أي أن WinRT لم يُستبدل بآلية لا علاقة لها بـ COM، بل أُضيفت طبقة فوق IUnknown. عدّ المراجع وQueryInterface وHRESULT لا تزال حيّة كما هي.

تسمّي وثائق C++/WinRT أيضاً واجهات WinRT «تطوّراً لـ COM (an evolution of COM)»، وتشرح أنّها تصميم يستخدم واجهات قائمة على COM عبر إسقاط لغة.211

نسب COM الكلاسيكي وWinRTفوق أساس مشترك هو العقد الثنائي لـ COM عبر IUnknown وvtable يقوم عالم COM الكلاسيكي مثل OLE وActiveX من التسعينيات وعالم WinRT من 2012 فما بعده وWinUI وWindows App SDK فوقه جنباً إلى جنب، وليسا حصريين بل متّصلينالعقد الثنائي لـ COM (IUnknown وvtable)COM الكلاسيكي (OLE وActiveX وCOM ذاتي)WinRT (IInspectable و.winmd)WinUI / Windows App SDKيمكن التعايش على الأساس نفسه

الشكل 1: COM الكلاسيكي وWinRT ليسا عالمين منفصلين بل جيلين قديم وجديد فوق العقد الثنائي نفسه.

لذا ليست هذه المقالة مجرّد «تقديم واجهة جديدة». إنّها مقالة تتأكّد أين تسري معرفة COM التي تملكها أصلاً في تطوير Windows لعام 2026.

3. IInspectable فوق IUnknown

الأساس الذي لا يتغيّر والثلاث دوال المضافة

تحدّد مواصفة نظام أنواع WinRT الرسمية أن كلّ واجهة WinRT تتطلّب IInspectable ضمناً، وIInspectable يتطلّب IUnknown. ما يعرّفه IUnknown هو الدوال الثلاث التقليدية QueryInterface وAddRef وRelease.12

فوق ذلك يضيف IInspectable الدوال الثلاث التالية.13

الدالّة الدور
GetIids تعيد قائمة IID للواجهات التي ينفّذها هذا الكائن
GetRuntimeClassName تعيد اسم نوع WinRT مؤهَّلاً بالكامل (Windows.Storage.StorageFile وغيره) كـ HSTRING
GetTrustLevel تعيد مستوى ثقة الكائن
IInspectable يركب فوق IUnknownتتطلّب كلّ واجهة WinRT IInspectable، ويتطلّب IInspectable IUnknown. يقدّم IUnknown QueryInterface وAddRef وRelease، ويقدّم IInspectable GetIids وGetRuntimeClassName وGetTrustLevel، وتركب فوقها دوال كلّ واجهة WinRTIUnknown (QI وAddRef وRelease)IInspectable (GetIids واسم النوع ومستوى الثقة)دوال كلّ واجهة WinRT

الشكل 2: كائن WinRT يرصف ثلاث دوال IUnknown ثم ثلاث دوال IInspectable ثم الواجهات الفردية.

من اسم النوع يمكن جلب تعريفات الدوال والخاصّيات والأحداث

المهمّ ليس عدد الدوال المضافة بقدر إمكان ربط اسم النوع بالبيانات الوصفية.

في COM الكلاسيكي كانت الطريقة القياسية لمعرفة هوية الكائن وقت التشغيل «معرفة IID والسؤال بـ QueryInterface». للغات السكربت كان هناك مسار آخر IDispatch.

في WinRT يمكن حلّ اسم النوع الحاصل بـ GetRuntimeClassName بالبيانات الوصفية .winmd في الفصل التالي. ومنها تُؤخذ التعريفات الكاملة للدوال والخاصّيات والأحداث. تقول المواصفة نفسها إن إمكان الحصول على اسم نوع WinRT قابل للحلّ بالبيانات الوصفية هو ما «يمكّن إسقاط اللغة (enables language projection)».12

من GetRuntimeClassName إلى إسقاط اللغةعندما يستدعي الطرف المستدعي GetRuntimeClassName للكائن يُعاد اسم نوع WinRT مؤهَّل بالكامل، وحلّ ذلك الاسم بـ Windows Metadata يعطي التعريف الكامل للنوع، وهذا ما يمكّن الإسقاط إلى كلّ لغةكائن WinRTاسم النوع (GetRuntimeClassName)حلّ تعريف النوع بـ .winmdيصير إسقاط اللغة ممكناً

الشكل 3: «أخذ اسم النوع وقت التشغيل وجلب البيانات الوصفية من اسم النوع» في مركز آلية WinRT.

افصل «الوراثة» و«الطلب» لواجهات يعرّفها المستخدم

هناك فرق ينتبه إليه من اعتاد COM. ليس في نظام أنواع WinRT وراثة بين واجهات يعرّفها المستخدم. الاشتقاق مثل IFileSystemBindData2 : IFileSystemBindData في COM الكلاسيكي غير موجود قصداً، ويُعبَّر بدلاً منه بتصريح «الواجهة A تتطلّب (requires) الواجهة B».121

هذا حديث مختلف عن سلسلة ABI الأساس IUnknownIInspectable التي رأيناها حتّى الآن. تبقى هذه الأساس أساس كلّ واجهة WinRT.

عُقد المستخدم أُميل إلى شكل أخلخ لا يعتمد على تخطيط وراثة vtable. وفي الوقت نفسه كيان الاستدعاء لا يزال عبر vtable. المهمّ عدم خلط فرق كتابة العقد بآلية الاستدعاء.

4. ما حلّه .winmd ── جحيم ربط معلومات النوع

صعوبة COM الكلاسيكي كانت في «طريقة توزيع معلومات النوع»

في عمل COM الكلاسيكي كان العبء أكبر في كيف تُوزَّع معلومات النوع منه في تنفيذ الواجهة نفسها.

جهة الاستخدام مسار إيصال معلومات النوع
C++ اكتب العقد بـ IDL، وولّد الترويسة والوكيل/البديل بـ MIDL
VB6 والسكربت وزّع مكتبة أنواع (TLB)
.NET اصنع تجميع تشغيل بيني على حدة

لـ TLB قيود أنواع أميل إلى الأتمتة، ومعلومات تُكتب في IDL ولا تدخل TLB. علاوة على ذلك، لأن المسار ينقسم لكلّ لغة، يقدُم أحدها فيؤدّي إلى عدم اتّساق النوع. هذا العناء كما عولج في مقالة مكتبة الأنواع وdscom ومقالة التوافق الخلفي لواجهات DLL وCOM.

.winmd عقد مشترك تقرؤه كلّ اللغات

جواب WinRT هو Windows Metadata (.winmd). تُوصف الواجهة بيانات وصفية قابلة للقراءة آلياً، وتقرأها الأدوات وإسقاطات اللغات لتوليد إسقاط نحو كلّ لغة.3

يضمّ Windows بيانات وصفية لكلّ واجهات WinRT المقدَّمة من النظام، ويقدّم أيضاً واجهات لحلّ فضاءات الأسماء والأنواع وقت التشغيل. يتضمّن Windows SDK نسخة لوقت الترجمة. يمكن لطرف ثالث أيضاً، بإرفاق .winmd بمكوّن WinRT الخاص به، المشاركة في إسقاط اللغة بالآلية نفسها لواجهات النظام.3

ما تغيّر هنا هو شكل معلومات النوع الموزَّعة. بدلاً من TLB والترويسة وتجميع التشغيل البيني المتفرّقة لكلّ لغة، صارت إسقاطات كلّ اللغات تقرأ .winmd واحداً.

لكن IDL لم يصر غير لازم. عند صنع مكوّن WinRT ما زلت تصف العقد بـ IDL (MIDL 3.0 المحدَّث نحو WinRT)، ويولّد مترجم MIDL .winmd.14

خطّ إنتاج صنع مكوّن WinRTما زال عقد مكوّن WinRT يُوصف بـ IDL أي MIDL 3.0، ويترجمه مترجم MIDL إلى .winmd. الموزَّع هو هذا .winmd، وتقرؤه إسقاطات كلّ لغة مثل cppwinrt.exe وcswinrt.exe لتوليد الإسقاط. ما استُبدل ليس IDL بل شكل معلومات النوع الموزَّعةوصف العقد (IDL وMIDL 3.0)مترجم MIDL.winmd (معلومات النوع الموزَّعة)توليد إسقاط كلّ لغة

الشكل 4: مدخل العقد (IDL) لا يزال قائماً، ومخرج معلومات النوع الموزَّعة وُحِّد في .winmd.

التنسيق نفسه لملفّ .NET لكنّه ليس وقت تشغيل مُداراً

يستخدم التنسيق المادي لـ .winmd مواصفة ECMA-335 نفسها لتجميعات CLR. لكن قواعد تركيب البيانات الصالحة تختلف عن تجميع CLR. استعارة التنسيق وضرورة CLR للتنفيذ أمران مختلفان.3

هنا يلزم القراءة بفصل واجهات النظام عن مكوّنات الطرف الثالث.

الهدف علاقة .winmd والتنفيذ
واجهات WinRT المقدَّمة من النظام .winmd بيانات وصفية خالصة بلا شيفرة تنفيذ. التنفيذ في DLL أصلي لنظام التشغيل، ولا يلزم CLR للتنفيذ
مكوّن WinRT لطرف ثالث قد يتضمّن .winmd شيفرة تنفيذ. لمكوّن مُدار (مكتوب بـ C#) يتضمّن MSIL يلزم وقت تشغيل .NET المقابل للتنفيذ

فتح .winmd بأداة يجعله يبدو كتجميع .NET، فيسهل سوء الفهم «WinRT = مُدار». لكن محتوى .winmd المقدَّم من النظام عقد واجهات COM.3

فصل .winmd عن التنفيذ.winmd بيانات وصفية تستعير التنسيق المادي لـ ECMA-335، والمقدَّم من النظام عقد بلا شيفرة تنفيذ، وتنفيذ واجهات WinRT المقدَّمة من النظام في DLL أصلي لنظام التشغيل. بسبب هذا الفصل لا يلزم CLR لتنفيذ واجهات نظام WinRT حتّى إن بدا .winmd كتجميع .NET (و.winmd مكوّن طرف ثالث مُدار يتضمّن MSIL ويتطلّب وقت تشغيل .NET)المقدَّم من النظام بلا شيفرةتعريف النوع والتنفيذ يتقابلان.winmd (عقد وتنسيق ECMA-335)DLL أصلي لنظام التشغيل (التنفيذ)واجهات النظام لا تحتاج CLR

الشكل 5: في واجهات WinRT المقدَّمة من النظام .winmd عقد والتنفيذ DLL أصلي لنظام التشغيل. التنسيق شبيه بـ .NET لكن التنفيذ COM أصلي.

مقابلة معلومات نوع COM الكلاسيكي و.winmdفي COM الكلاسيكي انقسم مسار معلومات النوع لكلّ لغة، من IDL إلى ترويسة C++، ومن مكتبة الأنواع إلى VB6 والسكربت، ومن تجميع التشغيل البيني إلى .NET، وصار سبب تباين، بينما في WinRT تقرأ إسقاطات كلّ اللغات .winmd واحداً مشتركاًCOM الكلاسيكي: المسار لكلّ لغةIDL ← ترويسة C++TLB ← VB6 والسكربتتجميع تشغيل بيني ← .NET.winmd (بيانات وصفية واحدة)تقرأ إسقاطات كلّ اللغات مشتركاً

الشكل 6: أعاد .winmd طيّ توزيع معلومات النوع المتفرّق لكلّ لغة إلى شكل «بيانات وصفية واحدة يقرأها الجميع».

لم تختفِ القيود؛ تغيّرت حول سهولة الإسقاط

لمن يعرف COM الكلاسيكي بجملة: .winmd هو «إعادة عمل مكتبة الأنواع». إن فهمته إعادة تصميم لدور حاولت TLB أداءه، فوق تنسيق مجرَّب ECMA-335، كأصل مشترك لكلّ اللغات من البداية، اتّضح الموقع.

لكن القيود لم تختفِ. قيود TLB الأميل إلى الأتمتة استُبدلت بقيود نظام أنواع WinRT الخاص المتمحور حول «إمكان الإسقاط الآمن إلى كلّ اللغات». غياب وراثة واجهات يعرّفها المستخدم الذي رأيناه في الفصل 3 مثال على ذلك.12

لذا لا يمكن بالضرورة إدخال عقد COM/IDL قائم إلى WinRT كما هو. قد يلزم إعادة تصميم الواجهة.

الاستبدال من قيود مكتبة الأنواع إلى قيود نظام أنواع WinRTقيود التعبير الأميل إلى الأتمتة التي كانت لـ TLB (مكتبة الأنواع) لم تُرفَع بـ .winmd بل استُبدلت بقيود نظام أنواع WinRT الخاص المتمحور حول إمكان الإسقاط الآمن إلى كلّ اللغات. مثال ذلك غياب وراثة واجهات يعرّفها المستخدم، ولا يمكن بالضرورة إدخال عقد COM/IDL قائم كما هو وقد يلزم إعادة تصميم الواجهةاستبدالقيود TLB (أميل إلى الأتمتة)قيود نظام أنواع WinRT (محور قابلية الإسقاط)مثال: وراثة يعرّفها المستخدم غير جائزةعقد COM قائم قد يحتاج مراجعة تصميم

الشكل 7: قيود TLB لم «تختفِ» بل استُبدلت بقيود أخرى محورها قابلية الإسقاط إلى كلّ اللغات.

5. C++/WinRT وC#/WinRT ليسا «غلافاً» بل إسقاطاً

إظهار العقد المشترك بشكل طبيعي لكلّ لغة

مع عقد مشترك .winmd يمكن توليد طريقة الإظهار في كلّ لغة تلقائياً بأداة. هذا هو إسقاط اللغة (language projection). ينشر واجهات WinRT وفق أسلوب كلّ لغة ويخفي تفاصيل COM، فيقدّم تجربة برمجة طبيعية لتلك اللغة.411

الإسقاطان اللذان تدعمهما Microsoft حالياً هما التاليان.4

الإسقاط ما يولّده السمات
C++/WinRT يولّد cppwinrt.exe ترويسة إسقاط نحو C++ من .winmd إسقاط قائم على ملفّات ترويسة C++17 القياسي. لا حاجة لامتداد لغة مثل C++/CX، وهو خلف C++/CX وWRL11
C#/WinRT (CsWinRT) يولّد cswinrt.exe شيفرة C# من .winmd ويجعلها تجميع تشغيل بيني إسقاط نحو .NET. سلسلة أدوات مستقلّة عن وقت التشغيل1516

مسار جهة C# مربك قليلاً فنفرزه. حتّى .NET Core 3.x كان وقت تشغيل .NET يدعم استخدام WinRT/winmd تضميناً. في .NET 5 حُذف ذلك الدعم المضمَّن وانتقل إلى C#/WinRT.16 ليست واجهات WinRT التي صارت غير قابلة للاستخدام؛ تغيّر مكان تولّي الإسقاط.

الآن عند تحديد TFM مثل net8.0-windows10.0.19041.0 في C# تُشار تجميعات إسقاط Windows SDK تلقائياً.10

توليد الإسقاط إلى كلّ لغة من .winmdعندما يقرأ cppwinrt.exe .winmd واحداً تُولَّد ترويسة إسقاط نحو C++17، وعندما يقرأ cswinrt.exe يُولَّد تجميع تشغيل بيني نحو C#، فتُنشر واجهات WinRT بشكل وفق أسلوب كلّ لغة.winmd (عقد الواجهة)cppwinrt.exe ← ترويسة C++17cswinrt.exe ← تجميع تشغيل بيني C#يمكن الاستدعاء بأسلوب C++يمكن الاستدعاء بأسلوب C#

الشكل 8: الإسقاط ليس غلافاً يُكتب يدوياً؛ تولّده الأداة آلياً من العقد (.winmd).

حتّى مع التوليد التلقائي يبقى كيان الاستدعاء COM

نسمّي في هذه المقالة «إسقاطاً» لا «غلافاً» للتأكيد أنّه آلية تُشتق آلياً من البيانات الوصفية، لا طبقة ترجمة يتابعها إنسان واجهة واجهة. يمكن جعل الواجهات المحمولة على .winmd قابلة للاستخدام في كلّ اللغات المدعومة من البداية.

وأيّاً كانت اللغة المستدعِية، ما يحدث تحت الإسقاط استدعاء COM نفسه. مثلاً كتابة await picker.PickSingleFolderAsync() في C# تجعل الإسقاط يجسر IAsyncOperation في WinRT إلى عالم Task في .NET. ومع ذلك يُستخدم في جهة ABI استدعاء دالّة عبر vtable وHRESULT. ظهور الخطأ بشكل استثناء COM (HRESULT مثل 0x80070005) لهذا السبب.

الطبقات من شيفرة C# إلى واجهة WinRT لنظام التشغيلتُحوَّل شيفرة التطبيق C# أو C++ عبر إسقاط اللغة إلى ABI الخاص بـ WinRT أي استدعاء vtable لـ IInspectable، وتصل إلى واجهة WinRT التي ينفّذها نظام التشغيل. الإسقاط يخفي تفاصيل COM فقط، وكيان الاستدعاء COMشيفرة التطبيق (C# وC++)إسقاط اللغةABI الخاص بـ WinRT (vtable لـ IInspectable)تنفيذ واجهة WinRT لنظام التشغيل

الشكل 9: ما يخفيه الإسقاط «تفاصيل» COM لا COM نفسه.

معرفة هذه البنية تتيح تقسيم الأعطال إلى طبقتين. عدم اتّساق إصدار الشيفرة المولَّدة أو تخلّف إعداد TFM طبقة الإسقاط، وHRESULT والشقّة وعدّ المراجع طبقة ABI. في الأخيرة تصير خبرة تطوير COM سلاحاً كما هي.

6. مواضع الانحشار في تطبيقات سطح المكتب ── HWND والهوية والشقّة

افصل أوّلاً «إمكان الإشارة إلى الواجهة» عن «شروط العمل»

معظم واجهات WinRT يمكن استدعاؤها من تطبيقات سطح المكتب WPF وWinForms وWin32.5 مدخل الاستدعاء يختلف بين C# وC++ كما يلي.10

البيئة الإعداد الأوّل
C# / .NET 6 فما بعده اجعل TargetFramework TFM يحمل إصدار نظام تشغيل Windows مثل net8.0-windows10.0.19041.0
C++ ثبّت حزمة NuGet Microsoft.Windows.CppWinRT واستخدم C++/WinRT بـ C++17 فما بعده

لكن إمكان الإشارة لا يعني أن كلّ واجهة تعمل كما هي. أكّد النقاط الثلاث التالية. شروط تسجيل إشعار التوست مرتَّبة على حدة في الفصل 9.

ما تؤكّده التدبير الرئيس
هل تحتاج نافذة وجهة عرض مرّر HWND عبر COM interop موافق للواجهة
هل تحتاج package identity امنح الهوية بـ MSIX أو حزمة تشير إلى موقع خارجي
هل هُيِّئ الخيط لـ WinRT في الشيفرة الأصلية هيّئ بتحديد STA/MTA. في C# يتولّى وقت التشغيل ذلك عادة

موضع الانحشار 1: مرّر HWND لأدوات الالتقاط ونحوها من الواجهة

تفترض بعض أدوات الالتقاط والحوارات وواجهة المشاركة CoreWindow في UWP كوجهة عرض. ليس لتطبيق سطح المكتب CoreWindow، لذا يلزم تمرير HWND نافذة المالك صراحة قبل العرض.6

المدخل المستخدم في أدوات الالتقاط ونحوها واجهة COM IInitializeWithWindow. ترث IUnknown وتقدّم نافذة مالك لكائن WinRT يُستخدم في تطبيق سطح مكتب.17

في C# اجلب HWND أوّلاً حسب إطار الواجهة المستخدم.186

نافذة المالك طريقة جلب HWND
Window في WinUI WinRT.Interop.WindowNative.GetWindowHandle
نافذة WPF WindowInteropHelper
نموذج WinForms خاصّية Handle للنموذج

ثم مرّره إلى الملتقط بـ WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd) واعرض بعده. في C++/WinRT اجلب الكائن بـ as<IInitializeWithWindow>() ثم استدعِ Initialize(hwnd). إن أُغفلت التهيئة يحدث استثناء أو فشل صامت.1819

الاستعلام بـ QueryInterface عن واجهة COM كلاسيكية على كائن WinRT حديث وتهيئته. أن هذا الجسر صار الأسلوب الرسمي يظهر أيضاً أن WinRT هو COM.

واجهة المشاركة واجهة أخرى. لا تستخدم IInitializeWithWindow تجاه DataTransferManager. استخدم IDataTransferManagerInterop المخصَّص ومرّر HWND إلى ShowShareUIForWindow.6

ملتقط Windows App SDK الجديد مسار آخر أيضاً. يتلقّى Microsoft.Windows.Storage.Pickers WindowId في المنشئ، لذا لا تلزم صيغة InitializeWithWindow. لكنّها ليست واجهة تُستخدم بإعداد TFM وحده. يفترض إدخال Windows App SDK، وللتطبيق unpackaged نشر وقت التشغيل وتهيئته على جهة التوزيع.19

إجراء عرض ملتقط من تطبيق سطح مكتببعد أن يولّد تطبيق سطح المكتب الملتقط، استدعاء PickSingleFolderAsync كما هو يرمي استثناء أو فشلاً صامتاً، لذا يلزم أوّلاً جلب HWND نافذة المالك وتمريره بـ Initialize لـ IInitializeWithWindow ثم العرضالملتقط (WinRT)تطبيق سطح المكتبالملتقط (WinRT)تطبيق سطح المكتبalt[عرض دون تمرير HWND][تمرير HWND أوّلاً]توليدPickSingleFolderAsyncاستثناء أو فشل صامتاضبط HWND بـ IInitializeWithWindowPickSingleFolderAsyncيظهر الملتقط

الشكل 10: الأسلوب الرسمي سدّ «ليس لسطح المكتب CoreWindow» بتمرير HWND صريح.

موضع الانحشار 2: واجهات تحتاج package identity

بعض واجهات WinRT مثل سجلّ إشعارات التوست (ToastNotificationHistory) وقائمة القفز وأهداف المشاركة لا تعمل إلّا في تطبيق يملك package identity (تطبيق معبّأ). تفشل عند الاستدعاء من تطبيق unpackaged يُوزَّع بمثبّت تقليدي.7

التدبير اثنان. التعبئة بـ MSIX، أو استخدام «حزمة تشير إلى موقع خارجي (ما يُسمَّى sparse package)» تمنح معرّفاً مع الإبقاء على المثبّت القائم.20 أيّ واجهة تتطلّب الهوية يمكن تأكيدها من القائمة الرسمية.7

مساران إلى واجهة تحتاج package identityاستدعاء واجهة WinRT تتطلّب package identity من تطبيق unpackaged يفشل، لذا يُمنح package identity إمّا بالتعبئة بـ MSIX أو بحزمة تشير إلى موقع خارجي تمنح المعرّف فقط مع الإبقاء على المثبّت القائمتريد استخدام واجهة تتطلّب الهويةعبّئ بـ MSIXحزمة تشير إلى موقع خارجياكتساب package identityيعمل سجلّ الإشعارات وغيره

الشكل 11: تدبير الواجهة التي تتطلّب الهوية خياران: «MSIX» أو «مثبّت قائم + منح معرّف».

موضع الانحشار 3: أكّد تهيئة الخيط وSTA/MTA

الخيط الذي يعالج كائنات WinRT يحتاج تهيئة مسبقة لـ WinRT. في الشيفرة الأصلية استخدم RoInitialize أو winrt::init_apartment وحدّد نموذج التزامن STA/MTA. في تطبيقات C# WPF/WinForms يتولّى وقت التشغيل التهيئة عادة.8

RoInitialize مدخل جيل WinRT في الإطار نفسه لـ CoInitializeEx في COM. ترشد وثائق CoInitialize نفسها أيضاً، عند استخدام Windows Runtime، إلى استدعاء RoInitialize أو Windows::Foundation::Initialize بدلاً منه.21

خيط واجهة WPF/WinForms هو STA، وكائنات الواجهة تُلمَس في خيط الواجهة، والانتظار الحاجب في STA يجلب قفل انتظار ميت. التفكير المعالج في مقالة STA/MTA يبقى حيّاً كما هو مع واجهات WinRT أيضاً.

هناك واجهات لا تُستخدم حتّى مع تجهيز HWND والهوية

التدابير حتّى الآن حديث واجهات لها مدخل لاستخدام سطح المكتب. الواجهات التي تعتمد على CoreWindow أو ApplicationView نفسها لا يمكن استخدامها في تطبيق سطح مكتب. في هذه الحالة لا تضف تهيئة بل ابحث عن واجهة بديلة.57

تفرّع مواضع الانحشار عند استدعاء واجهة WinRT من سطح المكتبأكّد أوّلاً أن الخيط مهيَّأ لـ WinRT (في الشيفرة الأصلية حدّد STA/MTA صراحة بـ RoInitialize ونحوه. في C# يتولّى وقت التشغيل ذلك عادة)، ثم إن كانت واجهة WinRT المراد استدعاؤها واجهة تفترض CoreWindow فمرّر HWND بـ IInitializeWithWindow أو استخدم الملتقط الجديد، وإن كانت تتطلّب package identity فامنح معرّفاً بـ MSIX أو حزمة تشير إلى موقع خارجي، والواجهات التي تعتمد على CoreWindow أو ApplicationView نفسها لا تُستخدم على سطح المكتب فابحث عن واجهة بديلة، ومعظم الواجهات الأخرى يمكن استدعاؤها كما هي بإعداد TFM أو C++/WinRT فقطواجهةتتطلّب الهويةتعتمد على CoreWindow نفسهغير ذلكتهيئة الخيطما طبيعة الواجهة المراد استدعاؤها؟الأصلي تحديد صريح، C# عادة تلقائيHWND أو الملتقط الجديدMSIX أو منح معرّفابحث عن واجهة بديلةيمكن الاستدعاء كما هو

الشكل 12: على فرض تهيئة الخيط (صريحة في الشيفرة الأصلية، وموكولة عادة إلى وقت التشغيل في C#) يمكن تصنيف مواضع الانحشار إلى ثلاث سلالات ولكلّ منها تدبير نمطي.

تقابل تهيئة خيط COM وWinRTفي COM الكلاسيكي تهيّئ الخيط بتحديد STA أو MTA بـ CoInitializeEx، وفي WinRT تهيّئ بتحديد نموذج التزامن STA أو MTA نفسه بـ RoInitialize. ترشد وثائق CoInitialize أيضاً إلى استدعاء RoInitialize عند استخدام WinRT، ومفهوم الشقّة مشتركCOM الكلاسيكي: CoInitializeExالشقّة (STA / MTA)WinRT: RoInitializeخيط الواجهة STA وانتبه للانتظار

الشكل 13: تغيّر اسم واجهة التهيئة، لكن مفهوم الشقّة نفسه يُستخدم باستمرار.

7. أساس WinUI ── حتّى مع التطوير العلني لا يتغيّر العقد

الانتقال إلى التطوير العلني ليس تغييراً للعقد الثنائي

أعلنت Microsoft رسمياً في صيف 2025 نهجاً تدريجياً لنقل التطوير الرئيس لـ WinUI إلى ساحة علنية على GitHub. أربع مراحل: رفع تواتر تحديث المرآة، وتمكين البناء المحلّي، وترتيب الاختبارات ثم قبول مساهمات المجتمع، وأخيراً جعل GitHub المقرّ الرئيس للتطوير.22

عند نشر هذه المقالة (نهاية أغسطس 2026) تنصّ الوثائق الرسمية أيضاً على أن «WinUI يُطوَّر في العلن (built in the open)». صار ممكناً تتبّع تقدّم الهندسة اليومية في المستودع العلني.9

من الطبيعي أن يشعر مطوّر تابع تعاقب الأجيال WinForms ← WPF ← UWP ← WinUI أن «الإطار يتغيّر من جديد». لكن يلزم النظر بفصل إطار الواجهة الذي تغيّر عن الأساس تحته. بقي Win32 وCOM، وABI الخاص بـ WinRT من 2012 فما بعده، في المكان نفسه.

نافذة WinUI أيضاً مسندة بـ HWND

WinUI مجموعة واجهات WinRT تُقدَّم كجزء من Windows App SDK.923 Microsoft.UI.Xaml.Window الخاص به نافذة مسندة بـ HWND تحلّ محلّ نموذج النافذة القائم على CoreWindow في جيل UWP. يبدأ درس التشغيل البيني الرسمي أيضاً من جلب مقبض النافذة.24

أي أن تطبيق WinUI تطبيق Win32 تعمل فيه شجرة كائنات تتبع عقد IInspectable فوق نافذة HWND. معرفة QueryInterface وعدّ المراجع والشقّة المكتسبة في COM، ومعرفة HWND وحلقة الرسائل المكتسبة في Win32، تسريان كما هما في تحقيق أعطال WinUI.

تعاقب أجيال إطار الواجهة والأساس الذي لا يتغيّرتعاقبت أطر الواجهة WinForms وWPF وXAML في UWP وWinUI، لكن WinForms وWPF يركبان أساس Win32 وCOM مباشرة، وXAML في UWP وWinUI يركبان أساس Win32 وCOM نفسه عبر ABI الخاص بـ WinRT. ما تعاقب الطبقة العليا، وعقد الأساس لم يتغيّرتعاقب أجيال إطار الواجهةWinForms وWPFXAML في UWPWinUI (الحالي)ABI الخاص بـ WinRT (من 2012)الأساس الذي لا يتغيّر (Win32 + COM)

الشكل 14: ما علا وهبط طبقة الإطار. يركب WinForms وWPF Win32+COM مباشرة، وUWP وWinUI عبر ABI الخاص بـ WinRT، الأساس نفسه.

الطبقات التي تسند تطبيق WinUIيُقدَّم XAML وعناصر WinUI كجزء من Windows App SDK، ويعمل فوق ABI الخاص بـ WinRT أي عقد IInspectable، وتحته أساس COM وHWND في Win32. تحت تعاقب أجيال إطار الواجهة لم يتغيّر عقد هذا الأساسWinUI (XAML والعناصر)Windows App SDKABI الخاص بـ WinRT (IInspectable)COM + Win32 (HWND)

الشكل 15: تحت WinUI ABI الخاص بـ WinRT، وتحته COM الكلاسيكي وWin32. تغيّر الرصف لا الأساس.

الخلط الجزئي بـ XAML Islands يحتاج تأكيد قيود كلّ جيل

استراتيجية «خلط عناصر WinUI فقط في شاشات WPF/WinForms القائمة» تحتاج تقييماً بفصل جيل XAML Islands.

الجيل الوضع عند الاستخدام من WPF/WinForms
XAML Islands جيل UWP توجد عناصر غلاف في Windows Community Toolkit. لكن نحو WPF/WinForms يتوقّف عند جيل .NET Core 3.x ولا يُدعم في .NET الحالي25
جيل WinUI 3 يمكن الاستضافة من WPF وWinForms وWin32 بـ DesktopWindowXamlSource في Windows App SDK. لكن لا عناصر غلاف مريحة مثل جيل UWP، فعبء التنفيذ والتحقّق بمعاملة واجهة الاستضافة مباشرة قائم26

إن خطّطت للخلط التدريجي فأأمن ألّا تفترض خلطاً لكلّ عنصر فقط. محور استخدام واجهات WinRT لكلّ وظيفة (الفصل 6) أو الفصل لكلّ شاشة أو عملية أصلب في 2026.

8. الدلالة لتطبيقات الأعمال ── الترحيل الشامل والاستخدام الجزئي مشكلتان مختلفتان

«WinRT عالم جديد منفصل، لذا الاستخدام لا يكون إلّا بهجر الأصول القائمة وإعادة البناء». يُحَلّ هذا سوء الفهم الذي يُلتقى في مواقع Custom Software Development بقسمه قسمين.

أصول COM القائمة وWinRT يمكنهما التعايش

يمكن إضافة واجهات WinRT إلى تطبيق WPF يستخدم أتمتة Excel COM ويحمل عناصر ActiveX ويستدعي مكوّنات COM خاصّة بالشركة. ليس بهلوانية خاصّة بل جمع وظائف فوق أساس COM نفسه.

لإشعار توست مثلاً اضبط TFM للإشارة إلى الواجهة واستوفِ شروط التسجيل لإصدار الإشعار. حتّى لا تُنسى الأخيرة رتّبناها حسب المسار في الفصل 9. في C++/WinRT يمكن معاملة واجهات WinRT وCOM الكلاسيكي كليهما بالآلية نفسها winrt::com_ptr وwinrt::implements.21

قدّر تجديد الواجهة وإضافة الوظيفة على حدة

«هل ترحّل الواجهة شاملة إلى WinUI» و«هل تستخدم واجهات WinRT في المواضع اللازمة فقط» حكمان يختلفان في الحجم والمدّة والمخاطر.

الترحيل الشامل للواجهة مسألة اختيار إطار تعتمد على أصول الشاشات وعناصر الطرف الثالث وهيئة التطوير. عولج هذا الحكم في اختيار WinForms/WPF/WinUI. أمّا الاستخدام الجزئي لواجهات WinRT فتحسين صغير يمكن الشروع فيه اليوم على تطبيق قائم.

لا حاجة لتقدير ترحيل شامل للواجهة في قضية تريد إشعارات توست فقط. وبالعكس لا حاجة لتأجيل استخدام واجهات WinRT أيضاً بسبب «لن نرحّل إلى WinUI».

الترحيل الشامل والاستخدام الجزئي حكمان مختلفانالترحيل الشامل للواجهة إلى WinUI حكم كبير لاختيار الإطار يعتمد على أصول الشاشات والهيئة، بينما الاستخدام الجزئي لواجهات WinRT حكم صغير يمكن إضافته اليوم إلى تطبيق WPF أو WinForms قائم بإعداد TFM ونحوه، ويُدرَس هذان بفصل دون خلط«تريد استخدام وظائف Windows جديدة»ترحيل شامل للواجهة (حكم كبير)استخدام جزئي لواجهات WinRT (حكم صغير)يعتمد على أصول الشاشات والهيئةيمكن الإضافة اليوم إلى تطبيق قائم

الشكل 16: إلى «وظيفة جديدة» طريقان، وخلطهما يُفسد التقدير والحكم.

9. جدول قرار ── نسخة WinRT من الإبقاء والتغليف والاستبدال

اختر التغيير اللازم فقط حسب الموقف

كامتداد لـ جدول قرار ActiveX نلخّص الحكم حسب الموقف في جهة WinRT.

الموقف التوصية السبب
تريد استخدام واجهات WinRT مثل التوست والمشاركة وBluetooth من WPF/WinForms استخدام جزئي بإعداد TFM (أو إدخال C++/WinRT) يمكن الاستدعاء اليوم بلا ترحيل واجهة. لكن واجهة المشاركة عبر IDataTransferManagerInterop (الفصل 6)، والتوست انظر التكملة تحت الجدول106
استثناء / فشل صامت في ملتقط أو حوار مرّر HWND بـ IInitializeWithWindow. للجديد الملتقط الموافق لـ WindowId (يفترض إدخال Windows App SDK) الأسلوب الرسمي سدّ تصميم يفترض CoreWindow بـ HWND619
لا يعمل سجلّ الإشعارات أو قائمة القفز وغيرهما امنح package identity بـ MSIX أو حزمة تشير إلى موقع خارجي الواجهة التي تتطلّب الهوية تفترض التعبئة720
أصول COM/ActiveX/OLE قائمة لا تهجر. احكم الإبقاء/التغليف/الاستبدال لكلّ أصل ليست حصرية مع WinRT ويمكن التعايش على الأساس نفسه (الفصل 8)
واجهة تطبيق سطح مكتب جديد قيّم WinUI كمرشّح أوّل (WPF لا يزال قائماً) التطوير العلني أوضح اتجاه الاستثمار. الأساس ABI الخاص بـ WinRT229
خلط عناصر WinUI جزئياً في شاشات WPF/WinForms قائمة قيّم بحذر مع تقدير عبء التنفيذ بلا غلاف Islands جيل UWP يتوقّف عند .NET Core 3.x، وجيل WinUI 3 واجهة استضافة فقط2526
خطّة تفترض «انتهى WinRT مع UWP» صحّح الفرض WinRT أساس واجهة حالي يمكن استدعاؤه من سطح المكتب5

إشعارات التوست لا تُعرض بإعداد TFM وحده

إعداد جعل الواجهة قابلة للاستدعاء وتسجيل عرض الإشعار أمران مختلفان. عندما «يمرّ البناء لكن الإشعار لا يظهر» أكّد لا جهة الاستدعاء فقط بل المسار المستخدم وشكل الحزمة ووجود الترقية.

عند استخدام ToastNotificationManager التقليدي

في تطبيق unpackaged بلا package identity يفترض تسجيل اختصار قائمة ابدأ مُسنَد إليه AppUserModelID (AUMID). دونه لا يمكن إصدار توست.27

تطبيق معبّأ بـ MSIX ونحوه تمنح هوية الحزمة AUMID، لذا لا يلزم هذا التسجيل اليدوي.

عند استخدام AppNotificationManager في Windows App SDK

في هذا المسار الموصى به حالياً يلزم إدخال Windows App SDK واستدعاء Register() عند البدء. ثم تنقسم الشروط حسب شكل الحزمة.28

شكل الحزمة ما تؤكّده إضافياً
unpackaged يلزم نشر وقت تشغيل Windows App SDK على كلّ جهاز توزيع. يقوم Register() بتسجيل خادم COM
معبّأ بـ MSIX لا يعمل التسجيل التلقائي بـ Register(). أعلن منشّط COM في Package.appxmanifest

علاوة على ذلك في مسار Windows App SDK الإشعار من عملية ترقّت كمسؤول غير مدعوم. Show يفشل بهدوء دون استثناء. لتطبيق يحتاج ترقية انظر في فصل الإشعار إلى عملية غير مُرقّاة.28

تفاصيل تنفيذ التسجيل مشمولة في دليل تنفيذ الإقامة في علبة النظام والإشعار.

مسارا إشعار التوست والتسجيل اللازملإصدار إشعار توست من تطبيق سطح مكتب يتفرّع مسار ToastNotificationManager التقليدي حسب packaged أم لا، ويحتاج تطبيق unpackaged المرور بتسجيل اختصار قائمة ابدأ مُسنَد إليه AppUserModelID، ويعطي تطبيق packaged هوية الحزمة AppUserModelID. في مسار AppNotificationManager لـ Windows App SDK بالإضافة إلى إدخال SDK واستدعاء Register عند البدء يستوفي تطبيق unpackaged نشر وقت التشغيل على كلّ جهاز توزيع وتطبيق معبّأ بـ MSIX إعلان منشّط COM في البيان قبل المضيّ. علاوة على ذلك لمسار Windows App SDK تفرّع هل العملية مُرقّاة، والإشعار من عملية ترقّت كمسؤول غير مدعوم وShow يفشل بهدوء دون استثناء، لذا العرض في هذا المسار مقصور على عملية غير مُرقّاة، وتطبيق يحتاج ترقية يفصل الإشعار إلى عملية غير مُرقّاةلانعملانعملانعمتريد إصدار توستتقليدي: ToastNotificationManagerWASDK: AppNotificationManagerpackaged؟تسجيل اختصار AUMIDالهوية تقدّم AUMIDإدخال SDK + Register()packaged؟نشر وقت التشغيلإعلان COM في البيانيُعرض الإشعارعملية مُرقّاة؟غير مدعوم: Show يفشل بهدوءافصل الإشعار إلى عملية غير مُرقّاة

الشكل 17: أيّاً كان المسار لا يُبلَغ العرض إلّا بعد استيفاء الفرض حسب شكل التعبئة. مسار Windows App SDK لا يُعرض من عملية مُرقّاة حتّى مع اكتمال الفرض كلّه.

أخيراً عُد إلى الإبقاء والتغليف والاستبدال

هل تحتاج وظيفة جديدة، أم تريد تجديد الواجهة نفسها. بالعودة إلى هذا السؤال يمكن الحكم بفصل استخدام WinRT عن استبدال الأصول القائمة.

تدفّق حكم معاملة الأصول القائمة وWinRTانطلاقاً من تطبيق سطح مكتب قائم، إن لم تلزم وظائف Windows جديدة فأبقِ، وإن لزمَت وظيفة فغلّف بالاستخدام الجزئي لواجهات WinRT (مع الانتباه إلى مواضع انحشار HWND وpackage identity وتهيئة الخيط في الفصل 6)، ولا تنظر في الاستبدال بـ WinUI إلّا عندما يلزم تجديد الواجهة نفسها، وهو تدفّق حكم تدريجيالوضع الحالي يكفيوظيفة جديدةتجديد الواجهةتطبيق سطح مكتب قائمما اللازم؟أبقِ (صيانة كما هي)غلّف (استخدام جزئي لواجهات WinRT)استبدل (قيّم WinUI)انتبه إلى HWND والهوية والتهيئة (الفصل 6)

الشكل 18: هيكل «أبقِ أو غلّف أو استبدل» نفسه لجدول قرار ActiveX ينطبق كما هو على جهة WinRT أيضاً.

10. خلاصة

WinRT ليس بيئة تنفيذ جديدة منفصلة عن COM. إنّه أساس واجهة يجمع العقد الثنائي لـ COM مع بيانات وصفية وإسقاط إلى كلّ لغة.

العنصر الدور الذي أُمسك في هذه المقالة
IUnknown وIInspectable يجعلان QueryInterface وعدّ المراجع أساساً، ويضيفان ثلاث دوال لجلب اسم النوع وغيره
.winmd عقد مشترك لكلّ اللغات يمكن منه جلب التعريف من اسم النوع. يستعير تنسيق ECMA-335، لكن المقدَّم من النظام لا يحتوي شيفرة تنفيذ
C++/WinRT وC#/WinRT يولّدان واجهة نحو كلّ لغة من العقد. صار إسقاط C# من .NET 5 فما بعده سلسلة أدوات مستقلّة عن وقت التشغيل

حتّى إن صار المظهر واجهة طبيعية لـ C# أو C++، يُستخدم تحتها استدعاء COM عبر vtable وHRESULT. لذا فهم تمرير HWND على سطح المكتب وpackage identity وSTA/MTA وتهيئة الخيط يسهّل أيضاً عزل أعطال WinRT.

أُعلن مسعى نقل التطوير الرئيس لـ WinUI إلى ساحة علنية في صيف 2025 كنهج تدريجي. عند نشر هذه المقالة تنصّ الوثائق الرسمية أيضاً على «built in the open»، لكن عقد IUnknownIInspectable تحته لم يتغيّر.229

الخلاصة لتطبيقات الأعمال هي نفسها. أصول COM/ActiveX القائمة وWinRT يمكنهما التعايش. عدم خلط الترحيل الشامل للواجهة والاستخدام الجزئي لواجهات WinRT يحفظ دقّة التقدير والحكم.

المستند المركَّب في التسعينيات الذي رأيناه في مقالة OLE، وWinUI الحالي، يقومان على IUnknown نفسه. معرفة COM ليست مجرّد «الإلمام بالقديم». إنّها قراءة أساس Windows الحالي.

مقالات ذات صلة

مجالات الاستشارة ذات الصلة

تتعامل شركة كومورا سوفت ذ.م.م. مع تطوير مكوّنات COM وصيانة تطبيقات أعمال Windows التي تتضمّن أصول COM وتعديلها واستبدالها. يمكن الاستشارة من مرحلة تصير فيها محتويات هذه المقالة محور النقاش كما هي: «أريد استخدام إشعارات توست وملتقط مع الإبقاء على WPF»، «استدعاء واجهة WinRT توقف باستثناء»، «هل ينبغي الترحيل إلى WinUI أم الاستفادة من الأصول القائمة».

روابط مرجعيّة

  1. Microsoft Learn, Author COM components with C++/WinRT. حول كشف مكوّن COM وصنف WinRT كليهما الوظائف بواجهة، والنصّ الصريح على «The Windows Runtime is based on COM»، واشتقاق واجهة COM الكلاسيكي من IUnknown وواجهة WinRT من IInspectable واشتقاق IInspectable من IUnknown، وكون الاشتقاق بين واجهات يعرّفها المستخدم مثل IFileSystemBindData2 : IFileSystemBindData وظيفة COM الكلاسيكي وغيابه قصداً في نظام أنواع WinRT.  2 3 4 5 6

  2. Microsoft Learn, Consume COM components with C++/WinRT. حول البرمجة عبر واجهة لا كائن في COM، وسريان ذلك خلف كواليس واجهات WinRT التي هي تطوّر لـ COM (an evolution of COM)، وإمكان معاملة WinRT وCOM الكلاسيكي بالأسلوب نفسه بمؤشّر COM ذكي winrt::com_ptr.  2 3 4

  3. Microsoft Learn, Windows Metadata (WinMD) files. حول وصف واجهات WinRT بيانات وصفية قابلة للقراءة آلياً .winmd واستخدام الأدوات وإسقاطات اللغات لها، وتضمين Windows بيانات وصفية لكلّ واجهات WinRT المقدَّمة من النظام وتقديم واجهات حلّ، وإمكان طرف ثالث المشاركة في إسقاط اللغة بالتنسيق نفسه، وكون التنسيق المادي مواصفة ECMA-335 (نفسه لتجميعات CLR) وكون WinMD المقدَّم من النظام بيانات وصفية خالصة.  2 3 4 5

  4. Microsoft Learn, Windows Runtime (WinRT) language projections. حول نشر إسقاط اللغة واجهات WinRT وفق أسلوب كلّ لغة، وتعريف .winmd لواجهات WinRT وقراءة الإسقاط لها، ودعم Microsoft C++/WinRT (C++17 فما بعده) وC#/WinRT (.NET) فقط.  2 3

  5. Microsoft Learn, WinRT APIs callable from a desktop app. حول إمكان استخدام معظم واجهات WinRT من تطبيقات سطح المكتب .NET وC++ الأصلي، واستثناء أصناف صُمِّمت خصّيصاً لـ UWP مثل CoreDispatcher وCoreWindow وApplicationView.  2 3 4

  6. Microsoft Learn, Display WinRT UI objects that depend on CoreWindow. حول اعتماد بعض أدوات الالتقاط والنوافذ المنبثقة والحوارات على CoreWindow، وعدم دعم CoreWindow في تطبيقات سطح المكتب، وإمكان ضبط HWND نافذة المالك قبل العرض للأصناف التي تنفّذ IInitializeWithWindow (أو IDataTransferManagerInterop المكافئ)، والإجراء في كلّ من WinUI 3 وWPF وWinForms.  2 3 4 5 6

  7. Microsoft Learn, WinRT APIs not supported in desktop apps. حول وجود سلالتين لواجهات WinRT لا تُستخدم في تطبيقات سطح المكتب، واجهات تعتمد على وظائف واجهة خاصّة بـ UWP وواجهات تتطلّب package identity (ToastNotificationHistory وJumpList وغيرهما)، ودعم الأخيرة في تطبيقات معبّأة بـ MSIX فقط.  2 3 4 5

  8. Microsoft Learn, RoInitialize function (roapi.h). حول تهيئة RoInitialize الخيط الحالي لـ Windows Runtime بنموذج التزامن المحدَّد (RO_INIT_SINGLETHREADED/RO_INIT_MULTITHREADED)، وحاجة كلّ خيط ينشّط كائنات WinRT أو يشغّلها إلى تهيئة مسبقة، وصيرورة RPC_E_CHANGED_MODE عند تحديد متعارض على خيط مهيَّأ كـ MTA.  2

  9. Microsoft Learn, WinUI 3. حول كون WinUI إطار الواجهة الأصلية الموصى به لتطبيقات سطح مكتب Windows الجديدة، وتقديمه كجزء من Windows App SDK، وعمله على Windows 10 الإصدار 1809 فما بعده، وتطويره في العلن.  2 3 4 5

  10. Microsoft Learn, Call Windows Runtime APIs in desktop apps. حول إمكان استدعاء واجهات WinRT عند تحديد TFM يحمل إصدار نظام تشغيل Windows (مثل net10.0-windows10.0.22621.0) من .NET 6 فما بعده فتُشار حزمة استهداف Windows SDK، واستخدام C++ حزمة NuGet Microsoft.Windows.CppWinRT وC++/WinRT بـ C++17 فما بعده.  2 3 4

  11. Microsoft Learn, Introduction to C++/WinRT. حول كون C++/WinRT إسقاط لغة بـ C++17 الحديث القياسي بالكامل وتنفيذه مكتبة قائمة على ملفّات ترويسة، وكونه الخلف الموصى به لـ C++/CX وWRL، وتصميم WinRT قائماً على واجهات COM ويُوصَل إليه عبر إسقاط لغة، وإخفاء الإسقاط تفاصيل COM، وتوليد cppwinrt.exe ترويسة إسقاط من .winmd.  2 3

  12. Microsoft Learn, The Windows Runtime (WinRT) type system. حول تتطلّب كلّ واجهة WinRT IInspectable ضمناً وتتطلّب IInspectable IUnknown، وتعريف IUnknown لـ QueryInterface وAddRef وRelease، والدوال الثلاث التي يضيفها IInspectable GetIids وGetRuntimeClassName وGetTrustLevel، وتمكين إسقاط اللغة بإعادة GetRuntimeClassName اسماً قابلاً للحلّ بالبيانات الوصفية، وغياب وراثة واجهات يعرّفها المستخدم في نظام أنواع WinRT والتعبير عنها بـ requires.  2 3 4

  13. Microsoft Learn, IInspectable interface (inspectable.h). حول تقديم IInspectable الوظائف اللازمة لكلّ أصناف WinRT، ووراثته IUnknown، وامتلاكه الدوال الثلاث GetIids وGetRuntimeClassName وGetTrustLevel. 

  14. Microsoft Learn, Introduction to Microsoft Interface Definition Language 3.0. حول كون MIDL 3.0 نحواً حديثاً موجزاً لإعلان أنواع WinRT، ووصف عقد WinRT لا يزال بـ IDL وتوليد مترجم MIDL Windows Metadata (.winmd). 

  15. Microsoft Learn, C#/WinRT. حول معالجة cswinrt.exe المتضمَّن في حزمة NuGet لـ C#/WinRT .winmd وتوليد شيفرة C# وترجمتها إلى تجميع تشغيل بيني، وموقعه المماثل لتوليد C++/WinRT ترويسة نحو C++. 

  16. Microsoft Learn, Built-in support for WinRT is removed from .NET. حول حذف الدعم المضمَّن لـ Windows Runtime من .NET في .NET 5 والانتقال إلى سلسلة أدوات CsWinRT.  2

  17. Microsoft Learn, IInitializeWithWindow interface (shobjidl_core.h). حول كونها واجهة تقدّم نافذة مالك لكائن WinRT يُستخدم في تطبيق سطح مكتب، ووراثتها IUnknown وامتلاكها الدالّة Initialize(HWND). 

  18. Microsoft Learn, Use WinRT COM interop classes in .NET. حول حاجة بعض كائنات WinRT مثل ملتقط الملفّ والحوار إلى HWND قبل العمل في تطبيق سطح مكتب، وإمكان التهيئة بأصناف C# آمنة الأنواع WinRT.Interop.WindowNative وWinRT.Interop.InitializeWithWindow دون استدعاء QueryInterface مكتوب يدوياً.  2

  19. Microsoft Learn, Tutorial: Open files and folders with pickers in WinUI. حول صيرورة استثناء أو فشل صامت عند استخدام Windows.Storage.Pickers التقليدي في تطبيق سطح مكتب (WinUI 3) دون تهيئة بـ HWND قبل العرض، وغياب CoreWindow في تطبيق سطح مكتب WinUI 3، وتلقّي ملتقط Windows App SDK الجديد (Microsoft.Windows.Storage.Pickers) WindowId في المنشئ وعدم لزوم صيغة InitializeWithWindow.  2 3

  20. Microsoft Learn, Features that require package identity. حول تتطلّب بعض وظائف Windows وواجهات WinRT package identity وقت التشغيل، وإمكان الحصول على المعرّف بالإضافة إلى التوزيع بحزمة MSIX بحزمة تشير إلى موقع خارجي (packaged with external location).  2

  21. Microsoft Learn, CoInitialize function (objbase.h). حول تهيئة CoInitialize مكتبة COM كـ STA، ووجوب استدعاء التطبيقات الجديدة CoInitializeEx، ووجوب استدعاء RoInitialize أو Windows::Foundation::Initialize بدلاً منه عند استخدام Windows Runtime. 

  22. GitHub, WinUI: Now Developing in the Open (microsoft/microsoft-ui-xaml Discussion #10700). الإعلان الرسمي نهاية يوليو 2025. حول عرض نهج تدريجي لجعل مستودع WinUI علنياً (رفع تواتر تحديث المرآة، وتحقيق البناء المحلّي، وقبول مساهمات المجتمع بعد ترتيب الاختبارات، وجعل GitHub أخيراً المقرّ الرئيس للتطوير).  2 3

  23. Microsoft Learn, Windows App SDK. حول كون Windows App SDK مجموعة مكتبات تطوير تطبيقات Windows الحالية بما فيها WinUI. 

  24. Microsoft Learn, Walkthrough: WinUI 3 app with Win32 interop. حول توسيع صنف Window في WinUI لدعم نافذة سطح المكتب، وإسناد Window في تطبيق سطح مكتب WinUI 3 بمقبض نافذة Win32 (HWND) وإمكان جلب مقبض النافذة وتشغيله بواجهات Win32. 

  25. Microsoft Learn, Host UWP XAML controls in desktop apps (UWP XAML Islands). حول كون XAML Islands جيل UWP آلية تحميل عناصر UWP XAML في تطبيقات سطح مكتب WPF وWinForms وC++، واقتصار الاستخدام في WPF/WinForms على تطبيقات تستهدف .NET Core 3.x وعدم الدعم في .NET الحالي أو .NET Framework.  2

  26. Microsoft Learn, DesktopWindowXamlSource Class (Microsoft.UI.Xaml.Hosting). حول كونه الصنف المركزي لواجهة استضافة XAML في Windows App SDK، وإمكان استضافة عناصر WinUI في أيّ عنصر واجهة مرتبط بـ HWND، وإمكان الاستخدام من تطبيقات سطح مكتب مصنوعة بـ WPF وWindows Forms وWin32 (Windows API).  2

  27. Microsoft Learn, Quickstart: Sending a toast notification from the desktop. حول افتراض إرسال توست من تطبيق سطح مكتب اختصار قائمة ابدأ مضبوطاً عليه System.AppUserModel.ID، وضرورة تمرير ذلك AppUserModelID إلى استدعاء CreateToastNotifier وإلّا لا يُعرض التوست. 

  28. Microsoft Learn, Use app notifications with a .NET app. حول وجوب استدعاء Register() بعد تسجيل معالج NotificationInvoked لاستخدام AppNotificationManager في Windows App SDK من تطبيق WPF/WinForms، وقيام Register() في تطبيق unpackaged تلقائياً بتسجيل خادم COM لتشغيل التطبيق عند نقر الإشعار، وافتراض إدخال Windows App SDK وتكوين استدعاء واجهات WinRT.  2

أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.

ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.

الأسئلة الشائعة

أسئلة شائعة حول موضوع هذه المقالة.

هل WinRT وقت تشغيل مُدار مثل .NET؟
لا. WinRT (Windows Runtime) ليس بيئة تنفيذ تملك آلة افتراضية أو جامع قمامة؛ بل ABI (عقد ثنائي) قائم على COM. تنصّ وثائق Microsoft نفسها على «The Windows Runtime is based on COM»، وتتطلّب كلّ واجهة WinRT IInspectable المشتق من IUnknown. كيان الاستدعاء لا يزال استدعاء COM عبر vtable، ويقوم على عدّ المراجع (AddRef/Release) وQueryInterface. يسهل سوء الفهم أنّه بيئة مُدارة بسبب اسم «.winmd» والألفة مع .NET، لكن .winmd ملفّ بيانات وصفية يستعير التنسيق المادي نفسه لـ ECMA-335، والـ .winmd المقدَّم من النظام لا يحتوي شيفرة تنفيذ. إمكان الاستدعاء الطبيعي من C# لأن إسقاط اللغة يولّد إسقاطاً نحو C# من البيانات الوصفية.
سمعت أن UWP لم يعد التيار الرئيس. هل لا يزال لتعلّم WinRT معنى الآن؟
نعم. نموذج تطبيق UWP وأساس واجهة WinRT شيئان مختلفان. بعد انكماش UWP ما زالت معظم واجهات WinRT تُقدَّم بشكل يمكن استدعاؤه من تطبيقات سطح المكتب WPF وWinForms وWin32، وكثير من «وظائف Windows الحالية» مثل إشعارات التوست والمشاركة وBluetooth وOCR تُنشر كواجهات WinRT. علاوة على ذلك يقوم WinUI (Windows App SDK)، إطار الواجهة الأصلية الذي توصي به Microsoft حالياً، على ABI الخاص بـ WinRT. أي أن آليات WinRT (IInspectable و.winmd وإسقاط اللغات) ليست إرث UWP بل أساس تطوير تطبيقات Windows الحالي نفسه.
هل يمكن استدعاء واجهات WinRT من تطبيق WPF أو WinForms؟
نعم. من .NET 6 فما بعده يكفي جعل TargetFramework في ملفّ المشروع TFM يحمل إصدار نظام تشغيل Windows مثل net8.0-windows10.0.19041.0، فتُشار تجميعات إسقاط Windows SDK ويمكن استدعاء واجهات WinRT في فضاء الأسماء Windows.* مباشرة من C#. في C++ ثبّت حزمة NuGet Microsoft.Windows.CppWinRT واستخدم C++/WinRT بـ C++17 فما بعده. لكن هناك ثلاثة مواضع انحشار. الأوّل أن أصناف الواجهة التي تفترض CoreWindow مثل أدوات الالتقاط والحوارات تحتاج تمرير HWND نافذة المالك بـ IInitializeWithWindow قبل العرض (لكن DataTransferManager لواجهة المشاركة استثناء: لا يستخدم IInitializeWithWindow بل IDataTransferManagerInterop المخصَّص ويمرّر HWND إلى ShowShareUIForWindow مساراً آخر). الثاني أن بعض الواجهات مثل سجلّ الإشعارات وقائمة القفز تتطلّب package identity (تعبئة MSIX أو حزمة تشير إلى موقع خارجي). الثالث أن الخيط الذي يعالج كائنات WinRT يحتاج تهيئة مسبقة. في الشيفرة الأصلية تحدّد نموذج التزامن STA/MTA بـ winrt::init_apartment أو RoInitialize (وفي تطبيقات C# WPF/WinForms يتولّى وقت التشغيل ذلك عادة). الواجهات التي تعتمد على CoreWindow أو ApplicationView نفسها لا يمكن استخدامها في تطبيقات سطح المكتب أصلاً.
استدعاء ملتقط مثل FolderPicker من تطبيق سطح مكتب يرمي استثناء. لماذا؟
لأن بعض أصناف WinRT لأدوات الالتقاط والحوارات صُمِّمت بافتراض CoreWindow في UWP كوجهة عرض. ليس لتطبيق سطح المكتب CoreWindow، لذا يلزم إخباره بنافذة المالك صراحة قبل العرض. تحديداً اجلب أوّلاً HWND نافذة المالك (لـ Window في WinUI: WinRT.Interop.WindowNative.GetWindowHandle، وفي WPF: WindowInteropHelper، وفي WinForms: خاصّية Handle للنموذج)، وفي C# مرّره إلى الملتقط بـ WinRT.Interop.InitializeWithWindow.Initialize. في C++/WinRT استعلم عن الكائن كـ IInitializeWithWindow (as<IInitializeWithWindow>()) واستدعِ Initialize(hwnd). دون هذه التهيئة يحدث استثناء أو فشل صامت. ملتقطات Windows App SDK الجديدة (Microsoft.Windows.Storage.Pickers) صُمِّمت لتلقّي WindowId في المنشئ، فلم تعد صيغة التهيئة هذه لازمة (لكنّها واجهة Windows App SDK، لذا لا تكفي إعدادات TFM وحدها؛ يفترض إدخال SDK، وللتطبيق unpackaged نشر وقت التشغيل وتهيئته على جهة التوزيع).
يُقال إن تطوير WinUI نُشر على GitHub. هل ينبغي التخلّي عن تطبيقات WPF/WinForms القائمة؟
لا حاجة للتخلّي على عجل. نشر التطوير الرئيس لـ WinUI إعلان اتجاه «Microsoft تستثمر جدّياً في الإطار الأصلي»، وليس إعلان إنهاء الأطر القائمة. ما زال WPF وWinForms مدعومين كجزء من .NET. اقسم الحكم قسمين. الأوّل هل ترحّل إطار الواجهة، وهذا حديث كبير يعتمد على حجم أصول الشاشات وعناصر الطرف الثالث وهيئة التطوير. الثاني هل تستخدم واجهات WinRT جزئياً من التطبيق القائم، وهذا يمكن البدء به اليوم بإعداد TFM. لكن TFM يجعل الاستدعاء ممكناً فقط؛ فإشعارات التوست مثلاً تحتاج بالإضافة إلى الاستدعاء تسجيلاً للإشعار (المسار التقليدي لتطبيق unpackaged تسجيل اختصار بـ AppUserModelID ── وإن كان معبّأ فهوية الحزمة تعطي AppUserModelID فلا يلزم ── ومسار Windows App SDK إدخال SDK ── وللتطبيق unpackaged أيضاً إدخال وقت تشغيل Windows App SDK على كلّ جهاز توزيع ── واستدعاء AppNotificationManager.Register()، وفي تطبيق معبّأ بـ MSIX لا يعمل التسجيل التلقائي بـ Register() ويلزم علاوة على ذلك إعلان منشّط COM في Package.appxmanifest). وفي مسار Windows App SDK الإشعار من عملية ترقّت كمسؤول غير مدعوم، وShow يفشل بهدوء دون استثناء ── لتطبيق يحتاج ترقية انظر في فصل الإشعار إلى عملية غير مُرقّاة. ومع ذلك إن أردت إشعارات توست فقط فلا يلزم الترحيل إلى WinUI. وخلط عناصر WinUI جزئياً في شاشات WPF/WinForms القائمة (XAML Islands) يحتاج تمييز الجيل. Islands جيل UWP يتوقّف دعم WPF/WinForms عند .NET Core 3.x، وفي جيل WinUI 3 يمكن استخدام واجهة استضافة XAML في Windows App SDK (DesktopWindowXamlSource) من WPF/WinForms أيضاً لكن بلا عناصر غلاف مريحة فعبء التنفيذ كبير، لذا التقييم الحذر آمن في الوقت الحالي.

الملف الشخصي للمؤلف

صفحة الملف الشخصي لمؤلف المقالة.

غو كومورا

مؤسّس شركة كومورا سوفت ذ.م.م.

يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.

العودة إلى المدونة