Получение исходного номера ошибки из COM-метода, вызываемого через отражение

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

  •  03-07-2019
  •  | 
  •  

Вопрос

У меня есть 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.Поднимите, чтобы сгенерировать номер ошибки, и мне нужно каким-то образом получить доступ к этому в моем вызове.Сетевое приложение.

Проблема, похоже, связана с TargetInvocationException, не содержащим номер ошибки, как я бы ожидал, если бы это было обычное COMException, поэтому:

Как я могу получить номер ошибки из COM-объекта в моем .Net-коде?

или

Могу ли я выполнить этот же вызов таким образом, чтобы вызвать COMException (содержащий номер ошибки), а не TargetInvocationException при сбое COM-компонента?

Пожалуйста, также обратите внимание, что целевой платформой является .Net 2.0, и у меня есть доступ к исходному коду VB6, но я бы счел изменение сообщения об ошибке, полученного из VB6, чтобы оно содержало код ошибки как часть текста, своего рода взломом.

Это было полезно?

Решение

Я присмотрелся к вашему коду немного внимательнее, и с помощью reflection вы обрабатываете 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); }
    }

Другие советы

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

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

Пример кода библиотеки DLL VB:(из проекта 1.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, как и ожидалось.

Просто хочу предложить обновление кода catch от @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