Получение исходного номера ошибки из COM-метода, вызванного с помощью отражения - PullRequest
0 голосов
/ 30 сентября 2008

У меня есть COM-компонент VB6, который мне нужно вызвать из моего метода .Net. Я использую отражение, чтобы создать экземпляр COM-объекта и активировать его следующим образом:

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

Мне нужно использовать GetTypeFromProgID вместо использования tlbimp для создания библиотеки для COM DLL, так как ProgId типа, который мне нужно создать, может различаться. Затем я использую Type.InvokeMember для вызова метода 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, на код ошибки в качестве части текста взломать.

Ответы [ 3 ]

2 голосов
/ 01 октября 2008

Я посмотрел на ваш код немного ближе, и с отражением вы обрабатываете 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); }
    }
2 голосов
/ 01 октября 2008

Просто хочу предложить обновление кода уловки @ 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
}
2 голосов
/ 01 октября 2008

Вы будете обрабатывать COMException и использовать свойство ErrorCode этого объекта исключения. Обычно в Visual Basic DLL, если вы генерируете пользовательские ошибки, вы можете вызвать ошибку с помощью: Err.Raise vbObjectError + 88, "Project1.Class1.Test3 ()", "Принудительный тест на ошибки"

В этом случае вам необходимо вычесть vbobjecterror (-2147221504) из исключений ErrorCode, чтобы получить действительный номер ошибки. Если нет, просто используйте значение ErrorCode.

Пример кода DLL VB: (из Project1.Class1)

Public Sub Test3 ()

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

End Sub

Пример кода обработки потребления 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, как и ожидалось.

...