دراسة حالة لجسر COM يستدعي DLL بـ 64bit من تطبيق 32bit

· آخر تحديث: · · COM, تطوير Windows, 32bit, 64bit

سجل التعديلات (5 تحديثات، آخر تحديث 3 Sep، 2026)

سجل بالتغييرات التي أُجريت على هذا المقال. وحيثما حُفظت نسخة سابقة، تبقى متاحة للقراءة عبر رابط دائم يحمل معرّف DOI.

أُضيفت روابط الاستشارة الموجودة في الأصل الياباني (consultation_services). ولم يتغيّر نصّ المقالة نفسه. قراءة النسخة السابقة لهذا التحديث (DOI: 10.5281/zenodo.22242888)
أُصلِحت بقايا يابانية في التعليقات ونص التشخيص ورابط المقالة ذات الصلة. قراءة النسخة السابقة لهذا التحديث (DOI: 10.5281/zenodo.22240794)
أُعيدَت الترجمة العربية كترجمة كاملة عن النص الياباني الأصلي، وأُضيفَت خريطة المعرفة.
أعيدت الترجمة كترجمة كاملة عن النص الياباني الأصلي. كانت النسخة العربية السابقة مختصراً يسقط أبواباً وجداول ورسوم Mermaid وتعليقات الأشكال وFAQ. أُعيدت هذه العناصر وفق الأصل الياباني، والادّعاءات التقنية مطابقة للنسخة اليابانية.
أُضيفت فقرة قبل القسم 3. إذا كان ما تريد الوصول إليه من جهة 64 بت خادم COM من نوع in-proc أصلًا (أي مكتبة DLL مسجَّلة عبر InprocServer32)، فإن إضافة AppID إلى الـ CLSID الخاص بها وكتابة DllSurrogate فارغ تحت ذلك الـ AppID تجعلها تُستضاف داخل dllhost.exe المرفق مع Windows، وقد يغنيك ذلك عن كتابة خادم EXE. وتشير الفقرة أيضًا إلى أن الـ bitness الخاص بالـ surrogate الذي يُشغَّل يتبع المكتبة لا العميل، وأن وجود LocalServer32 مسجَّل يعني أن الـ surrogate لن يُستخدم. أمّا إذا كان المطلوب استدعاء مكتبة أصلية عادية، كما في هذه المقالة، فلا يوجد أصلًا خادم COM لاستضافته، ويبقى أسلوب خادم الـ EXE الموصوف لاحقًا ضروريًا. وقد تُركت خطوات التسجيل والحدّ الفاصل بين ما يكفي فيه الـ surrogate وما يستدعي كتابة EXE خاص بك لروابط تحيل إلى المقالتين الأخريين. قراءة النسخة السابقة لهذا التحديث (DOI: 10.5281/zenodo.21621306)
النشر الأول
الاستشهاد بهذا المقال(DOI: 10.5281/zenodo.21621305)

هذا المقال محفوظ على Zenodo. يرد أدناه معرّف DOI الذي يشير دائمًا إلى أحدث نسخة، ومعرّف DOI المثبَّت على النسخة التي تقرؤها.

小村 豪 (2026). دراسة حالة لجسر COM يستدعي DLL بـ 64bit من تطبيق 32bit. شركة كومورا سوفت ذ.م.م.. https://doi.org/10.5281/zenodo.21621305 https://comcomponent.com/ar/blog/2026/01/25/002-com-case-study-32bit-to-64bit/

DOI (أحدث نسخة)
10.5281/zenodo.21621305
DOI (هذه النسخة)
10.5281/zenodo.22279679

استدعاء DLL بـ 64bit من تطبيق 32bit متطلّب نمطي جدّاً على Windows. وخصوصاً عندما تريد الإبقاء على أصل قائم واستخدام وظائف جانب 64bit فقط، تصير تركيبة جسر COM حلاً واقعياً في الغالب.

الجمهور المستهدف: من يصون تطبيقاً قائماً لـ Windows بـ 32bit ويريد استخدام DLL أو مكتبة في جانب 64bit. النصّ مكتوب ليُقرأ بافتراض أنّك «سمعت بـ COM لكنّك لم تركّبه بنفسك».

