Recuperar o número de erro original de um método COM chamado por meio de reflexo

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

  •  03-07-2019
  •  | 
  •  

Pergunta

Eu tenho um componente VB6 COM que eu preciso para chamar de meu método .Net. I usar a reflexão para criar uma instância do objeto COM e ativá-lo da seguinte maneira:

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

Eu preciso usar GetTypeFromProgID ao invés de usar tlbimp para criar uma biblioteca contra o COM DLL como o ProgId do tipo I precisa instanciar pode variar. Eu, então, usar Type.InvokeMember para chamar o método COM no meu código como:

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

I pegar qualquer levantada TargetInvocationException de para registro e pode obter a descrição detalhada do erro do campo TargetInvocationException.InnerException. No entanto, eu sei que o componente COM utiliza Error.Raise para gerar um número de erro e eu preciso de alguma forma obter espera deste na minha aplicação .Net chamando.

O problema parece resultar do TargetInvocationException não contendo o número do erro como eu esperaria se fosse um COMException normal para:

Como posso obter o número de erro do objeto COM no meu código .net?

ou

Posso fazer essa mesma chamada de uma forma que poderia causar um COMException (contendo o número do erro) em vez de um TargetInvocationException quando o componente COM falhar?

Observe também que a plataforma de destino é .Net 2.0 e eu tenho acesso ao código fonte VB6, mas consideraria alterar a mensagem de erro elevada de VB6 para conter o código de erro como parte do texto a ser um pouco de um hack.

Foi útil?

Solução

Eu olhei para o seu código um pouco mais e com reflexão você lida com TargetInvocationException e trabalhar com a exceção interna que é um COMException ... exemplo de código abaixo (eu corri e testou este também):

    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); }
    }

Outras dicas

Você vai lidar com COMException e use a propriedade ErrorCode desse objeto de exceção. Normalmente, em DLLs do Visual Basic, se você está jogando erros personalizados que elevaria o erro com: Err.Raise vbObjectError + 88, "Project1.Class1.Test3 ()", "forçado teste de erro"

Se este for o caso, você precisará subtrair vbObjectError (-2147221504) a partir das exceções ErrorCode para obter o número de erro real. Se não usar apenas o valor ErrorCode.

código Exemplo VB dll: (a partir de Project1.Class1)

Public Sub Test3 ()

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

End Sub

Exemplo C código de tratamento de consumo #:

    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); }
    }

O código de erro neste teste I retornos completado 88 como esperado.

Apenas quero oferecer uma atualização de @ sharvell código de captura. A menos que você esteja absolutamente certo InnerException é um COMException, é melhor para testá-lo com segurança em primeiro lugar. Caso contrário, você vai ter uma exceção no seu manipulador de exceção. Gritos!

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
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top