سؤال


السؤال

سؤالي هو: هل يدعم C# بشكل طبيعي IDispatch المرتبط المتأخر؟


يدّعي أحاول تشغيل Office تلقائيًا، مع التوافق مع أي إصدار قام العميل بتثبيته.

في عالم .NET، إذا قمت بالتطوير مع تثبيت Office 2000، فيجب على كل مطور وكل عميل، من الآن وحتى نهاية الوقت، أن يكون لديه Office 2000.

في العالم قبل .NET، كنا نستخدم كوم للتحدث إلى تطبيقات Office.

على سبيل المثال:

1) استخدم الإصدار المستقل ProgID

"Excel.Application"

والذي يقرر:

clsid = {00024500-0000-0000-C000-000000000046}

ثم باستخدام COM، نطلب إنشاء مثيل لواحدة من هذه الفئات في كائن:

IUnknown unk;
CoCreateInstance(
    clsid, 
    null,
    CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
    IUnknown, 
    out unk);

والآن نحن خارج السباقات - قادرون على استخدام برنامج Excel من داخل تطبيقي.بالطبع إذا حقًا إذا كنت تريد استخدام الكائن، فيجب عليك الاتصال بطريقة ما لطرق الاتصال.

نحن استطاع الحصول على أهولد من مختلف واجهه المستخدم التصريحات المترجمة إلى لغتنا.هذه التقنية جيدة لأننا نحصل عليها

  • ملزمة مبكرة
  • رؤية الكود
  • التحقق من بناء جملة النوع

وقد تكون بعض أمثلة التعليمات البرمجية:

Application xl = (IExcelApplication)unk;
ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
Worksheet worksheet = workbook.ActiveSheet;

ولكن هناك جانب سلبي لاستخدام الواجهات:يتعين علينا الحصول على إعلانات الواجهة المختلفة، المترجمة إلى لغتنا.ونحن عالقون في استخدام الاستدعاءات القائمة على الطريقة، حيث يتعين علينا تحديد جميع المعلمات، على سبيل المثال:

ExcelWorkbook workbook = xl.Workbooks.Add(template, lcid);
xl.Worksheets.Add(before, after, count, type, lcid);

لقد أثبت هذا، في العالم الحقيقي، أن له جوانب سلبية تجعلنا نتخلى عنه عن طيب خاطر:

  • ملزمة مبكرة
  • رؤية الكود
  • تجميع التحقق من بناء الجملة الوقت

واستخدام بدلا من ذلك IDispatch ملزمة متأخرة:

Variant xl = (IDispatch)unk;
Variant newWorksheet = xl.Worksheets.Add();

نظرًا لأنه تم تصميم أتمتة Excel لبرنامج VB Script، فمن الممكن حذف الكثير من المعلمات، حتى في حالة عدم وجود حمل زائد بدونها.

ملحوظة: لا تخلط بين مثالي لبرنامج Excel وسبب رغبتي في استخدام IDispatch.ليس كل كائن COM هو Excel.لا تحتوي بعض كائنات COM على دعم آخر غير IDispatch.

هل كانت مفيدة؟

المحلول

يمكنك نسبيًا استخدام ربط IDispatch المتأخر في C#.

http://support.microsoft.com/kb/302902

إليك بعض النماذج لاستخدام Excel.بهذه الطريقة لا تحتاج إلى إضافة اعتماد لا داعي له على PIA المتضخم من Microsoft:

//Create XL
Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));

//Get the workbooks collection.
//   books = xl.Workbooks;
Object books = xl.GetType().InvokeMember( "Workbooks", 
      BindingFlags.GetProperty, null, xl, null);

//Add a new workbook.
//   book = books.Add();
Objet book = books.GetType().InvokeMember( "Add", 
      BindingFlags.InvokeMethod, null, books, null );

//Get the worksheets collection.
//   sheets = book.Worksheets;
Object sheets = book.GetType().InvokeMember( "Worksheets",
      BindingFlags.GetProperty, null, book, null );

Object[] parameters;

//Get the first worksheet.
//   sheet = sheets.Item[1]
parameters = new Object[1];
parameters[0] = 1;
Object sheet = sheets.GetType().InvokeMember( "Item", 
      BindingFlags.GetProperty, null, sheets, parameters );

//Get a range object that contains cell A1.
//   range = sheet.Range["A1];
parameters = new Object[2];
parameters[0] = "A1";
parameters[1] = Missing.Value;
Object range = sheet.GetType().InvokeMember( "Range",
      BindingFlags.GetProperty, null, sheet, parameters );

