0Pricing
C# Academy · درس

التعامل البيني مع COM والتغليفات القابلة للاستدعاء من وقت التشغيل

استهلك مكوّنات COM من C# باستخدام RCW، واستورد مكتبات الأنواع، وتعامَل مع استثناءات HRESULT

التعامل البيني مع COM والتغليفات القابلة للاستدعاء من وقت التشغيل درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 4 دروس في المجموع.

ما المقصود بتكامل COM؟

إن COM (Component Object Model) معيار واجهة ثنائية قديم من Microsoft، ولا يزال مستخدمًا في Office وWindows Shell وواجهات DirectX البرمجية القديمة والعديد من أدوات المؤسسات. يستطيع .NET استخدام مكونات COM عبر أغلفة التكامل التي تترجم بين الكائنات المُدارة وواجهات COM.

الأغلفة القابلة للاستدعاء وقت التشغيل (RCW)

عند الوصول إلى كائن COM من .NET، ينشئ CLR غلافًا قابلًا للاستدعاء وقت التشغيل (RCW)، وهو وكيل مُدار يغلّف كائن COM. ويتولى RCW تلقائيًا عدّ المراجع، عبر AddRef/Release، والتعامل مع خيوط apartment، وإجراء marshaling بين أنواع COM و.NET.

// The RCW is created automatically when you instantiate a COM class
// via a registered ProgID or CLSID

// Example: create an Excel Application COM object
Type excelType = Type.GetTypeFromProgID("Excel.Application")!;
object excelApp = Activator.CreateInstance(excelType)!;

// excelApp is an RCW — the CLR wraps the underlying IDispatch COM object
// COM AddRef is called; CLR tracks references
Console.WriteLine(excelApp.GetType().Name); // ApplicationClass

استيراد مكتبات الأنواع (TLB)

تقرأ أداة tlbimp.exe (مستورد مكتبة الأنواع) مكتبة أنواع COM، سواء كانت .tlb أو مضمّنة في .dll، وتنشئ تجميعة تكامل لـ .NET تحتوي على فئات RCW مكتوبة بقوة وتعريفات للواجهات.

// From a Developer Command Prompt:
// tlbimp MyComLib.dll /out:MyComLib.Interop.dll

// Or reference via Visual Studio:
// Add Reference → COM → Microsoft Excel 16.0 Object Library
// → Generates Microsoft.Office.Interop.Excel.dll automatically

// The generated Interop assembly contains:
// - Interface types (matching COM vtable layout)
// - Co-class wrappers (implement the interfaces)
// - Enum types (from the type library)
// - Delegate types for COM event sinks

استخدام كائن COM عبر تجميعة التكامل

بعد الإشارة إلى تجميعة التكامل، تبدو أنواع COM مثل أنواع .NET العادية. ويُترجم استدعاء الدالة عبر RCW إلى إرسال عبر vtable في COM. احرص دائمًا على تحرير كائنات COM بطريقة صحيحة لتجنب تسرّب الموارد.

using Microsoft.Office.Interop.Excel;

Application excel = new Application();
excel.Visible = false;

Workbooks books = excel.Workbooks;
Workbook wb = books.Add();
Worksheet ws = (Worksheet)wb.Sheets[1];

((Range)ws.Cells[1, 1]).Value = "Hello, COM!";
wb.SaveAs(@"C:\Temp\test.xlsx");
wb.Close();

// Release COM RCW explicitly
Marshal.ReleaseComObject(ws);
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(books);
excel.Quit();
Marshal.ReleaseComObject(excel);

Marshal.ReleaseComObject

يستخدم COM عدّ المراجع، عبر AddRef/Release. ولا يستدعي RCW الدالة Release إلا بعد جمعه بواسطة GC، وقد يحدث ذلك بعد وقت طويل. استدعِ Marshal.ReleaseComObject() لخفض عدد مراجع RCW فورًا وتحرير كائن COM دون انتظار GC.

