استرداد رقم الخطأ الأصلي من أسلوب COM يتم استدعاؤه عبر الانعكاس

StackOverflow https://stackoverflow.com/questions/153438

  •  03-07-2019
  •  | 
  •  

سؤال

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

f_oType = Type.GetTypeFromProgID(MyProgId);
f_oInstance = Activator.CreateInstance(f_oType);

أحتاج إلى استخدام GetTypeFromProgID بدلاً من استخدام tlbimp لإنشاء مكتبة مقابل COM DLL حيث يمكن أن يختلف ProgId من النوع الذي أحتاج إلى إنشاء مثيل له.ثم أستخدم Type.InvoceMember لاستدعاء طريقة COM في الكود الخاص بي مثل:

f_oType.InvokeMember("Process", BindingFlags.InvokeMethod, null, f_oInstance, new object[] { param1, param2, param3, param4 });

لقد اكتشفت أي علامات TargetInvocationException مرفوعة للتسجيل ويمكنني الحصول على وصف الخطأ التفصيلي من حقل TargetInvocationException.InnerException.ومع ذلك، أعلم أن مكون COM يستخدم Error.Raise لإنشاء رقم خطأ وأحتاج إلى الحصول على هذا بطريقة أو بأخرى في تطبيق .Net للاتصال الخاص بي.

يبدو أن المشكلة تنبع من عدم احتواء TargetInvocationException على رقم الخطأ كما كنت أتوقع إذا كان COMException عاديًا:

كيف يمكنني الحصول على رقم الخطأ من كائن COM الموجود في كود .Net الخاص بي؟

أو

هل يمكنني إجراء نفس الاستدعاء بطريقة قد تتسبب في ظهور خطأ COMException (يحتوي على رقم الخطأ) بدلاً من نموذج TargetInvocationException عند فشل مكون COM؟

يرجى أيضًا ملاحظة أن النظام الأساسي المستهدف هو ‎.Net 2.0 ولدي إمكانية الوصول إلى كود مصدر VB6 ولكني أعتبر أن تغيير رسالة الخطأ التي تم رفعها من VB6 لتحتوي على رمز الخطأ كجزء من النص هو نوع من الاختراق.

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

المحلول

لقد ألقيت نظرة على التعليمات البرمجية الخاصة بك عن كثب ومع التأمل يمكنك التعامل مع TargetInvocationException والعمل مع الاستثناء الداخلي وهو COMException...مثال التعليمات البرمجية أدناه (لقد قمت بتشغيل واختبرت هذا أيضًا):

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            var f_oType = Type.GetTypeFromProgID("Project1.Class1");
            var f_oInstance = Activator.CreateInstance(f_oType);
            f_oType.InvokeMember("Test3", BindingFlags.InvokeMethod, null, f_oInstance, new object[] {});
        }
        catch(TargetInvocationException ex)
        {
            //no need to subtract -2147221504 if non custom error etc
            int errorNumber = ((COMException)ex.InnerException).ErrorCode - (-2147221504);
            MessageBox.Show(errorNumber.ToString() + ": " + ex.InnerException.Message);
        }
        catch(Exception ex)
        { MessageBox.Show(ex.Message); }
    }

نصائح أخرى

سوف تتعامل مع COException وتستخدم خاصية ErrorCode لكائن الاستثناء هذا.عادةً في ملفات DLL المرئية الأساسية إذا كنت ترمي أخطاء مخصصة، فإنك ستثير الخطأ باستخدام:Err.Raise vbObjectError + 88، "Project1.Class1.Test3()"، "اختبار الخطأ الإجباري"

إذا كانت هذه هي الحالة فسوف تحتاج إلى طرح vbobjecterror (-2147221504) من ErrorCode الاستثناءات للحصول على رقم الخطأ الفعلي.إذا لم يكن فقط استخدم قيمة ErrorCode.

مثال على كود VB dll:(من Project1.Class1)

الاختبار الفرعي العام 3()

MsgBox "this is a test 3"
Err.Raise vbObjectError + 88, "Project1.Class1.Test3()", "Forced error test"

نهاية الفرعية

مثال على كود معالجة استهلاك C#:

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            var p = new Class1();
            p.Test3();
        }
        catch (COMException ex)
        {
            int errorNumber = (ex.ErrorCode - (-2147221504));
            MessageBox.Show(errorNumber.ToString() + ": " + ex.Message);
        }
        catch(Exception ex)
        { MessageBox.Show(ex.Message); }
    }

رمز الخطأ في هذا الاختبار الذي أكملته للتو يُرجع 88 كما هو متوقع.

أريد فقط تقديم تحديث لرمز التقاط @sharvell.ما لم تكن متأكدًا تمامًا من أن InnerException هو COMException، فمن الأفضل اختباره بأمان أولاً.وإلا سيكون لديك استثناء في معالج الاستثناء الخاص بك.عفوًا!

catch(TargetInvocationException ex)
{
    if( ex.InnerException != null && ex.InnerException is COMException )
    {
        COMException ce = (COMException)ex.InnerException;
        // do something with ce - e.g. logging the error
    }
    // else InnerException not set, or it's not a COMException
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top