Recupero del numero di errore originale da un metodo COM chiamato tramite reflection

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

  •  03-07-2019
  •  | 
  •  

Domanda

Ho un componente COM VB6 che devo chiamare dal mio metodo .Net. Uso la riflessione per creare un'istanza dell'oggetto COM e attivarla nel modo seguente:

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

Devo usare GetTypeFromProgID invece di usare tlbimp per creare una libreria contro la DLL COM poiché il ProgId del tipo che devo istanziare può variare. Quindi uso Type.InvokeMember per chiamare il metodo COM nel mio codice come:

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

Prendo eventuali TargetInvocationException sollevati per la registrazione e posso ottenere la descrizione dettagliata dell'errore dal campo TargetInvocationException.InnerException. Tuttavia, so che il componente COM utilizza Error.Raise per generare un numero di errore e devo in qualche modo ottenerlo nella mia applicazione .Net chiamante.

Il problema sembra derivare da TargetInvocationException che non contiene il numero di errore come mi aspetterei se fosse una normale COMException quindi:

Come posso ottenere il numero di errore dall'oggetto COM nel mio codice .Net?

o

È possibile effettuare la stessa chiamata in modo da causare una COMException (contenente il numero di errore) anziché TargetInvocationException in caso di errore del componente COM?

Si noti inoltre che la piattaforma di destinazione è .Net 2.0 e che io abbia accesso al codice sorgente VB6, ma considererei la modifica del messaggio di errore generato da VB6 per contenere il codice di errore come parte del testo come un po 'di hackerare.

È stato utile?

Soluzione

Ho esaminato il tuo codice un po 'più da vicino e con la riflessione gestisci TargetInvocationException e lavoro con l'eccezione interna che è una COMException ... Esempio di codice di seguito (ho eseguito e testato anche questo):

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

Altri suggerimenti

Gestirai COMException e utilizzerai la proprietà ErrorCode di quell'oggetto eccezione. Normalmente nelle DLL di Visual Basic se si generano errori personalizzati, si solleva l'errore con: Err.Raise vbObjectError + 88, " Project1.Class1.Test3 () " ;, " Test di errore forzato "

In questo caso, sarà necessario sottrarre vbobjecterror (-2147221504) dalle eccezioni ErrorCode per ottenere il numero di errore effettivo. In caso contrario, utilizzare solo il valore ErrorCode.

Esempio di codice dll VB: (da Project1.Class1)

Public Sub Test3 ()

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

End Sub

Esempio di codice di gestione del consumo 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); }
    }

Il ErrorCode in questo test che ho appena completato restituisce 88 come previsto.

Voglio solo offrire un aggiornamento al codice di cattura di @ sharvell. A meno che tu non sia assolutamente sicuro che InnerException sia una COMException, è meglio testarla prima in sicurezza. Altrimenti avrai un'eccezione nel gestore delle eccezioni. Ops!

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
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top