Ausnahme des Typeninitialisierer aus InteropServices.COMException

  • VB.NET
  • .NET (FX) 3.0–3.5

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Ausnahme des Typeninitialisierer aus InteropServices.COMException

    Heyho,

    die ähnlichen Themen, die ich hier oder via Google fand, waren ungelöst oder sehr schwammig formuliert, sodass ich da keinen Weg der Lösung sehen konnte.

    Problem ist folgendes:

    Eine Form hat einen Button, welcher eine Funktion in einem Modul aufruft.
    Diese Funktion (ExcelSachen.testopenclose()) wird im Einzelschritt zwar aufgerufen aber der Einzelschrittdurchlauf springt nicht in das betreffende Modul sondern bricht schon beim Aufruf in der Form ab und fängt den Fehler im Catch-Block auf.
    Diese Exception wird von "System.Runtime.InteropServices.COMException" ausgelöst, aber dessen Fehlermeldung wird nicht durchgeschleift. Somit weiss ich nicht, was für eine Exception bei InteropServices anfällt :S

    Hat jemand eine Ahnung, wie ich an die Fehlermeldung von InteropServices komme?

    Der betreffende Code (Nachtrag: Option Strict On):

    VB.NET-Quellcode

    1. Private Sub btn_testopenclose_Click(sender As System.Object, e As System.EventArgs) Handles btn_testopenclose.Click
    2. Dim path As String = My.Settings.Rauheiten3040ImportPath
    3. Try
    4. OFD_RauheitenFile.InitialDirectory = path
    5. OFD_RauheitenFile.Filter = "Excel-Dateien|*.xls;*.xlsx"
    6. OFD_RauheitenFile.ShowDialog()
    7. tb_RauheitenFilename.Text = OFD_RauheitenFile.FileName
    8. ExcelSachen.testopenclose(tb_RauheitenFilename.Text)
    9. Catch ex As Exception
    10. Dim funcname As String = System.Reflection.MethodInfo.GetCurrentMethod.Name
    11. Hilfssachen.ShowError(funcname, ex.Message)
    12. Finally
    13. ' resetAll()
    14. End Try
    15. End Sub

    ExcelSachen.vb:

    VB.NET-Quellcode

    1. Imports Microsoft.Office.Interop.Excel
    2. Imports Microsoft.VisualBasic.ControlChars
    3. Module ExcelSachen
    4. Dim XLApp As New Microsoft.Office.Interop.Excel.Application
    5. Dim WBook As New Microsoft.Office.Interop.Excel.Workbook
    6. Dim WSheet As Microsoft.Office.Interop.Excel.Worksheet
    7. Dim openedXLFile As Boolean = False
    8. Public Sub testopenclose(ByVal filename As String)
    9. Try
    10. openXLFile(filename)
    11. closeXLFile()
    12. Catch ex As Exception
    13. MessageBox.Show(ex.Message)
    14. End Try
    15. End Sub
    16. ''' <summary>
    17. ''' Öffnet eine Excel-Datei und macht sie über das WBook-Objekt verfügbar
    18. ''' </summary>
    19. ''' <param name="filename">Dateiname (mit kompl. Pfad)</param>
    20. ''' <returns>0 = unhadled Error, 1 = all OK, 2 = already opened File</returns>
    21. ''' <remarks></remarks>
    22. Private Function openXLFile(ByVal filename As String) As UShort
    23. Try
    24. If Not openedXLFile Then
    25. WBook = XLApp.Workbooks.Open(filename)
    26. openedXLFile = True
    27. Return 1
    28. Else
    29. Return 2
    30. End If
    31. Catch ex As Exception
    32. MessageBox.Show("Fehler in Funktion ExcelSachen.openXLFile():" + CrLf + ex.Message, Nothing, MessageBoxButtons.OK)
    33. End Try
    34. Return 0
    35. End Function
    36. ''' <summary>
    37. ''' Schliesst die aktuelle geöffnete Excel-Datei
    38. ''' </summary>
    39. ''' <returns>true/false</returns>
    40. ''' <remarks></remarks>
    41. Private Function closeXLFile() As Boolean
    42. If openedXLFile Then
    43. Try
    44. WBook.Close()
    45. openedXLFile = False
    46. Return True
    47. Catch ex As Exception
    48. MessageBox.Show("Fehler in Funktion ExcelSachen.closeXLFile():" + CrLf + ex.Message, Nothing, MessageBoxButtons.OK)
    49. End Try
    50. Else
    51. Return False
    52. End If
    53. Return False
    54. End Function
    55. ''' <summary>
    56. ''' Die aktuell geöffnete Excel-Datei speichern
    57. ''' </summary>
    58. ''' <param name="filename"></param>
    59. ''' <returns>0 = unknown error, 1 = alles OK, 2 = Fehler beim speichern, 3 = keine XL-Datei offen</returns>
    60. ''' <remarks></remarks>
    61. Private Function saveXLFile(Optional ByVal filename As String = "none") As UShort
    62. If openedXLFile Then
    63. If filename = "none" Then
    64. Try
    65. WBook.Save()
    66. Return 1
    67. Catch ex As Exception
    68. MessageBox.Show("Fehler in Funktion ExcelSachen.saveXLFile(ohne filename):" + CrLf + ex.Message, Nothing, MessageBoxButtons.OK)
    69. Return 2
    70. End Try
    71. Else
    72. Try
    73. WBook.SaveAs(filename)
    74. Return 1
    75. Catch ex As Exception
    76. MessageBox.Show("Fehler in Funktion ExcelSachen.saveXLFile(mit filename):" + CrLf + ex.Message, Nothing, MessageBoxButtons.OK)
    77. Return 2
    78. End Try
    79. End If
    80. Else ' openedXLFile = false
    81. Return 3
    82. End If
    83. Return 0
    84. End Function
    85. End Module


    AUsgabe vom Direktfenster:

    Quellcode

    1. Einzelschritt: Nichtbenutzercode "Trixell_Master4.My.MySettingsProperty.get_Settings" wird übersprungen.
    2. Einzelschritt: Trixell_Master4.My.MySettings.get_Default-Eigenschaft wird übersprungen. Für einen Einzelschritt in Eigenschaften deaktivieren Sie unter "Extras->Optionen->Debuggen" die Option "Eigenschaften und Operatoren überspringen (nur verwaltet)".
    3. Einzelschritt: Nichtbenutzercode "Trixell_Master4.My.MySettingsProperty.get_Settings" wird übersprungen.
    4. Einzelschritt: Trixell_Master4.My.MySettings.get_Rauheiten3040ImportPath-Eigenschaft wird übersprungen. Für einen Einzelschritt in Eigenschaften deaktivieren Sie unter "Extras->Optionen->Debuggen" die Option "Eigenschaften und Operatoren überspringen (nurEinzelschritt: Nichtbenutzercode "Trixell_Master4.GetRauheiten.OFD_RauheitenFile.get" wird übersprungen.
    5. Einzelschritt: Nichtbenutzercode "Trixell_Master4.GetRauheiten.OFD_RauheitenFile.get" wird übersprungen.
    6. Einzelschritt: Nichtbenutzercode "Trixell_Master4.GetRauheiten.OFD_RauheitenFile.get" wird übersprungen.
    7. Einzelschritt: Nichtbenutzercode "Trixell_Master4.GetRauheiten.tb_RauheitenFilename.get" wird übersprungen.
    8. Einzelschritt: Nichtbenutzercode "Trixell_Master4.GetRauheiten.tb_RauheitenFilename.get" wird übersprungen.
    9. Eine Ausnahme (erste Chance) des Typs "System.Runtime.InteropServices.COMException" ist in Trixell-Master4.exe aufgetreten.
    10. Eine Ausnahme (erste Chance) des Typs "System.TypeInitializationException" ist in Trixell-Master4.exe aufgetreten.
    11. Einzelschritt: Nichtbenutzercode "System.Exception.Message.get" wird übersprungen.
    12. Eine Ausnahme (erste Chance) des Typs "System.Runtime.InteropServices.COMException" ist in Trixell-Master4.exe aufgetreten.
    13. Eine Ausnahme (erste Chance) des Typs "System.TypeInitializationException" ist in Trixell-Master4.exe aufgetreten.

    hirnwunde schrieb:

    beim Aufruf in der Form
    in der Form_Load?
    Nimm die Form_Shown, da werden Exceptions ordentlich geworfen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    in der Form_Load?


    Nein, Rod.
    Das im Load-Event das Debuggen gerne mal im Nirvana endet, weiss ich mittlerweile ;)
    Der Funktionsaufruf von ExcelSachen.testopenclose() findet über ein Button.Click-Event statt, siehe Zeile 9 im ersten Code-Block des ersten Posting ;)

    @KaskadekingDE
    Ich fand nun die wirkliche Fehlermeldung, wie hier drunter zu lesen ist. Stichwort InnerException.


    Wenn ich im Einzelschrittmodus mit der Maus über die Ausnahme fahre, kann ich mir ja die ganzen Informationen vom Objekt "ex" anschauen.
    Da ist auch eine Eigenschaft/Objekt (?) "InnerException".
    Deren Message-Eigenschaft ist:
    "Die COM-Klassenfactory für die Komponente mit CLSID {00020819-0000-0000-C000-000000000046} konnte aufgrund des folgenden Fehlers nicht abgerufen werden: 80040154."
    Auf Stack Overflow fand ich Informationen darüber, dass die Klasse nicht registriert sei.
    Als ich unter C:\Windows\assembly nachschaute, findet sich da aber die ganze Office-Interop-Familie.

    In den Assemblies steht als Processor-Architektur der ganzen Interop-Sachen "MSIL".
    Andere sind hingegen mit explizit mit "x86" oder "AMD64" gekennzeichnet.

    Ja, ich habe die 64Bit-Version von Office 2010 installiert.

    Bei den Projekt-Einstellungen unter "Kompilieren" habe ich nur die Platform-Auswahl von x86.

    Da ich aber eine nicht von mir (stammende und räudig) programmierte VBA-Geschichte in Excel habe, die, da sie mit massig Daten/Workbooks rumhantiert, gerne mal mehr als 3GB RAM benötigt, im Einsatz habe und ich auf dieses "Tool" angewiesen bin, benötige ich auch die 64Bit-Variante :(

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „hirnwunde“ ()

    hirnwunde schrieb:

    VB.NET-Quellcode

    1. OFD_RauheitenFile.ShowDialog()
    Zunächst solltest Du hier den Rückgabewert auswerten, falls Du Esc drückst:

    VB.NET-Quellcode

    1. If OFD_RauheitenFile.ShowDialog() <> Windows.Forms.DialogResult.OK Then
    2. Return
    3. End If
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    hier den Rückgabewert auswerten, falls Du Esc drückst:


    da diese Sub nur als Test-Sub gedacht ist und diese im Release-Stadium nicht mehr vorhanden ist (ebenso wie ExcelSachen.testopenclose()), war ich da etwas faul. Den Einzigen, den ich dann für UnhandledExceptions verantwortlich machen kann, bin ich selbst ;)

    Prinzipiell sind die Open/Save-FileDialog's bei mir mit abfang-Routinen ausgestattet, die genau Dein beschriebenes Verhalten auffangen. :)
    Dennoch danke für den Hinweis!
    Ok ... ich hab den Fehler gefunden.

    Es lag weder an den Mix aus x86 und 64Bit, noch an einer fehlenden Klassen-Registrierung.

    Es gab eine falsche Zuweisung meinerseits.
    Ich darf am Anfang nicht schon eine XLApp erstellen, nur den Typ als solches definieren.
    Das "erstellen" mittels New darf erst in der Funktion, die dies benötigt geschehen.

    Ich bitte, kundigere Forenmitglieder, meine durchaus falschen Angaben bzgl "erstellen", "definieren" und "zuweisen" zu korrigieren.

    Falsch (auf's Wesentliche gekürzt):

    VB.NET-Quellcode

    1. Imports Microsoft.Office.Interop.Excel
    2. Imports Microsoft.VisualBasic.ControlChars
    3. Module ExcelSachen
    4. Dim XLApp As New Microsoft.Office.Interop.Excel.Application
    5. Dim WBook As New Microsoft.Office.Interop.Excel.Workbook
    6. Dim WSheet As Microsoft.Office.Interop.Excel.Worksheet
    7. Dim openedXLFile As Boolean = False
    8. Private Function openXLFile(ByVal filename As String) As UShort
    9. Try
    10. If Not openedXLFile Then
    11. WBook = XLApp.Workbooks.Open(filename)
    12. openedXLFile = True
    13. Return 1
    14. Else
    15. Return 2
    16. End If
    17. Catch ex As Exception
    18. MessageBox.Show("Fehler in Funktion ExcelSachen.openXLFile():" + CrLf + ex.Message, Nothing, MessageBoxButtons.OK)
    19. End Try
    20. Return 0
    21. End Function
    22. Private Function closeXLFile() As Boolean
    23. If openedXLFile Then
    24. Try
    25. WBook.Close()
    26. openedXLFile = False
    27. Return True
    28. Catch ex As Exception
    29. MessageBox.Show("Fehler in Funktion ExcelSachen.closeXLFile():" + CrLf + ex.Message, Nothing, MessageBoxButtons.OK)
    30. End Try
    31. Else
    32. Return False
    33. End If
    34. Return False
    35. End Function
    36. End Module


    Funktionierender Code (der nicht zwangsläufig "richtig" sein muss):

    VB.NET-Quellcode

    1. Imports Microsoft.Office.Interop.Excel
    2. Module ExcelSachen
    3. Dim XLApp As Microsoft.Office.Interop.Excel.Application
    4. Dim WBook As Microsoft.Office.Interop.Excel.Workbook
    5. Dim WSheet As Microsoft.Office.Interop.Excel.Worksheet
    6. Dim openedXLFile As Boolean = False
    7. Private Function openXLFile(ByVal filename As String) As UShort
    8. Try
    9. If Not openedXLFile Then
    10. XLApp = New Microsoft.Office.Interop.Excel.Application
    11. WBook = XLApp.Workbooks.Open(filename)
    12. openedXLFile = True
    13. Return 1
    14. Else
    15. Return 2
    16. End If
    17. Catch ex As Exception
    18. Dim funcname As String = System.Reflection.MethodInfo.GetCurrentMethod.Name
    19. Hilfssachen.ShowError(funcname, ex.Message)
    20. End Try
    21. Return 0
    22. End Function
    23. Private Function closeXLFile() As Boolean
    24. If openedXLFile Then
    25. Try
    26. WBook.Close()
    27. XLApp.Quit()
    28. openedXLFile = False
    29. Return True
    30. Catch ex As Exception
    31. Dim funcname As String = System.Reflection.MethodInfo.GetCurrentMethod.Name
    32. Hilfssachen.ShowError(funcname, ex.Message)
    33. End Try
    34. Else
    35. Return False
    36. End If
    37. Return False
    38. End Function
    39. End Module


    Eigentlich muss hier noch eine Methode zum freigeben aller COM-Resourcen erdacht/gesucht werden.
    Denn aktuell ist es so, dass Excel32.exe solang geöffnet bleibt, wie das Programm läuft.
    Sollte dies regulär beendet werden, wird auch Excel geschlossen.
    Sollte das Programm mit einer Unhandled Exception in einem undefienierten Zustand geraten und es abgeschossen werden muss, bleibt auch der Excel-Prozess offen.

    Da muss ich mich also noch drum kümmern ;)

    Danke @RodFromGermany und @KaskadekingDE für Eure Beiträge!
    @hirnwunde
    Ich hab' 'mal diesen Code gefunden (dotnet-snippets.de) und erfolgreich verwendet:

    VB.NET-Quellcode

    1. ''Zugang zur API ''user32''
    2. Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Integer, ByRef lpdwProcessId As IntPtr) As IntPtr
    3. ''Beenden eines speziellen Excel Prozesses, anhand seiner Id
    4. Private Shared Sub killExcelInstanceById(ByRef xlsApp As Excel.Application)
    5. Dim processId As IntPtr = Nothing
    6. ''API Funktion, out val: processId
    7. GetWindowThreadProcessId(xlsApp.Hwnd, processId)
    8. ''Prozess erstellen
    9. Dim excelProcess As Process = Process.GetProcessById(processId.ToInt32())
    10. Debug.WriteLine(processId)
    11. ''die lang ersehnte Erlösung, für den speziellen Excel Process der XlsApp :)
    12. excelProcess.Kill()
    13. End Sub

    Eine letzte Frage habe ich noch, dazu sollte kein neuer Thread nötig sein..

    RodFromGermany schrieb:

    in der Form_Load?
    Nimm die Form_Shown, da werden Exceptions ordentlich geworfen.


    hirnwunde schrieb:

    RodFromGermany schrieb:
    in der Form_Load?

    Nein, Rod.
    Das im Load-Event das Debuggen gerne mal im Nirvana endet, weiss ich mittlerweile


    Kann jemand das für mich etwas detaillierter formulieren?
    Ich verstehe nicht, warum Exceptions von dem Ereignis Form_Load nicht "ordentlich geworfen" werden sollen?
    @Bruno
    Guckst Du DBExtensions: Fehler bei Initialaisierung einer Access-Datenbank, Post#14
    Das Verhalten bei x32 und x64 und AnyCpu Kompilierung ist unterschiedlich BY DESIGN. Kannst Du nix machen.
    @Bruno Vielleicht solltest Du da ein wenig experimentieren mit gezieltem Werfen von Exceptions in der Form_Load im Gegensatz zu Form_Shown oder einer Button_Click.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!