بيئة الافتراض: Windows بإصدار 64bit (x64)، وبيئة تطوير تكتب فيها C# (مثل Visual Studio). تسجيل خادم COM على الجهاز كلّه (تحت HKEY_LOCAL_MACHINE) يتطلّب امتيازات المدير. الفكرة الأساسية لـ COM مرتّبة في «ما هو COM - لماذا لا يزال تصميم Windows COM يبدو جميلاً».

المحتويات

  1. الوضع المفترض
  2. طريقة الحلّ
  3. تدفّق المعالجة (مخطّط تسلسل)
  4. عيّنة شيفرة (تصوّر)
  5. عيّنة الشيفرة الكاملة
  6. خلاصة
  7. مراجع

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

1. الوضع المفترض

الحالة: الإبقاء على تطبيق قائم بـ 32bit، مع الرغبة في استخدام معالجة DLL بـ 64bit. غير أنّ عملية 32bit لا تحمّل DLL بـ 64bit. هذا قيد على مستوى نظام التشغيل، لا أمر يُحلّ بالتحايل.

الشائع هو وضع كهذا.

  • التطبيق القائم بـ 32bit أصل كبير، ولا يمكن ترحيله فوراً
  • في جانب DLL بـ 64bit وظيفة جديدة، أو مكتبة تابعة متاحة بـ 64bit فقط
  • تريد الاستدعاء من جانب 32bit «بأنواع»

بهذا الجمع، طريق الاستدعاء داخل العملية نفسها مغلق من البداية.

بنية الوضع المفترضمخطّط يبيّن أنّ تطبيقاً قائماً بـ 32bit يريد استخدام معالجة DLL بـ 64bit، لكنّ عملية 32bit لا تحمّل DLL بـ 64bit بسبب قيد على مستوى نظام التشغيل، فطريق الاستدعاء داخل العملية نفسها مغلق.تطبيق قائم بـ 32bitيريد استخدام معالجة DLL بـ 64bitلا يمكن التحميل داخل العملية نفسهاقيد على مستوى نظام التشغيل لا يُتحايل عليه

الشكل 1: عملية 32bit لا تحمّل DLL بـ 64bit، لذلك لا يوجد من البداية طريق للاستدعاء داخل العملية نفسها.

2. طريقة الحلّ

من هنا تتوالى مصطلحات متخصّصة، فنضع الحدّ الأدنى من الكلمات أوّلاً.

المصطلح المعنى
In-proc COM (خادم DLL) شكل يحمّل مكوّن COM في العملية نفسها مع المستدعي. سريع، لكنّه لا يُحمَّل إن لم يتطابق عدد البتّات
Out-of-proc COM (خادم EXE) شكل يشغّل مكوّن COM كعملية أخرى. يمكن الربط حتى إن اختلف عدد البتّات
LocalServer خادم COM يعمل كعملية أخرى على الجهاز نفسه. يُسجَّل مسار EXE في مفتاح السجلّ LocalServer32
IDL / TypeLib تعريف يكتب شكل الواجهة (أسماء الدوال وأنواع الوسائط) (IDL)، ونسخته الثنائية (TypeLib). يُستخدم حتى يرى الطرفان «العقد» نفسه
marshalling إعادة تعبئة الوسائط والقيم المعادة إلى شكل يمكن إرساله لعبور حدود العملية. العكس هو unmarshalling
Proxy / Stub شيفرة وكيلة تقوم بالـ marshalling فعلاً. يقوم Proxy في جهة المستدعي، وStub في جهة الخادم
WOW6432Node المكان الذي تُوضع فيه فعلياً محتويات السجلّ الموجّهة لتطبيقات 32bit على Windows بـ 64bit. حتى مع اسم المفتاح نفسه يختلف المحتوى بين جانب 32bit وجانب 64bit

أساس الحلّ هو الفصل عبر Out-of-proc COM (خادم EXE). تُستدعى DLL بـ 64bit من خادم COM (EXE) بـ 64bit، ويستخدمها تطبيق 32bit عبر COM.

التركيبة الأساسية لجسر COMمخطّط يبيّن تركيبة الفصل إلى عملية أخرى: تطبيق 32bit يستدعي EXE خادم COM بـ 64bit عبر COM، وذلك الخادم يستدعي داخلياً DLL بـ 64bit.يستدعي عبر COMيستدعي داخلياًتطبيق 32bitخادم COM بـ 64bit (EXE)DLL بـ 64bit

