Riesci a rilevare un’eccezione nativa nel codice C #?

Nel codice C # è ansible rilevare un’eccezione nativa generata da una libreria non gestita in profondità? Se è così devi fare qualcosa di diverso per prenderlo o fa un tentativo standard … prendilo?

È ansible utilizzare Win32Exception e utilizzare la relativa proprietà NativeErrorCode per gestirlo in modo appropriato.

// http://support.microsoft.com/kb/186550 const int ERROR_FILE_NOT_FOUND = 2; const int ERROR_ACCESS_DENIED = 5; const int ERROR_NO_APP_ASSOCIATED = 1155; void OpenFile(string filePath) { Process process = new Process(); try { // Calls native application registered for the file type // This may throw native exception process.StartInfo.FileName = filePath; process.StartInfo.Verb = "Open"; process.StartInfo.CreateNoWindow = true; process.Start(); } catch (Win32Exception e) { if (e.NativeErrorCode == ERROR_FILE_NOT_FOUND || e.NativeErrorCode == ERROR_ACCESS_DENIED || e.NativeErrorCode == ERROR_NO_APP_ASSOCIATED) { MessageBox.Show(this, e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } } 

Catch without () rileverà eccezioni compatibili con CLS incluse le eccezioni native.

 try { } catch { } 

Vedere la seguente regola FxCop per maggiori informazioni http://msdn.microsoft.com/en-gb/bb264489.aspx

Il livello di interoperabilità tra C # e il codice nativo convertirà l’eccezione in un modulo gestito, consentendole di essere catturato dal codice C #. A partire da .NET 2.0, catch (Exception) dovrebbe rilevare qualcosa di diverso da un errore irreversibile.

Da qualche parte con .NET Reflector ho visto il seguente codice:

 try { ... } catch(Exception e) { ... } catch { ... } 

Hmm, C # non consente di lanciare un’eccezione non derivante dalla class System.Exception. E per quanto ne so, qualsiasi eccezione fatta dal marshaller di interoperabilità è racchiusa nella class di eccezioni che eredita System.Exception.

Quindi la mia domanda è se è ansible rilevare un’eccezione che non è un System.Exception.

Questo dipende dal tipo di eccezione nativa di cui si sta parlando. Se ti riferisci a un’eccezione SEH, allora il CLR farà una delle due cose.

  1. Nel caso di un codice di errore SEH noto lo mapperà all’eccezione .Net appropriata (es. OutOfMemoryException)
  2. Nel caso di un codice non mappabile (E_FAIL) o sconosciuto, verrà semplicemente lanciata un’istanza SEHException .

Entrambi saranno catturati con un semplice blocco “catch (Exception)”.

L’altro tipo di eccezione nativa che può attraversare il confine nativo / gestito sono le eccezioni C ++. Non sono sicuro di come sono mappati / gestiti. La mia ipotesi è che da quando Windows implementa le eccezioni C ++ su SEH, vengono mappate allo stesso modo.

Quasi, ma non del tutto. Conoscerai l’eccezione

 try { ... } catch (Exception e) { ... } 

ma avrai ancora problemi potenziali. Secondo MSDN , per assicurare che i distruttori di eccezioni siano chiamati dovresti prendere come:

 try { ... } catch { ... } 

Questo è l’unico modo per assicurare che venga chiamato un distruttore di eccezioni (anche se non sono sicuro del perché). Ma questo ti lascia con il compromesso della forza bruta contro una ansible perdita di memoria.

Per inciso, se si utilizza l’approccio (Eccezione e), è necessario conoscere i diversi tipi di eccezioni che si potrebbero incontrare. RuntimeWrappedException è ciò che verrà mappato a qualsiasi tipo non eccezione gestito (per le lingue che possono lanciare una stringa) e verranno mappati altri, ad esempio OutOfMemoryException e AccessViolationException. INTERFACCIA di COM HRESULTS o eccezioni diverse da E___FAIL verranno mappate a COMException e infine alla fine si avrà SEHException per E_FAIL o qualsiasi altra eccezione non mappata.

Quindi cosa dovresti fare? La scelta migliore è non gettare eccezioni dal tuo codice non gestito! Hah. In realtà, se hai una scelta, imposta barriere e fallimenti che rendono la scelta di ciò che è peggio, una possibilità di perdita di memoria durante la gestione delle eccezioni, o non sapere quale sia il tipo di eccezione.

Se usi a

 try { } catch(Exception ex) { } 

rileverà TUTTE le eccezioni, a seconda di come chiamate le librerie esterne, potresti ottenere un’eccezione correlata alla com che incapsula l’errore, ma colpirà l’errore.

Una presa di prova standard dovrebbe fare il trucco in cui credo.

Mi imbatto in un problema simile con un’eccezione System.data che genera un’eccezione sqlClient che non è stata aggiunta, aggiungendo un try..catch nel mio codice ha fatto il trucco nell’istanza