كيف تستخدم DLL الخاصّة بـ .NET 8 من VBA بـ early binding عبر COM و dscom
لا تزال هناك حالات اعتياديّة كثيرة تحتاج فيها VBA إلى استدعاء كود .NET 8.
ينطبق ذلك خاصّةً عندما يبقى حلّ Excel أو Access في مكانه، لكنّ الفريق يريد نقل المنطق الأثقل إلى C#:
- المعالجة الباهظة
- معالجة النصوص
- عمل HTTP
- التشفير
- منطق العمل الذي لم يعد ينتمي إلى كود الماكرو
إن بقي كلّ شيء late-bound عبر CreateObject، فإنّ VBA تتحوّل بسرعة إلى مستنقع من متغيّرات Object وافتراضات قائمة على النصوص. تضعف IntelliSense، وتبقى أخطاء أسماء الـ methods حتى وقت التنفيذ، ويصبح الكود أصعب في الوثوق به.
لذا فإنّ هذا المقال يُضيّق المشكلة عن قصد:
كشف DLL الخاصّة بـ .NET 8 عبر COM، وتوليد type library باستخدام dscom، واستخدامها من VBA بـ early binding.
هذا ليس عن المسار الأقدم .NET Framework + RegAsm، ولا عن IDL مكتوب يدويّاً مع MIDL، ولا عن Reg-Free COM. التركيز هنا على مسار محدّد واحد:
.NET 8 / COM host / dscom / VBA early binding
1. النسخة المختصرة
التدفّق العمليّ هو:
- بناء class library الخاصّة بـ .NET 8 مع
EnableComHosting=true - تعريف interfaces وclasses صريحة مرئيّة لـ COM
- إبقاء classes على
ClassInterfaceType.Noneبدلاً من الاعتماد علىAutoDual - استخدام
InterfaceIsDualللـ interfaces التي ستستهلكها VBA - تشغيل
dscom tlbexportعلى الـ assembly المبنيّ لإنتاج*.tlb - تسجيل
*.comhost.dllالمولّد بـregsvr32 - تسجيل
*.tlbالمولّد بـdscom tlbregister - إضافة المرجع في VBA واستخدام المكتبة عبر early binding
النموذج الذهنيّ النظيف هو:
نقطة دخول COM هي *.comhost.dll الذي يولّده الـ SDK، بينما تعيش معلومات النوع المرئيّة لـ VBA في *.tlb الذي يولّده dscom.
2. الشكل الكامل للحلّ
ها هي الصورة الكاملة أوّلاً.
flowchart LR
VBA["VBA / Excel / Access"] -->|Reads type information from referenced TLB| TLB["VbaTypedComSample.tlb"]
VBA -->|COM calls| COMHOST["VbaTypedComSample.comhost.dll"]
COMHOST --> DOTNET["VbaTypedComSample.dll (.NET 8)"]
DOTNET --> RUNTIME[".NET 8 Runtime"]
كلّ ملفّ له وظيفة مختلفة:
| الملفّ | الدور |
|---|---|
VbaTypedComSample.dll |
تنفيذ .NET 8 الفعليّ |
VbaTypedComSample.comhost.dll |
نقطة دخول تفعيل COM |
VbaTypedComSample.tlb |
معلومات النوع التي تقرأها VBA لـ early binding |
VbaTypedComSample.deps.json |
بيانات حلّ التبعيّات |
VbaTypedComSample.runtimeconfig.json |
إعداد إقلاع .NET runtime |
ذلك التمييز يهمّ كثيراً.
VBA لا تحصل على معلومات النوع الودودة من DLL التنفيذ بسحر.
بل تحصل عليها من type library.
وتفعيل COM نفسه يمرّ عبر COM host، لا عبر assembly التنفيذ مباشرةً.
3. اقرّر bitness أوّلاً
إن أُجّل هذا الجزء، فإنّ المشروع غالباً ما ينحرف مباشرةً نحو:
«ActiveX component can’t create object.»
ينبغي أن يتطابق جانب Office / VBA مع جانب COM server في bitness.
| المستهلك | هدف جانب .NET | أداة TLB | مسار التسجيل |
|---|---|---|---|
| Office 64-bit | x64 / win-x64 |
dscom |
C:\Windows\System32\regsvr32.exe |
| Office 32-bit على Windows 64-bit | x86 / win-x86 |
dscom32.exe |
C:\Windows\SysWOW64\regsvr32.exe |
مع COM hosting الحديث في .NET، فإنّ ترك المشروع على AnyCPU غالباً ما لا يكون الخيار الأكثر أماناً للتشغيل البينيّ مع Office. إن كان تثبيت Office المستهدف معروفاً، فإنّ التصريح بـ x86 أو x64 يكون عادةً أهدأ.
تفترض الأمثلة أدناه Office 64-bit.
لـ Office 32-bit، استبدل أمثلة x64 بـ x86، و win-x64 بـ win-x86.
4. ابنِ جانب .NET 8
للمثال، تخيّل مكتبة صغيرة تكشف ثلاث methods لـ VBA:
AddDivideHello
4.1 ملفّ المشروع
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Generate the COM host -->
<EnableComHosting>true</EnableComHosting>
<!-- 64-bit Office example -->
<PlatformTarget>x64</PlatformTarget>
<NETCoreSdkRuntimeIdentifier>win-x64</NETCoreSdkRuntimeIdentifier>
</PropertyGroup>
</Project>
الخاصيّة الأساسيّة هي EnableComHosting.
ذلك ما يجعل الـ SDK يُنتج *.comhost.dll.
4.2 أبقِ الـ assembly مغلقاً افتراضيّاً
عادةً ما يكون أنظف إبقاء الـ assembly غير مرئيّ لـ COM افتراضيّاً وفتح الأنواع المحدّدة فقط التي تريد كشفها.
using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
4.3 عرّف الـ interface والـ class صراحةً
using System.Runtime.InteropServices;
namespace VbaTypedComSample;
[ComVisible(true)]
[Guid("2A1BBEDE-DE6E-4C34-AD60-2E9E0E33E999")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ICalculator
{
[DispId(1)]
int Add(int x, int y);
[DispId(2)]
double Divide(double x, double y);
[DispId(3)]
string Hello(string name);
}
[ComVisible(true)]
[Guid("FAD1C752-0BB6-4DDD-889F-FE446350847A")]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ICalculator))]
public class Calculator : ICalculator
{
public Calculator()
{
}
public int Add(int x, int y) => checked(x + y);
public double Divide(double x, double y)
{
if (y == 0)
{
throw new ArgumentOutOfRangeException(nameof(y), "Cannot divide by zero.");
}
return x / y;
}
public string Hello(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return "Hello";
}
return $"Hello, {name}";
}
}
النقاط العمليّة هنا هي:
- أعطِ الـ interface و الـ class GUIDs خاصّة بكلّ منهما
- أبقِ الـ class على
ClassInterfaceType.None - استخدم
InterfaceIsDualحتى تستهلك VBA الـ interface براحة - اضبط قيم
DispIdلتقليل الكسر القابل للتجنّب - وفّر public parameterless constructor لتفعيل COM
قد يبدو AutoDual مغرياً لأنّه يبدو سريعاً ومريحاً.
لكنّه أيضاً طريقة سهلة لجعل الشكل المكشوف هشّاً لاحقاً. العقود الصريحة تتقدّم في العمر بشكل أفضل.
5. ابنِ المشروع
استخدم Release build:
dotnet build -c Release
بعد البناء، ينبغي أن يحتوي مجلّد الإخراج على الأقلّ على:
bin/
Release/
net8.0-windows/
VbaTypedComSample.dll
VbaTypedComSample.comhost.dll
VbaTypedComSample.deps.json
VbaTypedComSample.runtimeconfig.json
مجلّد الإخراج هذا هو وحدة النشر الحقيقيّة.
إن نقلت الملفّات لاحقاً إلى مكان آخر، فعادةً ما يحتاج التسجيل إلى إعادة النظر فيه أيضاً.
6. ولّد TLB بـ dscom
6.1 لـ Office 64-bit
ثبّت dscom أوّلاً:
dotnet tool install --global dscom
ثمّ صدّر type library من الـ assembly المبنيّ:
dscom tlbexport .\bin\Release\net8.0-windows\VbaTypedComSample.dll --out .\bin\Release\net8.0-windows\VbaTypedComSample.tlb
6.2 لـ Office 32-bit
هذا فخّ صغير لكنّه مهمّ.
إن كان الهدف هو Office 32-bit، فإنّ استخدام dscom32.exe هو المسار الأكثر أماناً لـ workflow الخاصّ بـ TLB.
.\tools\dscom32.exe tlbexport .\bin\Release\net8.0-windows\VbaTypedComSample.dll --out .\bin\Release\net8.0-windows\VbaTypedComSample.tlb
7. سجّل COM host و TLB
ينبغي تشغيل هذه الأوامر من command prompt أو PowerShell برفع صلاحيّات (elevated).
7.1 حالة Office 64-bit / COM 64-bit
$out = Resolve-Path .\bin\Release\net8.0-windows
C:\Windows\System32\regsvr32.exe "$out\VbaTypedComSample.comhost.dll"
dscom tlbregister "$out\VbaTypedComSample.tlb"
7.2 Office 32-bit على Windows 64-bit
$out = Resolve-Path .\bin\Release\net8.0-windows
C:\Windows\SysWOW64\regsvr32.exe "$out\VbaTypedComSample.comhost.dll"
.\tools\dscom32.exe tlbregister "$out\VbaTypedComSample.tlb"
ثمّة عمليّتا تسجيل منفصلتان تحدثان هنا:
regsvr32يسجّل نقطة دخول COM servertlbregisterيسجّل type library
تحتاج كليهما إن كنت تريد:
- تفعيل COM
- بالإضافة إلى early binding مع types في VBA
7.3 إلغاء التسجيل أثناء التطوير
أثناء التكرار، غالباً ما يكون من المفيد إلغاء التسجيل قبل إعادة البناء أو تغيير تخطيط الـ binary.
للحالة 64-bit:
$out = Resolve-Path .\bin\Release\net8.0-windows
C:\Windows\System32\regsvr32.exe /u "$out\VbaTypedComSample.comhost.dll"
dscom tlbunregister "$out\VbaTypedComSample.tlb"
لـ Office 32-bit، استبدل System32 بـ SysWOW64 واستخدم dscom32.exe.
8. أضف المرجع في VBA واستخدمه مع types
بمجرّد تسجيل type library:
- افتح Excel أو Access
- افتح VBA editor
- اذهب إلى
Tools -> References - ضع علامة على المكتبة المسجّلة إن ظهرت في القائمة
- عند الحاجة، تصفّح للوصول إلى
VbaTypedComSample.tlbالمولّد
عندئذ تستطيع VBA استخدام الأنواع مباشرةً:
Option Explicit
Public Sub UseCalculator()
Dim calc As VbaTypedComSample.ICalculator
Set calc = New VbaTypedComSample.Calculator
Debug.Print calc.Add(10, 20)
Debug.Print calc.Divide(10, 4)
Debug.Print calc.Hello("VBA")
End Sub
هذا يُعيد الأشياء التي يفقدها late binding:
- IntelliSense
- اكتشاف أسهل للأخطاء الإملائيّة
- سطح API قابل للتصفّح
- كود يُقرأ كعقد بدلاً من كومة من
Object
8.1 الاستثناءات تظهر كأخطاء COM في VBA
إن رمى جانب .NET، فإنّ VBA عادةً ما ترى خطأ COM.
Option Explicit
Public Sub UseCalculatorWithErrorHandling()
On Error GoTo EH
Dim calc As VbaTypedComSample.ICalculator
Set calc = New VbaTypedComSample.Calculator
Debug.Print calc.Divide(10, 0)
Exit Sub
EH:
Debug.Print Err.Number
Debug.Print Err.Description
End Sub
ذلك سبب يجعل من المفيد إبقاء رسائل الاستثناءات على جانب .NET مفهومة.
9. التفكير في النشر
لا تفكّر في النشر على أنّه «انسخ DLL واحدة».
وحدة النشر العمليّة أقرب إلى:
VbaTypedComSample.dll
VbaTypedComSample.comhost.dll
VbaTypedComSample.deps.json
VbaTypedComSample.runtimeconfig.json
VbaTypedComSample.tlb
(and any dependency DLLs)
تحتاج الجهة المستهدفة أيضاً إلى .NET 8 runtime المطابق.
هذا المسار الخاصّ بـ COM hosting عادةً ما يكون framework-dependent بدلاً من self-contained.
ترتيب معقول هو:
- اقرّر مجلّد الهدف
- ضع مجموعة الإخراج الكاملة هناك
- تأكّد من تثبيت .NET 8 runtime
- سجّل COM host و TLB
- أضف مرجع VBA
التسجيل أوّلاً ثمّ نقل الملفّات لاحقاً طريقة جيّدة لإنشاء فشل تفعيل مربك.
10. الفخاخ الشائعة
10.1 لا تترك المشروع على AnyCPU
إن لم يتطابق bitness الخاصّ بـ Office مع bitness الخاصّ بـ COM host، فإنّ حالات الفشل تصبح غير سارّة بسرعة.
- Office 64-bit ->
x64/win-x64 - Office 32-bit ->
x86/win-x86
10.2 لا تستخدم ClassInterfaceType.AutoDual
يبدو أسهل، لكنّه يجعل العقد المكشوف أسهل في الكسر بكثير لاحقاً.
إن كان الهدف هو استهلاك VBA مستقرّ مع types، فإنّ interfaces الصريحة بالإضافة إلى ClassInterfaceType.None تصميم أكثر صحّة.
10.3 لا تُعد توليد GUIDs بطيش
في COM، الـ GUIDs جزء من العقد:
- interface IDs
- class IDs
تغييرها بإهمال بعد وجود مستهلكين بالفعل سيكسر التسجيلات ومراجع VBA.
10.4 لا تكسر الـ interfaces المنشورة بطيش
COM لا يغفر دائماً التغييرات «الصغيرة».
إن احتجت إلى تطوير كبير في الـ interface، فعادةً ما يكون أكثر أماناً التفكير بمصطلحات مثل:
- إبقاء
ICalculator - إضافة
ICalculator2للتوسّع غير المتوافق - ترك الـ class ينفّذ كليهما عند الحاجة
10.5 أبقِ أنواع الحدّ بسيطة
عند الحدّ المواجه لـ VBA، الأنواع المملّة عادةً ما تكون أصدقاءك.
الخيارات الآمنة الشائعة تتضمّن:
intdoubleboolstringDateTimedecimalenum
أسطح الأنواع شديدة الذكاء تميل إلى التقدّم في العمر بشكل سيّئ عند حدود COM.
10.6 لا تُعد البناء بينما يحمل Office الـ DLL
يستطيع Excel أو Access إبقاء الـ DLL محمّلة، ممّا يجعل إعادة البناء وإعادة التسجيل أكثر إحباطاً ممّا ينبغي.
إيقاع تطوير أهدأ هو:
- إغلاق Office
- إلغاء التسجيل عند الضرورة
- إعادة البناء
- التسجيل مرّة أخرى
11. الخلاصة
إن قصرت المشكلة على:
كشف COM + TLB مولّد بـ dscom + early binding مع types في VBA
فإنّ قصّة .NET 8 في الواقع منظّمة بشكل لا بأس به.
- استخدم
EnableComHosting=true - عرّف interfaces صريحة لـ COM
- أبقِ classes على
ClassInterfaceType.None - استخدم
InterfaceIsDualللـ interface المواجه لـ VBA - ولّد TLB بـ
dscom tlbexport - سجّل
*.comhost.dll - سجّل
*.tlb - أضف مرجع VBA واستخدم المكتبة بأنواع حقيقيّة
التقسيم الذهنيّ الأساسيّ هو:
*.comhost.dll-> نقطة دخول تفعيل COM*.tlb-> معلومات النوع لـ VBA*.dll-> التنفيذ
بمجرّد أن يصبح ذلك الفصل واضحاً، يصبح المسار من VBA إلى .NET 8 أسهل بكثير في التفكير فيه.
12. المراجع
- Expose .NET components to COM - Microsoft Learn
- Qualify .NET Types for Interoperation - Microsoft Learn
- ComInterfaceType enum - Microsoft Learn
- ClassInterfaceType enum - Microsoft Learn
- COM Callable Wrapper - Microsoft Learn
- DispIdAttribute - Microsoft Learn
- dscom - NuGet Gallery
- How to use the Regsvr32 tool and troubleshoot Regsvr32 error messages - Microsoft Support
- .NET 8 downloads
مقالات ذات صلة
أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.
ما يجب التحقّق منه عندما لا يعمل ActiveX على Office 2024 / Microsoft 365 - الترتيب العمليّ لتغطية التعطيل الافتراضيّ، 32bit / 64bit، تسجيل COM، DLL التابعة، ووصولًا إلى IE mode
دليل عمليّ لتشخيص توقّف ActiveX على Office 2024 و Microsoft 365، يرتّب الفحوص من التعطيل الافتراضيّ إلى تطابق 32bit / 64bit وتسجيل COM وD...
دليل المراجعة الشاملة لـ VBA و Excel macro والأدوات الداخليّة استعدادًا لإيقاف VBScript - الجرد / الكشف الساكن / سجلّات التشغيل / اختيار البديل / الاختبار / النشر التدريجيّ
ملخّص عمليّ على صفحة واحدة لمسار الاستعداد لإيقاف VBScript تدريجيًّا: جرد VBA و Excel macro والأدوات الداخليّة، الكشف الساكن، تجميع سجلّا...
كيف تبني إخراج تقارير Excel - دليل قرار عمليّ بين COM Automation وOpen XML والمقاربة المعتمدة على القوالب والمقايضات
دليل قرار عمليّ لاختيار طريقة إخراج تقارير Excel بين COM Automation وOpen XML والقوالب وVBA الموروثة، مع موازنة بيئات التشغيل والصيانة.
المزالق الشائعة في تطوير مكوّنات COM و OCX / ActiveX - فخاخ Visual Studio بين 32-bit و 64-bit، والتسجيل، وصلاحيّات المسؤول
دليل عمليّ يكشف الأسباب الحقيقيّة لإخفاق مكوّنات COM و OCX و ActiveX: عدم تطابق 32-bit / 64-bit مع Visual Studio 2022، وأخطاء regsvr32 و ...
إلى أين ينتهي unit test وأين يبدأ integration test - دليل عمليّ لرسم الحدّ الفاصل
دليل عمليّ يميّز unit test وintegration test بأربعة أسئلة: نتحقّق من منطقنا أم من الغراء، ويبقى المعنى مع fake، وما طبيعة الاعتماد، ومدى ...
أين يتصل هذا الموضوع
ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.
تطوير تطبيقات ويندوز
ندعم تطوير برامج ويندوز للأعمال، وتكامل الأجهزة، وأدوات التواصل.
دعم إعادة استخدام الأصول القديمة وترحيلها
ندعم إعادة استخدام وترحيل الأصول التي تحمل قيود COM / ActiveX / OCX أو 32bit / 64bit.