انتقل عبر الشوك للدراجات ، الجزء الأول: تعلم أساسيات تخصيص مصحح أخطاء Visual Studio باستخدام المكونات الإضافية

رافق أحد الابتكارات في Visual Studio 2012 ظهور مصحح أخطاء مخصص جديد يسمى Concord. يتيح نظام المكونات الخاص به لـ VSIX المكونات الإضافية لتخصيص سلوك مصحح الأخطاء وكتابة أدوات جديدة حساسة للسياق يمكنها استخدام مصحح الأخطاء لاحتياجاتها. يوفر API الخاص به العديد من ميزات QOL ، مثل التنظيم بين التعليمات البرمجية المدارة / غير المُدارة ، والتكامل السلس مع عملية تصحيح الأخطاء عن بُعد / محليًا ، وأكثر من ذلك. في الواقع ، يمكن القيام بكل شيء تقريبًا في IDE برمجيًا باستخدام واجهة Concord API! قم بتغيير قيم المتغيرات المحددة أثناء التنقل ، ووظائف الاتصال عند الطلب (أو قم بإجراء تخطي البرنامج على وجه التحديد لهم!) ، يمكن أن تبحث المكونات الإضافية عن طريق PDB (!) ، وتجاوز خطوة بخطوة ، وحتى تعديل الرمز! افتح القطة وستتعرف على هذه الابتكارات غير المعروفة في مجال بناء الدراجات.