الشكل 2: تُحمَل DLL بـ 64bit في خادم EXE بـ 64bit، ويستخدم تطبيق 32bit ذلك الخادم عبر COM.

التدفّق كالتالي.

  1. تجهيز COM LocalServer (EXE) بـ 64bit، واستدعاء DLL بـ 64bit من داخله
  2. مشاركة واجهة COM (IDL/TypeLib) ونشر الأنواع
  3. يستدعي تطبيق 32bit COM «بأنواع» (التبادل عبر Proxy/Marshal)

غير أنّ هناك نقاط انتباه.

  • تسجيل 32bit/64bit منفصل (بما فيه WOW6432Node)
  • البنى المخصّصة تحتاج تصميم marshalling
  • توجد تكلفة IPC، فالحذر من الاستدعاء عالي التكرار

أي أنّ المسار المعتمد هو «تهريب معالجة 64bit إلى عملية أخرى، والجسر إليها عبر COM».

ثلاث خطوات لتركيب الجسرمخطّط يبيّن تدفّق ثلاث خطوات: تجهيز COM LocalServer بـ 64bit واستدعاء DLL بـ 64bit من داخله، ونشر أنواع الواجهة بـ IDL وTypeLib، ثم استدعاء تطبيق 32bit بأنواع.تجهيز COM LocalServer بـ 64bitنشر الأنواع بـ IDL / TypeLibتطبيق 32bit يستدعي بأنواعالتبادل عبر Proxy / Marshal

الشكل 3: يكتمل الجسر بثلاث مراحل: تجهيز LocalServer، ونشر الأنواع، والاستدعاء ذي الأنواع.

علماً بأنّه إذا كان ما تريد استخدامه في جانب 64bit خادم COM من نوع in-proc أصلاً (DLL تُسجَّل عبر InprocServer32)، فقد تستغني عن كتابة خادم EXE. إذا أضفتَ AppID إلى CLSID وكتبتَ DllSurrogate بسلسلة فارغة تحت مفتاح AppID ذاك، تُحمَّل تلك الـ DLL داخل عملية الـ surrogate المرفقة مع Windows (System32\dllhost.exe إن كانت الـ DLL بـ 64bit)، وتبدو لعميل 32bit كخادم COM من نوع out-of-proc يعمل في عملية أخرى (هذا ليس تسجيل مسار EXE في LocalServer32. بل على العكس، وجود LocalServer32 يمنع استخدام الـ surrogate). الآلية نفسها تنطبق في الاتجاه المعاكس (استخدام COM DLL بـ 32bit من تطبيق بـ 64bit)، ويتحدّد bitness الـ surrogate الذي يُشغَّل من جانب الـ DLL لا من جانب العميل. غير أنّه إن كان ما تريد استدعاءه مجرّد DLL أصلية كما في هذا المقال، فلا يوجد أصلاً خادم COM يُحمَّل في الـ surrogate، لذلك يلزم أسلوب خادم EXE المشروح فيما يلي. خطوات التسجيل مجموعة في القسم 3.5 من مطبات شائعة في تطوير مكوّنات COM وOCX / ActiveX - فخاخ Visual Studio بين 32-bit و64-bit والتسجيل وامتيازات المدير (مكتوب بافتراض DLL بـ 32bit، فيكفي أن تعكس الـ view الذي تُكتب فيه قيمة AppID)، والخطّ الفاصل بين ما يكفي فيه الـ surrogate وما يستوجب كتابة EXE خاص بك مجموعة في كيف تتعامل مع ActiveX / OCX اليوم - جدول قرار للإبقاء والتغليف والاستبدال في القسم 5.2.

3. تدفّق المعالجة (مخطّط تسلسل)

فيما يلي تدفّق الاستدعاء عندما يستدعي تطبيق 32bit معالجة داخل DLL بـ 64bit.