// Pattern: release COM objects in finally block
Application? excel = null;
Workbook? wb = null;
try
{
    excel = new Application();
    wb = excel.Workbooks.Add();
    // ... do work ...
}
finally
{
    if (wb   != null) Marshal.ReleaseComObject(wb);
    if (excel != null)
    {
        excel.Quit();
        Marshal.ReleaseComObject(excel);
    }
    // Force GC to clean up any remaining RCWs
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

HRESULT واستثناءات COM

تُرجع دوال COM قيم HRESULT للإشارة إلى النجاح أو الفشل. ويفحص RCW قيمة HRESULT تلقائيًا ويطرح استثناء COMException، أو استثناءً أكثر تحديدًا، عند الإشارة إلى الفشل. ويمكنك معالجتها باستخدام try/catch المعتاد.

try
{
    // COM method that might fail
    Workbook wb = excel.Workbooks.Open(@"C:\missing.xlsx");
}
catch (COMException ex) when (ex.HResult == unchecked((int)0x800A03EC))
{
    // Excel-specific HRESULT for file not found
    Console.WriteLine($"Excel error: {ex.Message}");
}
catch (COMException ex)
{
    // General COM failure
    Console.WriteLine($"COM error 0x{ex.HResult:X8}: {ex.Message}");
}

الربط المتأخر باستخدام dynamic

إذا لم تتوفر لديك مكتبة أنواع أو تجميعة تكامل، يمكنك استخدام الكلمة المفتاحية dynamic في C# لإجراء إرسال COM مرتبط متأخرًا عبر IDispatch. وهذا أبطأ، إذ تُحل معرّفات الإرسال وقت التشغيل، لكنه لا يتطلب أغلفة مولّدة.

// Late-bound COM via dynamic — no interop DLL needed
Type type = Type.GetTypeFromProgID("Word.Application")!;
dynamic word = Activator.CreateInstance(type)!;

word.Visible = false;
dynamic docs = word.Documents;
dynamic doc = docs.Add();

doc.Content.Text = "Late-bound COM example";
doc.SaveAs2(@"C:\Temp\test.docx");
doc.Close();
word.Quit();

Marshal.ReleaseComObject(doc);
Marshal.ReleaseComObject(docs);
Marshal.ReleaseComObject(word);

مستقبلات أحداث COM

تطلق كائنات COM الأحداث عبر نقاط الاتصال. وتنشئ تجميعة التكامل واجهات مستقبلات الأحداث. ويمكنك الاشتراك باستخدام المفوضات والأحداث العادية في .NET، بينما يتولى RCW إعدادات COM الخاصة بـ IConnectionPoint.

using Microsoft.Office.Interop.Excel;

Application excel = new Application();
excel.Visible = true;

// Subscribe to COM event via generated event wrapper
excel.WorkbookBeforeClose += (wb, ref cancel) =>
{
    Console.WriteLine($"Closing: {wb.Name}");
    // Set cancel = true to prevent close
};

excel.WorkbookOpen += (wb) =>
{
    Console.WriteLine($"Opened: {wb.Name}");
};

// Open a workbook to trigger events
excel.Workbooks.Open(@"C:\Temp\test.xlsx");

شقق COM: STA مقابل MTA

تتطلب العديد من مكونات COM، ولا سيما المكونات المرتبطة بواجهة المستخدم مثل Office، شقة أحادية الخيط (STA). احرص دائمًا على تمييز الخيوط التي تنشئ كائنات COM من نوع STA باستخدام [STAThread] في Main، أو عيّن حالة apartment للخيط قبل تشغيله.

// Console apps default to MTA — COM Office automation requires STA
// Option 1: Mark Main with [STAThread]
[STAThread]
static void Main()
{
    var excel = new Microsoft.Office.Interop.Excel.Application();
    // ...
}

// Option 2: Run on an STA thread manually
Thread staThread = new Thread(() =>
{
    var excel = new Microsoft.Office.Interop.Excel.Application();
    // ...
    excel.Quit();
    Marshal.ReleaseComObject(excel);
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();

ComImport والتصريحات اليدوية لـ COM

يمكنك تعريف واجهات COM يدويًا باستخدام السمات [ComImport] و[Guid] و[InterfaceType]، وهذا مفيد عند عدم وجود مكتبة أنواع أو عند الحاجة إلى جزء محدود فقط من واجهة COM البرمجية الكبيرة.

[ComImport]
[Guid("00000000-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IUnknown
{
    void QueryInterface(ref Guid riid, out IntPtr ppvObject);
    int  AddRef();
    int  Release();
}

// Declare a specific COM interface you want to consume:
[ComImport]
[Guid("0000010C-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPersist
{
    void GetClassID(out Guid pClassID);
}

اختبار سريع

ما الغرض من الغلاف القابل للاستدعاء وقت التشغيل (RCW) في تكامل COM مع .NET؟

مراجعة: تكامل COM والأغلفة القابلة للاستدعاء وقت التشغيل

أهم النقاط:

  • RCW هو وكيل مُدار يغلّف كائن COM؛ وينشئ CLR واحدًا تلقائيًا لكل كائن COM
  • استخدم tlbimp.exe أو مراجع Visual Studio لإنشاء تجميعات تكامل مكتوبة بقوة
  • استدعِ Marshal.ReleaseComObject() لتحرير كائنات COM فورًا، دون انتظار GC
  • تظهر أخطاء COM في صورة COMException مع قيمة HRESULT الأصلية
  • يتيح dynamic الإرسال المتأخر إلى COM دون تجميعة تكامل
  • تتطلب مكونات COM الخاصة بـ Office وواجهة المستخدم خيط STA؛ استخدم [STAThread] أو عيّن حالة apartment

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

هل درس «التعامل البيني مع COM والتغليفات القابلة للاستدعاء من وقت التشغيل» مجاني؟

نعم — نص درس «التعامل البيني مع COM والتغليفات القابلة للاستدعاء من وقت التشغيل» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 4 دروس في المجموع.

ماذا ستتعلم في «التعامل البيني مع COM والتغليفات القابلة للاستدعاء من وقت التشغيل»؟

استهلك مكوّنات COM من C# باستخدام RCW، واستورد مكتبات الأنواع، وتعامَل مع استثناءات HRESULT تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟

لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «التعامل البيني مع COM والتغليفات القابلة للاستدعاء من وقت التشغيل»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟

نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. أساسيات P/Invoke
  2. LibraryImport وP/Invoke المولّد من المصدر
  3. التعليمات البرمجية غير الآمنة والمؤشرات والمخازن المؤقتة الثابتة
  4. التعامل البيني مع COM والتغليفات القابلة للاستدعاء من وقت التشغيل
← العودة إلى C# Academy