Récupération du numéro d'erreur d'origine d'une méthode COM appelée via réflexion

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

  •  03-07-2019
  •  | 
  •  

Question

J'ai un composant COM VB6 que je dois appeler depuis ma méthode .Net. J'utilise réflexion pour créer une instance de l'objet COM et l'activer de la manière suivante:

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

Je dois utiliser GetTypeFromProgID plutôt que tlbimp pour créer une bibliothèque contre la DLL COM, car le ProgId du type que je dois instancier peut varier. J'utilise ensuite Type.InvokeMember pour appeler la méthode COM dans mon code comme suit:

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

J'intercepte toutes les exceptions TargetInvocationException soulevées pour la journalisation et je peux obtenir la description détaillée de l'erreur dans le champ TargetInvocationException.InnerException. Cependant, je sais que le composant COM utilise Error.Raise pour générer un numéro d'erreur et que je dois d'une manière ou d'une autre l'obtenir dans mon application .Net appelante.

Le problème semble provenir de la TargetInvocationException qui ne contient pas le numéro de l'erreur, comme je l'aurais cru s'il s'agissait d'une exception COMException normale:

Comment puis-je obtenir le numéro d'erreur de l'objet COM dans mon code .Net?

ou

Puis-je effectuer le même appel de manière à provoquer une exception COMException (contenant le numéro d'erreur) plutôt qu'une exception TargetInvocationException en cas de défaillance du composant COM?

Veuillez noter également que la plate-forme cible est .Net 2.0 et que j’ai accès au code source de VB6, mais que le fait de modifier le message d’erreur généré par VB6 afin de contenir le code d’erreur dans le texte est un peu bidouille.

Était-ce utile?

La solution

J'ai examiné votre code un peu plus près et avec réflexion, vous gérez TargetInvocationException et travaillez avec l'exception interne qui est une exception COMException ... Exemple de code ci-dessous (j'ai également testé et testé ceci):

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

Autres conseils

Vous allez gérer COMException et utiliser la propriété ErrorCode de cet objet exception. Normalement, dans les DLL Visual Basic, si vous générez des erreurs personnalisées, vous devez les générer avec: Err.Raise vbObjectError + 88, "Project1.Class1.Test3 ()", "Test d'erreur forcée"

Si tel est le cas, vous devrez soustraire vbobjecterror (-2147221504) aux exceptions ErrorCode pour obtenir le numéro d'erreur réel. Sinon, utilisez simplement la valeur ErrorCode.

Exemple de code DLL VB: (à 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

Exemple de code de traitement de la consommation 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); }
    }

Le code d'erreur de ce test que je viens de terminer renvoie 88 comme prévu.

Je veux juste proposer une mise à jour du code de capture de @ sharvell. Sauf si vous êtes absolument certain que InnerException est une exception COMException, il est préférable de le tester en toute sécurité. Sinon, vous aurez une exception dans votre gestionnaire d'exceptions. Oups!

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
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top