//Write "Hello, World!" in cell A1.
//   range.Value = "Hello, World!";
parameters = new Object[1];
parameters[0] = "Hello, World!";
objRange_Late.GetType().InvokeMember( "Value", BindingFlags.SetProperty, 
      null, range, parameters );

//Return control of Excel to the user.
//   xl.Visible = true;
//   xl.UserControl = true;
parameters = new Object[1];
parameters[0] = true;
xl.GetType().InvokeMember( "Visible", BindingFlags.SetProperty,
      null, xl, Parameters );
xl.GetType().InvokeMember( "UserControl", BindingFlags.SetProperty,
      null, xl, Parameters );

نصائح أخرى

يجب عليك الانتظار حتى ظهور الإصدار C# 4.0 للحصول على الارتباط المتأخر الذي تبحث عنه.في أي وقت أحتاج فيه إلى إمكانات التشغيل المتداخل، أعود مرة أخرى إلى وضع VB.Net حتى أتمكن من الاستفادة من إمكانيات COM التي يبدو أن C# تفتقر إليها.

الطريقة البسيطة التي أستخدمها هي إنشاء فئة في VB.Net تعمل على IDispatch ثم الكشف عن الأساليب التي أريد استخدامها كطرق للمجمّع الخاص بي وبعد ذلك يمكنني الاتصال بها حسب الرغبة من كود C# الخاص بي.ليس الحل الأكثر أناقة، لكنه أخرجني من مأزق أو اثنين خلال الأشهر القليلة الماضية.

ج#4 dynamic الكلمة الأساسية تدعم IDispatch والربط المتأخر.يمكنك قراءة سام نج سلسلة ديناميكية للمزيد من المعلومات

أوه، وC# 4 متاح فقط كبرنامج CTP اليوم.سيتعين عليك إما انتظار Visual Studio vNext أو استخدام الإصدار التجريبي (الذي يعمل على Windows Server 2008 Virtual PC) لاستخدام ذلك.

ربما يمكنك الابتعاد برمز أجمل كثيرًا في C# 2.0/3.0 إذا كنت تأخذ الوقت الكافي لكتابة واجهة تحتوي على الأساليب والخصائص التي تريدها من الكائن وإضافة بعض السمات (أكتبها من الذاكرة ، لذلك قد لا تكون التفاصيل صحيح ، لكني أقسم أنه عمل بالنسبة لي ...)

    using System.Runtime.Interopservices;

    [Guid("00024500-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    interface IExcel
    {
      // sample property
      string Name{get;}
      // more properties
    }

    // and somewhere else
    void main()
    {
      Object xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
      IExcel excel = (IExcel)xl;
      string name = xl.name
    }

كما ذكرنا سابقًا، لن يعمل الكود خارج الصندوق، بل هو مجرد تلميح لما يجب البحث عنه في msdn.

كما قال الآخرون - باستخدام الصخور الأساسية "الديناميكية" لـ c#4.إليك مثال بسيط - وهو أكثر إيجازًا من استخدام "InvocMethod"

dynamic xl = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));
dynamic books = xl.Workbooks;
dynamic book = books.Add();

Console.WriteLine(books.Count);     //Writes 1

foreach (dynamic b in books)        
{
Console.WriteLine(b.Name);      //Writes "Book1"
}

مرحبًا يا صاح ، لدي مشروعان CodePlex حاليًا لحل هذه المشكلة.

الأول هو LateBindingApi.Excel http://excel.codeplex.comتم تعيين استدعاء متأخر مرتبط بنموذج الكائن المعروف.كان هذا مشروعًا تجريبيًا للمشروع التالي.

والثاني هو CodeGenerator http://latebindingapi.codeplex.comتقوم الأداة بإنشاء مشاريع c# من مكتبات نوع COM.تتضمن المشاريع التي تم إنشاؤها كائنات مخطط لها إمكانية الوصول إلى خادم COM.أبرز ما في الأمر هو أن الأداة تقوم بتحويل libs من نوع COM في إصدارات مختلفة إلى مشروع واحد واحد (على سبيل المثال Excel 9,10,11) ووضع علامة على جميع الكيانات باستخدام سمة SupportByLibrary المحددة ذاتيًا.لقد قمت بتحليل جميع تطبيقات Office في الإصدار 9،10،11،12،14 باستخدام هذه الأداة الآن وقمت بإنشاء حل C#، وهو متاح كإصدار تجريبي تم اختباره مع نموذج التعليمات البرمجية على الصفحة الرئيسية.

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