تعالجها بنية marshalling في COM بعد التسجيل64bit DLL64bit COM Server(EXE)COM Stub(جانب 64bit)RPC/IPC(تواصل بين العمليات)COM Proxy(جانب 32bit)تطبيق عميل 32bit64bit DLL64bit COM Server(EXE)COM Stub(جانب 64bit)RPC/IPC(تواصل بين العمليات)COM Proxy(جانب 32bit)تطبيق عميل 32bitmarshalling للوسائطunmarshalling للوسائطmarshalling للقيمة المعادةunmarshalling للقيمة المعادةICalcService.Add(1, 2)بيانات مُسَلسَلةنقل عبر حدود العمليةAdd(1, 2)استدعاء دالة أصليةالنتيجة: 3النتيجة: 3نتيجة مُسَلسَلةنقل عبر حدود العمليةالنتيجة: 3

الشكل 4: استدعاء تطبيق 32bit يصل إلى خادم 64bit وDLL بـ 64bit عبر Proxy والتواصل بين العمليات وStub، وتعود النتيجة بالمسار نفسه.

النقاط الجوهرية:

  • يستطيع تطبيق 32bit الاستدعاء بأمان الأنواع عبر واجهة ICalcService
  • يعبر زمن تشغيل COM حدود العملية باستخدام Proxy/Stub DLL المسجّلة، وmarshaller لـ TypeLib، والـ marshaller القياسي، وغيرها
  • توجد تكلفة تواصل بين العمليات، لذلك يُفضَّل التجميع على الاستدعاءات الدقيقة
فكرة حبيبات الاستدعاءمخطّط يبيّن الفكرة: للتواصل بين العمليات تكلفة، فتتراكم إن تكرّرت الاستدعاءات الدقيقة بتكرار عالٍ، ويُفضَّل التجميع لتقليل الأثر.تكلفة التواصل بين العملياتتتراكم بتكرار الاستدعاءات الدقيقةيقلّ الأثر إذا مِلت إلى التجميعهذا هو المرغوب

الشكل 5: كلّ عبور لحدود العملية له تكلفة، لذلك يُفضَّل تجميع الاستدعاءات بحبيبات أخشن.

4. عيّنة شيفرة (تصوّر)

4.1. الواجهة المشتركة والخادم والعميل

فيما يلي تصوّر للفكرة. للتشغيل تحتاج تسجيل القسم 4.2 بعد هذا.