ربما يجب أن تبدأ من البداية. يكتشف مصحح الأخطاء المكونات من خلال قراءة المعلومات من ملف vsdconfig المشار إليه بواسطة بيان مكون VSIX. بدوره ، تشير vsdconfig إلى الواجهات التي يتم تنفيذها بواسطة مكونات البرنامج المساعد وكيفية العثور على هذه المكونات (ارتباط إلى ملف .dll ، يشير إلى الفئة أو ، في حالة التنفيذ الأصلي ، يشير إلى CLSID. سأقدم أمثلة في C #). أيضا ، يشار إلى معرف فريد (GUID) لكل مكون ، وكذلك "مستواه". المستوى هو الذي يحدد في أي ترتيب سوف تتم معالجة المكونات الإضافية ، وكذلك في سياق العملية التي سيتم تحميل هذا التطبيق - في عملية IDE أو في عملية التطبيق الذي تم تصحيحه. هذا يرجع إلى حقيقة أن بعض الوظائف يمكن أن تعمل فقط في سياق IDE ، والعكس بالعكس - فقط في سياق عملية تم تصحيحها. تعمل بعض وظائف API بنفس الطريقة هناك وهناك. أيضًا ، هناك عدد من المكونات لديها قواعد تخطيط خاصة بها ، لأنها قد تعتمد على عناصر مصحح الأخطاء الموجودة في مستوياتها الثابتة. لتجنب الحوادث ، أوصي بـ RTFM (https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualstudio.debugger.componentinterfaces؟view=visualstudiosdk-2017) وتجارب مستقلة في صندوق حماية منفصل ، مما لن يكون مؤسفًا حذف إذا حدث شيء ما (هذا مرتبط ، مرة أخرى ، بمثل هذه الفروق الدقيقة - في بعض الحالات ، لا يكون من الواضح سبب عدم تحميل التجميع أو النوع ، لأنني ما زلت لا أستطيع العثور على المكان الذي ستظهر به السجلات التي تشير إلى المشكلة بشكل ثابت. خطأ ، على سبيل المثال ، مع الإشارة إلى التبعية التي لا يمكن تحميلها في العملية الهدف ، فقد تظهر في الإخراج st DI-، أو لا. كن akuratno، واتخاذ يرتكب متكررة، وعدم الجلوس وراء عجلة القيادة في حالة سكر).

قائمة المستويات هي كما يلي (سأقدم النص باللغة الإنجليزية حتى لا يتعرض القارئ لحوادث عند ارتكاب أعمال RFTM):

مستويات مكون IDE (القيم> 100،000):
عنصرمستوى المكون
AD7 AL1000000000
مزود التفكيك9998000
Stack Query - المكونات التي ترغب في الاستعلام عن مكدس الاستدعاءات9997000
مزود المكدس9996000
عامل تصفية المكدس - المستوى الذي يمكن فيه ترشيح المكدسات وتعليقها9995000
مدير نقطة التوقف9994000
تقييم التعبير IDE9992000
Symbol Stack Walkers - مشايات المكدس التي تحتاج إلى الوصول إلى الرموز9991000
IDE SymbolProvider - المكونات التي توفر معلومات الرمز لبقية المصحح. لا ينبغي استخدام مسار الرمز أسفل هذا المستوى.1999000

مستويات مكونات العملية المستهدفة (القيم <99.999):
عنصرمستوى المكون
Monitor Symbol Provider - موفرو الرمز عندما تكون الحالة الرمزية مبنية على الكمبيوتر المستهدف (على سبيل المثال: المترجم الشفهي المترجم ديناميكيًا / المنبعث ديناميكيًا)75000
Breakpoint Condition Processor - هذا المستوى هو لمعالجة شروط نقطة التوقف مثل تعبيرات الحالة وعدد مرات الدخول. أسفل هذه النقطة ، ستكون جميع أحداث نقاط التوقف الفعلية مرئية بغض النظر عما إذا كانت هناك ظروف مزيفة أم لا.70000
Monitor Task Provider - هذا هو المستوى لاستخراج بيانات المهمة في العملية المستهدفة65500
مراقب مقيم التعبير65000
تنسيق الشاشة - المكونات التي تتحكم بين الشاشات المختلفة للخطو ، أو نقاط التوقف حسب العنوان الأصلي ، أو السير المكدس ، إلخ.60000
مراقبة مشوا المكدس55000
Custom Debug Monitor - محجوز لمراقبي تصحيح الأطراف الثالثة الذين يرغبون في الاستفادة من الخدمات التي توفرها شاشات تصحيح الأخطاء القياسية.40500
Runtime Debug Monitor - يوفر فحص البيانات والتحكم في التنفيذ لرمز المدارة / الأم / البرنامج النصي40000
رصد تصحيح قاعدة10000
خدمات مراقبة تصحيح الأخطاء الأساسية - توفر خدمات الأداة المساعدة لأجهزة مراقبة تصحيح الأخطاء الأساسية (على سبيل المثال: إنشاء العملية) بالإضافة إلى خدمات ما قبل تصحيح الأخطاء (على سبيل المثال: تعداد العمليات)1000

بعد ذلك ، بالترتيب ، عملية إنشاء مشروع. إذا لم تكن هناك أي فروق دقيقة مهمة ، فيمكنني وصف هذه العملية إلى الحد الأدنى أو تخطيها على الإطلاق ، ولكن الحقائق مختلفة تمامًا - نحتاج إلى عدد من التبعيات بالمكتبة ، فضلاً عن أداة لإنشاء ملفات التكوين ، والتي لا يتم توزيعها مع VisualStudio لسبب ما ، ولكنها متوفرة فقط مع nuget. في الواقع ، نحن الآن بحاجة إلى الانتقال إلى الجوهر. تتمحور عملية إنشاء وإعداد مشروع على النحو التالي:

  1. افتح Visual Studio. في حالتي ، 2017 مجتمع الطبعة
  2. VSIX Project ( Visual C # -> علامة التبويب القابلية للتوسعة ، أو عبر البحث). دعنا نسميها "HelloVSIX"
  3. أضف مشروع مكتبة فئة جديدة في الحل ، واسمه "DebuggeePlugin"
  4. وضعنا المرجع في مشروع "DebuggeePlugin" في مشروع "HelloVSIX"
  5. نضع الإشارة إلى التجميع "Microsoft.VisualStudio.Debugger.Engine" في مشروع DebuggeePlugin
  6. إضافة المرجع لحزمة nuget Microsoft.VSSDK.Debugger.VSDConfigTool إلى مشروع "DebuggeePlugin". هذه هي أداتنا لإنشاء تكوينات VSD.

الآن ، نحن مستعدون لجعل البرنامج المساعد لدينا يفعل شيئًا مفيدًا. لنقم بأبسط ما يمكنك القيام به - فدعه يعرض MessageBox مكتوب عليه "Hello VSIX" عندما تصادف العملية الهدف نقطة إدخال. للقيام بذلك ، نحتاج إلى إنشاء فئة تنفذ واجهة IDkmEntryPointNotification ، بالإضافة إلى ملء العديد من ملفات التكوين. أضف فئة عامة جديدة تسمى DkmEntryPointNotificationService ، وارث واجهة IDkmEntryPointNotification ، واترك التطبيق الافتراضي الآن:

using Microsoft.VisualStudio.Debugger; using Microsoft.VisualStudio.Debugger.ComponentInterfaces; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DebuggeePlugin { class DkmEntryPointNotificationService : IDkmEntryPointNotification { public void OnEntryPoint(DkmProcess process, DkmThread thread, DkmEventDescriptor eventDescriptor) { throw new NotImplementedException(); } } } 

أضف الملف "DkmEntryPointNotificationService.vsdconfigxml" إلى مشروع "DebuggeePlugin". لكل فئة معلنة يجب أن تتلقى إعلامات من خلال تطبيقات Microsoft.VisualStudio.Debugger.ComponentInterfaces واجهات مساحة الاسم ، يجب أن يكون لديك مثل هذا الملف. بالمناسبة ، من الممكن تنفيذ العديد من هذه الواجهات دفعة واحدة في فصل واحد. نحن الآن بحاجة إلى تغيير إجراء الإنشاء لملف ".vsdconfigxml". للقيام بذلك ، يجب عليك تحرير ملف المشروع يدويًا (بجدية). نقوم بإلغاء تحميل مشروع DebuggeePlugin ، وفتحه مع محرر الاستوديو. نحتاج إلى العثور على علامة XLM التالية:

 <None Include="DkmEntryPointNotificationService.vsdconfigxml" /> 

ونقل هذه العلامة إلى ItemGroup الخاصة بك ، وتغيير الكتابة من بلا إلى VsdConfigXmlFiles:
 <ItemGroup> <VsdConfigXmlFiles Include="DkmEntryPointNotificationService.vsdconfigxml" /> </ItemGroup> 

يمكنك حفظ وإعادة تحميل المشروع.

الآن ، انتقل إلى التكوينات. أول شيء يجب فعله: إذا تمت إضافة ملف vsdconfig.xsd إلى مشروع DebuggeePlugin ، فينبغي حذفه. سنستبدلها الآن ، لأنه من الأسهل التعامل مع النص الخام. افتح DkmEntryPointNotificationService.vsdconfigxml واستبدل النص بما يلي:

 <?xml version="1.0" encoding="utf-8"?> <Configuration xmlns="http://schemas.microsoft.com/vstudio/vsdconfig/2008"> <ManagedComponent ComponentId="422413E1-450E-40A6-AE24-7E80A81CC668" ComponentLevel=^_^quot𘙮quot^_^ AssemblyName="DebuggeePlugin"> <Class Name="DebuggeePlugin.DkmEntryPointNotificationService"> <Implements> <InterfaceGroup> <NoFilter/> <Interface Name="IDkmEntryPointNotification"/> </InterfaceGroup> </Implements> </Class> </ManagedComponent> </Configuration> 

في أي ملف من هذا القبيل ، سنطلب منك الإشارة إلى الأشياء التالية:

  1. ComponentId - يمكن إنشاء هذه القيمة باستخدام أداة إنشاء GUID (أدوات -> CreateGUID)
  2. ComponentLevel هو مستوى مكوننا في التسلسل الهرمي. انظر الجدول أعلاه ومساعدة المعلومات على MSDN لتحديد نطاق القيم المطلوب.
  3. Assemblyname هو اسم التجميع الخاص بنا (ليس حلاً!). في هذه الحالة ، سيكون هناك DebuggeePlugin
  4. اسم الفصل - يجب الإشارة إلى بما في ذلك مساحة الاسم التي يوجد بها الفصل. في هذه الحالة ، DebuggeePlugin.DkmEntryPointNotificationService
  5. صفيف InterfaceGroup - يشير كل إدخال فيه إلى واجهة يتم تنفيذها بواسطة هذا المكون. داخل كل عقدة InterfaceGroup ، يجب أن يكون هناك عقدة فرعية تشير إلى الواجهات الشائعة للجميع ، في هذه المجموعة ، التصفية ، ولكن حول المرشحات لاحقًا. الآن لدينا عقدة واجهة واحدة فقط ، وتحمل اسم واجهة IdkmEntryPointNotification. إذا كان لدينا العديد من واجهات ، سيكون هناك العديد من العقد واجهة.

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

  1. بعد قيامنا بإنشاء ملف ".vsdconfigxml" ، يجب علينا ... جمع الحل مرة واحدة ، وإلا فلن يكون لدينا أي ملف .vsdconfig في دليل إخراج المشروع)
  2. بعد ذلك ، افتح محرر النصوص لملف source.extension.vsixmanifest وأضف الكود التالي قبل علامة PackageManifest الختامية:

  <Assets> <Asset Type="DebuggerEngineExtension" d:Source="File" Path="DebuggeePlugin.vsdconfig" /> </Assets> 

إذا ظهر الملف "DebuggeePlugin.vsdconfig" في مشروع HelloVSIX ، بعد الإجراءات المكتملة ، فيجب إزالته من المشروع وينبغي جمع الحل مرة أخرى ، وإلا فلن يتم تحديثه.

العمل التحضيري قد انتهى! يمكنك البدء في تصحيح البرنامج المساعد لدينا. يتم ذلك عن طريق بدء مثيل تجريبي لـ VisualStudio (لمشاريع VSIX ، يكون هذا هو الهدف الافتراضي لتصحيح الأخطاء ، لذلك لا توجد خطوات إضافية ضرورية). في الواقع ، نقر فوق Debug-> StartDebugging ونرى نسخة تجريبية من VisualStudio. في ذلك ، بشكل افتراضي ، ينبغي بالفعل تثبيت البرنامج المساعد لدينا. يمكنك التحقق من ذلك من خلال القائمة أدوات> ملحقات والتحديثات.

نظرًا لحقيقة أننا قمنا بتطبيق واجهة IDkmEntryPointNotification ، سيتعين علينا إنشاء مشروع اختبار في نسخة تجريبية من VisualStudio. في الواقع ، نقوم بإنشاء مشروع جديد ، حدد C ++ -> تطبيق وحدة التحكم (اختر C ++ ، لأن الأمثلة التالية سوف تحتوي على تفاصيل C ++) ، نسميها VSIXTestApp ، قم بتشغيل دون أي تغييرات ، وجمع ونرى أن المثال التجريبي لدينا توقف عن وضع استثناء داخل طريقة DebuggeePlugin. DkmEntryPointNotificationService.OnEntryPoint. ! ممتاز الآن تحتاج إلى إظهار MessageBox. للقيام بذلك ، من الضروري إضافة المراجع التالية إلى مشروع DebuggeePlugin:

  • Microsoft.VisualStudio.Shell.15.0
  • Microsoft.VisualStudio.Shell.Interop
  • Microsoft.VisualStudio.Shell.Interop.8.0
  • Microsoft.VisualStudio.OLE.Interop

أضف استخدامين في بداية ملف DkmEntryPointNotificationService.cs:

 using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; 

وقم بإضافة مكالمة إلى طريقة VsShellUtilities.ShowMessageBox في طريقة DkmEntryPointNotificationService.OnEntryPoint:

 using Microsoft.VisualStudio.Debugger; using Microsoft.VisualStudio.Debugger.ComponentInterfaces; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DebuggeePlugin { class DkmEntryPointNotificationService : IDkmEntryPointNotification { public void OnEntryPoint(DkmProcess process, DkmThread thread, DkmEventDescriptor eventDescriptor) { VsShellUtilities.ShowMessageBox(Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider, "Hello VSIX", "Hello VSIX", OLEMSGICON.OLEMSGICON_INFO, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } } 

نقوم بإعادة البناء ، وإطلاق نسخة تجريبية من الاستوديو ، وإطلاق مشروع اختبار وفويلا!

نرى أن مثيل اختبار الاستوديو خلق MessageBox!



وما الفائدة في الواقع؟

لقد تعلمنا هنا كيفية إعداد مشروع VSIX يحتوي على مكون إضافي لمصحح Visual Studio ، مع مراعاة معظم الفروق الدقيقة التي أعاقت النتيجة. هذه هي نقطة الانطلاق لمزيد من العمل المفصل. في المقالة التالية ، سأريك نقطة مهمة أخرى: كيفية إجراء الاتصال بين IDE ومكونات Debug المستهدفة.

لمزيد من المساعدة في استخدام واجهة Concord API ، يمكنك الرجوع ليس فقط إلى MSDN ، ولكن أيضًا إلى مستودعات Microsoft التالية على github:
github.com/microsoft/PTVS
github.com/Microsoft/ConcordExtensibilitySamples

Source: https://habr.com/ru/post/ar476298/


All Articles