// الواجهة المشتركة (تعادل IDL)
[ComVisible(true)]
[Guid("7A4B5B23-0A2F-4D2B-9D4D-8A2A92B8B001")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICalcService
{
    int Add(int a, int b);
}

// خادم COM LocalServer بـ 64bit (جانب EXE)
[ComVisible(true)]
[Guid("1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("KomuraSoft.CalcService")]
public class CalcService : ICalcService
{
    public int Add(int a, int b)
    {
        // استدعِ DLL بـ 64bit هنا
        return a + b;
    }
}

// جانب تطبيق 32bit (العميل)
Type t = Type.GetTypeFromProgID("KomuraSoft.CalcService");
var calc = (ICalcService)Activator.CreateInstance(t);
int result = calc.Add(1, 2);

بهذا الشكل يتعامل جانب 32bit «بأنواع». يستخدم COM داخلياً الوكيل/الـ stub ويستدعي عبر IPC.

سبب إضافة [ProgId("KomuraSoft.CalcService")] هو تمكين العميل من البحث بـ Type.GetTypeFromProgID("KomuraSoft.CalcService"). ProgID مجرّد «اسم بديل يقرأه الإنسان»، وما يجد الخادم فعلاً هو تسجيل CLSID المشروح تالياً.

من ProgID حتى الوصول إلى الخادممخطّط يبيّن ترتيب الحلّ: ProgID الذي يحدّده العميل مجرّد اسم بديل يقرأه الإنسان، ومنه يُستخرج CLSID، وبتسجيل CLSID يُعثر على الخادم الفعلي.ProgID (اسم بديل يقرأه الإنسان)تسجيل CLSIDيُعثر على الخادم

الشكل 6: ProgID اسم بديل عند المدخل، وما يشير إلى الخادم فعلاً هو تسجيل CLSID.

4.2. الحدّ الأدنى من خطوات التسجيل

COM آلية «يسحب فيها زمن تشغيل COM CLSID المسجّل في السجلّ ويشغّله»، لذلك شيفرة غير مسجّلة لا تعمل أبداً (Type.GetTypeFromProgID يعيد null، أو CreateInstance يعطي REGDB_E_CLASSNOTREG). تسجيل خادم EXE (LocalServer) يُختصر إلى المفاتيح الثلاثة التالية.

ما يُسجَّل المفتاح القيمة
تقابل ProgID ← CLSID HKEY_CLASSES_ROOT\KomuraSoft.CalcService\CLSID {1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11}
CLSID ← مسار EXE HKEY_CLASSES_ROOT\CLSID\{1C9B6F4D-…}\LocalServer32 المسار الكامل لـ EXE خادم COM بـ 64bit
البحث العكسي CLSID ← ProgID HKEY_CLASSES_ROOT\CLSID\{1C9B6F4D-…}\ProgID KomuraSoft.CalcService

وهنا الفخّ الذي هو موضوع المقال نفسه. وثائق Microsoft تنصّ على أنّ HKEY_LOCAL_MACHINE\SOFTWARE\Classes مشترك بين تطبيقات 32bit و64bit، بينما مفتاح CLSID الفرعي تحته (وInterface وغيرها) منفصل بين جانب 32bit وجانب 64bit (كيان جانب 32bit هو WOW6432Node). أي أنّ مفتاح ProgID إن كُتب مرّة يُرى من الاثنين، أمّا تسجيل CLSID إن لم يُكتب في الـ view بـ 32bit والـ view بـ 64bit معاً، فلن يجد عميل 32bit الخادم.

الجزء المشترك من السجلّ والجزء المنفصلمخطّط يبيّن أنّ مفتاح ProgID تحت Classes مباشرة إن كُتب مرّة يُرى من 32bit و64bit، بينما التسجيل تحت CLSID منفصل بين view بـ 64bit وview بـ 32bit فيلزم الكتابة في الاثنين، وإن نقص جانب 32bit لا يرى عميل 32bit الخادم.مفتاح ProgID (تحت Classes مباشرة)يُرى من الاثنينالتسجيل تحت CLSIDيُكتب في الـ view بـ 64bitيُكتب في الـ view بـ 32bitالكيان هو WOW6432Nodeإن نقص لا يُرى من 32bit

الشكل 7: مفتاح ProgID مشترك، أمّا ما تحت CLSID فمنفصل لكلّ view بـ 32bit/64bit، لذلك يُسجَّل في الاثنين.

الأضمن في موجه أوامر بامتيازات المدير استخدام /reg:32 و/reg:64 لأمر reg (كتابة Wow6432Node بنفسك في المسار غير مستحسن عند Microsoft).

:: نفِّذ في موجه أوامر بامتيازات المدير
set CLSID={1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11}
set PROGID=KomuraSoft.CalcService
set SERVER=C:\Program Files\KomuraSoft\CalcServer.exe

:: 1) ProgID → CLSID (ما تحت HKLM\SOFTWARE\Classes مباشرة مشترك بين 32/64)
reg add "HKLM\SOFTWARE\Classes\%PROGID%\CLSID" /ve /d "%CLSID%" /f

:: 2) CLSID → LocalServer32 و ProgID (ما تحت CLSID منفصل لـ 32/64 فاكتبه في الاثنين)
::    قيمة LocalServer32 تُدخل مسار الملف التنفيذي مع علامات الاقتباس.
::    إن كتبت /d "%SERVER%" تختفي علامات الاقتباس في تحليل وسائط reg.exe، وتُخزَّن القيمة
::    كما هي C:\Program Files\... . يفسّرها COM كسطر أوامر
::    فيبحث أولاً عن C:\Program.exe المقطوع قبل الفراغ
reg add "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\LocalServer32" /ve /d "\"%SERVER%\"" /f /reg:64
reg add "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\ProgID"        /ve /d "%PROGID%"     /f /reg:64
reg add "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\LocalServer32" /ve /d "\"%SERVER%\"" /f /reg:32
reg add "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\ProgID"        /ve /d "%PROGID%"     /f /reg:32

:: تحقّق من القيمة المخزَّنة. إن ظهرت "C:\Program Files\..." مع علامات الاقتباس فهي صحيحة
reg query "HKLM\SOFTWARE\Classes\CLSID\%CLSID%\LocalServer32" /ve /reg:64

علامات الاقتباس في LocalServer32 ليست مجرّد مسألة أدب. بدونها يمكن تفسير C:\Program Files\... على أنّه «تمرير Files\... كوسيط إلى C:\Program». والنتيجة أنّه في بيئة يملك فيها طرف صلاحية إنشاء C:\Program.exe قد يُشغَّل ذلك أوّلاً. إذا وضعتَ مساراً فيه فراغ فأرفق علامات الاقتباس حتماً.

كيف يتغيّر التفسير بوجود علامات اقتباس LocalServer32 أو غيابهامخطّط يبيّن أنّ تخزين المسار في قيمة LocalServer32 بلا علامات اقتباس يتيح تفسيراً يقطع قبل الفراغ، وقد يُشغَّل C:\Program.exe أوّلاً في بيئة يمكن وضع ذلك الملفّ فيها، بينما التخزين مع علامات الاقتباس يشغّل EXE المقصود.تخزين بلا علامات اقتباسيصحّ تفسير يقطع قبل الفراغقد يُشغَّل C:\Program.exe أوّلاًتخزين مع علامات الاقتباسيُشغَّل EXE المقصود

الشكل 8: تسجيل مسار فيه فراغ بلا علامات اقتباس يفتح مجالاً لتشغيل ملفّ تنفيذي آخر.

الإلغاء مجرّد حذف المفاتيح نفسها.

set CLSID={1C9B6F4D-1E9A-4E61-9A4F-6A0F1D2D9A11}
set PROGID=KomuraSoft.CalcService

reg delete "HKLM\SOFTWARE\Classes\CLSID\%CLSID%" /f /reg:64
reg delete "HKLM\SOFTWARE\Classes\CLSID\%CLSID%" /f /reg:32
reg delete "HKLM\SOFTWARE\Classes\%PROGID%" /f

إضافة إلى ذلك، على جانب EXE عند التشغيل أن يعلن لـ COM «أنا المسؤول عن هذا CLSID». في C/C++ هذا CoRegisterClassObject، وفي .NET Framework RegistrationServices.RegisterTypeForComClients. تسجيل السجلّ لا يرعى إلا حتى تشغيل COM للـ EXE، فإن سقط هذا الإعلان تحصل على فشل مربك: الـ EXE يعمل لكن لا يُنشأ الكائن.

تسجيل السجلّ وإعلان جانب EXEمخطّط يبيّن أنّ تسجيل السجلّ يرعى حتى تشغيل COM للـ EXE، ولا يُنشأ الكائن إلا بعد أن يعلن EXE المشغَّل أنّه المسؤول عن هذا CLSID، وإن سقط الإعلان يفشل الإنشاء رغم تشغيل EXE.إن سقط الإعلانتسجيل السجلّCOM يشغّل EXEEXE يعلن أنّه مسؤول CLSIDيمكن إنشاء الكائنفشل: يعمل لكن لا يُنشأ

الشكل 9: تسجيل السجلّ يصل إلى تشغيل EXE، وما بعده لا يُنشئ الكائن دون إعلان EXE نفسه.

علماً بأنّه للتجربة أثناء التطوير يمكنك الكتابة بالبنية نفسها في HKCU\SOFTWARE\Classes بدل HKLM دون امتيازات مدير (HKEY_CLASSES_ROOT هو view مركّب من HKLM وHKCU). غير أنّ HKCU\SOFTWARE\Classes\CLSID يُعامل أيضاً معاملة منفصلة بين 32bit/64bit، لذلك لا يتغيّر لزوم الكتابة في الـ viewين.

4.3. طريقة البناء تختلف بين .NET Framework و.NET (5 وما بعده)

الشيفرة أعلاه C#، لكن الخطوات تتغيّر كثيراً بحسب أيّ .NET تستخدم. الخلط هنا يوقعك في مأزق.

  .NET Framework .NET (Core 3.0 / 5 وما بعده)
أداة التسجيل يوجد RegAsm.exe (لكنّ ما يُنشأ هو تسجيل InprocServer32 لـ in-proc، لذلك تكتب LocalServer32 بنفسك في النهاية) لا توجد أداة تعادل RegAsm
النشر القياسي لـ COM صفات على التجميعة ثمّ RegAsm توليد *.comhost.dll بـ <EnableComHosting>true</EnableComHosting> والتسجيل بـ regsvr32 (in-proc فقط)
توليد TypeLib (‎.tlb) يمكن التوليد بـ TlbExp / RegAsm /tlb غير مدعوم. تكتب IDL يدوياً وتترجمه بـ MIDL (من .NET 6 يمكن تضمين ‎.tlb الجاهز في comhost)
تحديد CLSID يمكن حذفه التصريح بـ CLSID إلزامي للأصناف التي يولّدها COM
معاملة AnyCPU يمكن استخدامه من عملاء 32bit و64bit *.comhost.dll المرفق 64bit افتراضياً، لذلك لا يُستخدم إلا من عميل 64bit

تركيبة هذا المقال (خادم EXE) خارج نطاق EnableComHosting القياسي في .NET (5 وما بعده)، لذلك تكتب معالجة التسجيل بنفسك. عيّنة Microsoft الرسمية OutOfProcCOM نقطة انطلاق إن ركّبت في جانب .NET.

المسار عند تركيب خادم EXE في .NET (5 وما بعده)مخطّط يبيّن المسار: تركيبة خادم EXE في هذا المقال خارج نطاق EnableComHosting القياسي في .NET 5 وما بعده، لذلك تكتب معالجة التسجيل بنفسك، وعيّنة OutOfProcCOM الرسمية نقطة الانطلاق.خادم EXE في .NET (5 وما بعده)خارج نطاق EnableComHosting القياسيتكتب معالجة التسجيل بنفسكعيّنة OutOfProcCOM الرسمية نقطة الانطلاق

الشكل 10: خادم EXE في .NET (5 وما بعده) خارج نطاق الوظيفة القياسية، لذلك تفترض كتابة معالجة التسجيل بنفسك.

5. عيّنة الشيفرة الكاملة

عيّنة تنفّذ الفكرة أعلاه بشكل يعمل فعلاً منشورة على GitHub.

Call64bitDLLFrom32bitProc - GitHub

يتضمّن المستودع ما يلي:

  • Call64bitDLLFrom32bitProc/ - COM LocalServer بـ 64bit (EXE)
  • X64DLL/ - DLL بـ 64bit (المعالجة الفعلية)
  • X86App/ - عميل 32bit (WinForms)
  • scripts/ - سكربتات تسجيل خادم COM وإلغائه

إذا بنيتَ وسجّلت وفق خطوات README يمكنك التحقّق فعلاً من استدعاء DLL بـ 64bit من عملية 32bit.

6. خلاصة

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

حالات مناسبة حالات غير مناسبة
لا يمكن إعادة بناء تطبيق 32bit نفسه (تكلفة التعديل لا تتناسب) يمكن أصلاً إعادة بناء جانب 32bit بـ 64bit (هذا الأقصر)
الاستدعاء بحبيبات خشنة (صورة واحدة لكلّ استدعاء، أو ملفّ واحد لكلّ استدعاء، إلخ) تدوير استدعاءات دقيقة بتكرار عالٍ، مثل عشرات الآلاف عنصراً عنصراً (تكلفة IPC تصير مهيمنة)
ما يُتبادل أرقام أو سلاسل أو مصفوفات وأنواع يسهل عمل marshalling لها ذهاب وإياب كثير لمؤشّرات خام أو بنى مخصّصة معقّدة
تريد إبقاء التطبيق نفسه حيّاً حتى إن سقطت معالجة جانب 64bit (فصل العملية مزيّة) لا تريد كتابة معالجة استعادة لتعطّل الخادم أو إعادة تشغيله
تريد الإبقاء على استدعاء ذي أنواع (IntelliSense وفحص وقت الترجمة) يكفي معالجة دفعية لمرّة واحدة، والتمرير عبر الإدخال/الإخراج القياسي أو ملفّ كافٍ

كقلب الصفّ الأخير، يستحقّ دائماً النظر في البديل الساذج: «جعل معالجة جانب 64bit مجرّد EXE لوحدة تحكّم، والتبادل بالوسائط والملفّات». جسر COM ينفع عندما تريد الإبقاء على استدعاء ذي أنواع، وعندما تريد استدعاء خادم يحمل حالة مرّات كثيرة.

نقطة الانفصال بين جسر COM والبديل الساذجمخطّط يبيّن نقطة الانفصال: إن لزم الإبقاء على استدعاء ذي أنواع أو استدعاء خادم يحمل حالة مرّات كثيرة ينفع جسر COM، وإن كفت معالجة دفعية لمرّة واحدة يستحقّ النظر في بديل ساذج يجعل الأمر EXE لوحدة تحكّم ويتبادل بالوسائط والملفّات.نعملاهل يلزم استدعاء ذو أنواع أو الاحتفاظ بالحالة؟جسر COMEXE لوحدة تحكّم وتبادل بالوسائط والملفّات

الشكل 11: لزوم الاستدعاء ذي الأنواع والاحتفاظ بالحالة هو نقطة الانفصال بين الجسر والبديل الساذج.

كخطوة تالية نوصي بهذا الترتيب.

  1. أوّلاً استنسخ مستودع العيّنة في الباب 5، وابنِ وسجّل وفق README، واصنع لديك حالة واحدة تعمل.
  2. اختر دالة واحدة من DLL بـ 64bit لديك، وأضف إلى العيّنة دالة واحدة في واجهة تعادل ICalcService، وأمرّرها.
  3. إذا مرّت، قِس عدد الاستدعاءات وحجم البيانات لكلّ مرّة. إن أنهيت هنا حكم التصميم «الميل إلى حبيبات أخشن» (جمع استدعاءات متعدّدة في واحد) أوّلاً، قلّ الرجوع لاحقاً.

7. مراجع

  • نظرة عامّة على Component Object Model (COM) https://learn.microsoft.com/en-us/windows/win32/com/component-object-model–com–portal
  • تسجيل COM LocalServer32 https://learn.microsoft.com/en-us/windows/win32/com/localserver32
  • أساسيات واجهة COM https://learn.microsoft.com/en-us/windows/win32/com/the-component-object-model
  • COM Interop (الاستخدام من .NET) https://learn.microsoft.com/en-us/dotnet/standard/native-interop/cominterop
  • موجّه سجلّ WOW64 (HKLM\SOFTWARE\Classes مشترك، وما تحت CLSID منفصل بين 32/64) https://learn.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys
  • نشر مكوّنات .NET (Core / 5 وما بعده) إلى COM https://learn.microsoft.com/en-us/dotnet/core/native-interop/expose-components-to-com

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

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

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

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

هل يمكن استدعاء DLL بـ 64bit مباشرة من تطبيق 32bit؟
لا. عملية 32bit لا تحمّل DLL بـ 64bit، وهذا قيد على مستوى نظام التشغيل، لا أمر يمكن التحايل عليه. طريق الاستدعاء داخل العملية نفسها مغلق من البداية، لذلك يلزم فصل معالجة جانب 64bit إلى عملية أخرى.
كيف تستخدم وظائف DLL بـ 64bit من تطبيق 32bit؟
الفصل عبر Out-of-proc COM (خادم EXE) هو المسار المعتمد. تُستدعى DLL بـ 64bit من COM LocalServer (EXE) بـ 64bit، ويستخدمها تطبيق 32bit عبر واجهة COM بأنواع. تُشارَك واجهة COM (IDL/TypeLib) لنشر الأنواع، ويتولّى زمن تشغيل COM عبور الحدود بالوكيل/الـ stub والتواصل بين العمليات.
ما نقاط الانتباه في تركيبة جسر COM؟
ثلاث نقاط رئيسة. تسجيل 32bit/64bit منفصل (بما فيه WOW6432Node)، والبنى المخصّصة تحتاج تصميم marshalling، وهناك تكلفة تواصل بين العمليات تستدعي الحذر من الاستدعاءات الدقيقة عالية التكرار. الأفضل تجميع العمل دفعة واحدة بدل تمرير استدعاءات صغيرة كثيرة.
هل توجد عيّنة شيفرة تعمل فعلاً؟
نعم. مستودع Call64bitDLLFrom32bitProc على GitHub ينشر عيّنة كاملة تضمّ COM LocalServer (EXE) بـ 64bit، وDLL بـ 64bit، وعميلاً 32bit (WinForms)، وسكربتات تسجيل خادم COM وإلغائه. إذا بنيتَ وسجّلت وفق خطوات README يمكنك التحقّق من استدعاء DLL بـ 64bit من عملية 32bit.

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

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

غو كومورا

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

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

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