Das Notes Forum

Best Practices => Diskussionen zu Best Practices => Thema gestartet von: ata am 30.01.08 - 11:46:53



Titel: COM-Schnittstelle MS Excel
Beitrag von: ata am 30.01.08 - 11:46:53
Hallo @All,

im Laufe der Zeit steht man immer wieder vor den gleichen Anforderungen. Da ich in der letzten Zeit häufiger auf Excel angesprochen wurde, kam mir der Gedanke hier eine Sammlung von rudimentären Funktionen einzubringen, die man immer wieder im Zusammenhang mit COM-Schnittstellenprogrammierung braucht...

Die Funktionen können dann in einer Library oder auch direkt verwendet werden. Sie basieren auf den aktuellen COM-Klassenobjekten.

Für eine bessere Navigation würde ich pro Funktion eine Antwort erstellen - die Überschrift enthält den Funktionsnamen.

Gibt es daran Interesse?

Toni



*** edit ***


Hier der Beginn einer Auflistung aller bisherigen Funktionen:

Excel als Variant initialisieren
Function xlGet( ... ) (http://atnotes.de/index.php?topic=39862.msg253615#msg253615)

Excel im Backend schließen
Function xlClose( ... ) (http://atnotes.de/index.php?topic=39862.msg253622#msg253622)

Excel im Frontend anzeigen oder verbergen
Function xlShow( ... ) (http://atnotes.de/index.php?topic=39862.msg253644#msg253644)

Zellinhalte auslesen - mit der Möglichkeit mehrere Zellen einer Zeile einzulesen
Function xlGetCellValues( ... ) (http://atnotes.de/index.php?topic=39862.msg253628#msg253628)

Werte in eine Excel-Zelle schreiben - mit der Option einer Zellformatierung für Darstellungsformat
Function xlSetCell( ... ) (http://atnotes.de/index.php?topic=39862.msg253782#msg253782)

Hilsfunktion zum Initialisieren der möglichen 256 Spaltennamen ( A - IV ) in eine Textliste
Function xlGetColumnNames( ) (http://atnotes.de/index.php?topic=39862.msg253988#msg253988)

Importieren einer ASCII-Datei
Function xlDataImport(...) (http://atnotes.de/index.php?topic=39862.msg253633#msg253633)

Einen Tabellenbereich nach einer Spalte sortieren
Function xlSort( ... ) (http://atnotes.de/index.php?topic=39862.msg253630#msg253630)

Zellen in Höhe und Breite automatisch anpassen - für gesamtes Tabellenblatt
Function xlAutoFit( ... )  (http://atnotes.de/index.php?topic=39862.msg253625#msg253625)

Einen Tabellenbereich in Höhe und Breite anpassen
Function xlFitRange( ... ) (http://atnotes.de/index.php?topic=39862.msg253724#msg253724)

Zellen miteinander verbinden
Function xlMergeCells(...) (http://atnotes.de/index.php?topic=39862.msg253649#msg253649)

Schriftformatierung für einen Bereich - Schriftart und -größe, Gewicht und Kursiv
Function xlFormatFont( ... ) (http://atnotes.de/index.php?topic=39862.msg253769#msg253769)

Tabellenblatt an einer bestimmten Stelle einfrieren
Function xlFreeze( ... ) (http://atnotes.de/index.php?topic=39862.msg253629#msg253629)


... Fortsetzung folgt...


Titel: Function xlGet( ... )
Beitrag von: ata am 30.01.08 - 12:04:26
Code:
Function xlGet( sPath As String , bVisible As Variant , xl As Variant , xlWbk As Variant ) As Variant
   ' # Initialisierung einer Excel-Anwendung.
   ' # sPath => String-Variable für die vollständige Pfadangabe einer Excel-Datei oder Leersting
   ' # bVisible => True oder False für die Sichtbarkeit im Frontend
   ' # xl => Variant-Variable für das Excel-Objekt
   ' # xlWbk => Variant-Variable für die Excel-Datei
   ' # Rückgabe ist xl Als Applikation
   '
   On Error Resume Next
   '
   Set xl = GetObject("", "Excel.Application")
   '
   If Err = 208 Then  '  Fehler 208 tritt auf wenn Excel noch nicht läuft
     Err = 0
     Set xl = CreateObject( "Excel.Application" )   'Excel wird initialisiert
   End If
   '
   If Not xl Is Nothing Then
      XL.Visible = bVisible
      If sPath <> "" Then
         Set xlWbk = xl.Workbooks.Open( sPath ) ' # bestehende Datei öffnen
      Else
         Set xlWbk = xl.Workbooks.Add ' # neue Datei verwenden
      End If
      Print "OK - Excel konnte initialisiert werden"
      Set xlGet = xl
   Else
      Set xlGet = Nothing
   End If
End Function

Eine Validierung, ob eine bestimmte Datei am angegebenen Pfad existiert muß zuvor separat durchgeführt werden...

Toni


Titel: Grundgerüst einer Excel-Klasse
Beitrag von: Axel am 30.01.08 - 12:21:04
Code:
'--- Deklaration von API-Funktionen ---
Declare Function SetActiveWindow Lib "user32" Alias "SetActiveWindow" (Byval Hwnd As Long) As Long
Declare Function SetForegroundWindow Lib "user32" (Byval Hwnd As Long) As Long
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (Byval ClassName As String, Byval lpWindowName As Long) As Long

Class cExcel

  objExcel As Variant
  objSheet As Variant   


'Konstruktor
  Sub New
    Set objExcel = Nothing

    On Error Resume Next

    Set objExcel = GetObject("", "Excel.Application")
    If Err = 208 Then  '  Fehler 208 tritt auf wenn Excel noch nicht läuft
      Err = 0
      Set objExcel = CreateObject("Excel.Application")   'Excel wird "unsichtbar" gestartet
    End If  'If Err = 208 Then
 
  End Sub


'Destruktor-Prozedur
  Sub Delete
    Set objExcel = Nothing         
  End Sub


'Beendet den Excel-Task, es werden alle offenen Arbeitsmappen ohne Speicherung geschlossen
  Sub Quit
    objExcel.DisplayAlerts = False  'Warnmeldungen ausschalten
    Call objExcel.Quit
  End Sub


' Macht den Excel-Task sichbar
  Sub SetVisible
    objExcel.Visible = True  'Excel sichtbar machen
  End Sub


'Bringt Word als Vollbild in den Vordergrund
  Sub ActivateExcel

    Dim hWnd As Long

    'Handle für Excel-Application ermittlen
    hWnd = FindWindow("XLMAIN", 0)
    If hWnd = 0 Then Exit Sub

    'Excel aktivieren und in den Vordergrund bringen
    Call SetActiveWindow(hWnd)
    Call SetForegroundWindow(hWnd)
  End Sub


'  Erstellt eine neue Arbeitsmappe     
  Sub NewWorkbook
    Call objExcel.Workbooks.Add
    Set objSheet = objExcel.Workbooks(1).Worksheets(1)
  End Sub


'  Öffnet eine Arbeitsmappe     
  Sub OpenWorkbook(strFileName As String)
    Call objExcel.Workbooks.Open (strFileName)
    Set objSheet = objExcel.Workbooks(1).Worksheets(1)
  End Sub


'  Schreibt einen Wert in die angegebene Zelle
'  Es werden nur maximal 912 Zeichen übernommen
  Sub SetCellValue(sZiel As Variant, varValue As Variant)

    Dim sTmp As String
    Dim result As Variant

    sTmp = Cstr(varValue)

    If Len(sTmp) > 912 Then
      objSheet.Range(sZiel).Value = Left(sTmp,912)
    Else
      objSheet.Range(sZiel).Value = sTmp
    End If  'If Len(varValue) > 912 Then
  End Sub

End Class


Der Code ist an manchen Ecken noch etwas rudimentär und stellenweise auch noch felxibler gestaltbar. Es fehlt auch noch eine durchgängige Fehlerbehandlung.


Axel
 


Titel: Function xlClose( ... )
Beitrag von: ata am 30.01.08 - 12:21:55
... zum Ende des Codes sollte die Excel-Datei aufgeräumt werden, damit die Anwendung nicht im Backend erhalten bleibt.
... die Funktion sollte auch in einem Fehlerhandling eingesetzt werden

Code:
Function xlClose( xl As Variant , xlWbk As Variant ) As Variant
   ' # Excel ohne Speicherdialog schließen
   ' # xl => Variant => Excal-Applikation
   ' # xlWbk => Variant => Excel-Datei
   ' # Rückgabe => True
   '
   xl.DisplayAlerts = False  'Warnmeldungen ausschalten
   '
   Call xlWbk.Close( False )
   '
   Call xl.Quit(  )
   Set xl = Nothing
   '
   xlClose = True
   '
End Function


Titel: Function xlAutoFit( ... )
Beitrag von: ata am 30.01.08 - 12:29:01
... alle Spalten und Zeilen eines Arbeitsblattes in der Breite optimieren

Code:
Function xlAutoFit( xl As Variant , xlSheet As Variant )
   ' # Alle Spalten automatisch optimiert in der Breite formatieren.
   ' # xl => Variant => Die Excel-Anwendung
   ' # xlSheet => Variant => das gewünschte Excel-Arbeitsblatt
   '
   xlSheet.Cells.Select
   '
   xl.Selection.Columns.AutoFit
   xl.Selection.Rows.AutoFit
   '
End Function


Titel: Function xlGetCellValues( ... )
Beitrag von: ata am 30.01.08 - 12:34:49
... dynamische Funktion zum zeilenorientierten Auslesen von Excel-Zell-Werten

Es ist zu beachten, daß die Rückgabe "vRes" immer ein String-Array ist und als Variant deklariert werden muß

...
Dim vRes As Variant

vRes = xlGetCellValues( xlSheet,  1 , 10 ) ' # liest die 10. Spalte der 1. Reihe des Tabellenblattes ein
vRes = xlGetCellValues( xlSheet , 1 , 0 ) ' # liest alle 255 Spalten der 1. Reihe des Tabellenblattes  ein
vRes = xlGetCellValues( xlSheet , 1 , -10 ) ' # liest die ersten 10 Spalten der 1. Reihe des Tabellenblattes ein
vRes = xlGetCellValues( xlSheet , 1 , 99999 ) ' # liest bis zur ersten leeren Spalte der 1. Reihe des Tabellenblattes ein

Code:
Function xlGetCellValues( xlSheet As Variant , row As Variant , column As Variant ) As Variant
   ' # Einlesen von Excel-Werten
   Dim sDummy( 0 to 0 ) As String
   Dim vValue As Variant
   Dim i As Integer
   '
   On Error Goto GeneralError
   '
   If column > 0 And column <= 255 Then
      sDummy( 0 ) = xlSheet.Cells( row , column ).Value
      xlGetCellValues =  sDummy
   Else
      vValue = sDummy
      If column = 0 Then
         column = 254
      Elseif column = 99999 Then
          i = 1
          While Trim( xlSheet.Cells( row , i ).Value ) <> ""
             i = i + 1
          Wend
          column = i
      Else
         column = ( column * ( -1 ) ) - 1
      End If
      Redim vValue( 0 to column )
      For i = 0 to column
         vValue( i ) = Trim( Cstr( xlSheet.Cells( row , i + 1 ).Value ) )
      Next
      xlGetCellValues =  vValue
   End If
WayOut:
   Exit Function
GeneralError:
   xlGetCellValues = sDummy
   Resume WayOut
End Function


Titel: Function xlFreeze( ... )
Beitrag von: ata am 30.01.08 - 12:43:47
... kann man beim Export gut verwenden, um ein Arbeitsblatt an einer bestimmten Stelle zu fixieren...

Code:
Function xlFreeze( xl As Variant , xlSheet As Variant , row As Long , column As Integer ) As Variant
   ' # Einfrieren eines Arbeitsblattes für besseres Scrollen.
   Call xlSheet.Select
   Call xlSheet.Cells( row , column ).Select
   xl.ActiveWindow.FreezePanes = True
End Function


Titel: Function xlSort( ... )
Beitrag von: ata am 30.01.08 - 12:47:34
... sortieren eines Bereiches eines Arbeitsblattes anhand eines Spaltenbereiches...

Ein Aufruf kann wie folgt aussehen:
' # Sortieren der Spalten 1 - 6 von Zeile 2 bis 21 anhand der ersten Spalte "A"
Call xlSort( xlSheet , "A2:F21" , "A2:A21" )


Code:
Function xlSort( xlSheet As Variant , sDataRange As String , sColumnRange As String ) As Variant
   ' # sDataRange => der gesamte Bereich mit Daten => "A2:F20" bei Kopfzeile, 5 Spalten und 19 Daten-Zeilen
   ' # sColumnRange => Die Spalte, nach der sortiert werden soll => "A2:A20" bei Kopfzeile und 19 Daten-Zeilen
   Call xlSheet.Range( sRange ).Sort( xlSheet.Range( sColumnRange ) , 1 )
End Function


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: Axel am 30.01.08 - 12:59:43
Formatieren von Zellen

Code:
'Konstanten für die vertikale Ausrichtung innerhalb der Zellen
Const xlVAlignTop = -4160
Const xlVAlignBottom = -4107
Const xlVAlignCenter = -4108

'Formatiert ein Arbeitsblatt mit den Attributen vertikale Textausrichtung oben und
'optimale Spaltenbreite
  Sub FormatRangeAlignment
    objSheet.Cells.Select  'Gesamtes Arbeitsblatt markieren
    objExcel.Selection.VerticalAlignment = xlVAlignTop  'Vertikale Ausrichtung nach oben
    objExcel.Selection.Columns.AutoFit  'Optimale Spaltenbreite
    objExcel.Selection.Rows.AutoFit  'Optimale Zeilenhöhe
    objSheet.Range("A1").Select           
End Sub


'Formatiert ein Arbeitsblatt mit der entsprechenden Schriftart und -grösse
'Aufruf ...FormatRangeFont("Arial", 10)

Sub FormatRangeFont(strFontName As String, iFontSize As Integer)
  objSheet.Cells.Select  'Gesamtes Arbeitsblatt markieren
  objExcel.Selection.Font.Name = strFontName  'Schriftart
  objExcel.Selection.Font.Size  = iFontSize  'Zeichengrösse setzen
  objSheet.Range("A1").Select           
End Sub


' Formatiert einen Bereich mit entsprechender Breite und Zeilenumbruch
'Aufruf ...FormatRangeWidth("A:A") für Spalte A

Sub FormatRangeWidth(sZiel As Variant)         
  objSheet.Columns(sZiel).Select
  objSheet.Columns(sZiel).ColumnWidth = 28
  objExcel.Selection.WrapText = True  'Zeilenumbruch zulassen
  objSheet.Range("A1").Select
End Sub

Axel


Titel: Function xlDataImport( ... )
Beitrag von: ata am 30.01.08 - 13:15:35
... Es kann manchmal performanter sein, eine Text-Datei nach Excel zu importieren, als mühsam alle Zeilen und Spalten "zu Fuß mit der Hand am Arm" zu befüllen...


' # als Beispiel eine Textdatei mit 6 Spalten
Dim vDataTypes( 0 to 5 ) As Integer
vDataTypes( 0 ) = 1    ' # 1. Spalte automatisch - implizit
vDataTypes( 1 ) = 2    ' # 2. Spalte als Text
vDataTYpes( 2 ) = 4    ' # 3. Spalte als Datum-Zeit-Wert => t.m.j
vDataTypes( 3 ) = 2    ' # 4. Spalte als Text
vDataTypes( 4 ) = 9    ' # 5. Spalte nicht importieren
vDataTypes( 5 ) = 1    ' # 6. Spalte automatisch

Call xlDataImport( xlSheet , "C:\Temp\Test.csv" , ";" , vDataTypes , "A1" )


Code:
Function xlDataImport( xlSheet As Variant , sFilePath As String , sSep As String , vDataTypes As Variant , sStartPos As String) As Variant
   ' # importieren einer ASCII-Datei nach Excel
   ' # xlSheet => Variant => Arbeitsblatt als Excel-Objekt
   ' # sFilePath => String => vollständiger Pfad der zu importierenden Text-Datei
   ' # sSep => String => Separator, mit dem die Daten voneinander getrennt sind
   ' # vDataTypes => String-Array => Alias der Datentypen für die importierten Spalten - erster Wert = erste Spalte
   ' # sStartPos => String => z.B. "A1" für die erste Zelle in der ersten Spalte
   '
    With xlSheet.QueryTables.Add( "TEXT;" & sFilePath, xlSheet.Range( sStartPos ))
        .Name = "Adressen"
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .RefreshStyle = 1 ' xlInsertDeleteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .TextFilePromptOnRefresh = False
        .TextFilePlatform = 1252 ' # Windows Ansi
        .TextFileStartRow = 1
        .TextFileParseType = 1 ' xlDelimited
        .TextFileTextQualifier = -4142 ' xlTextQualifierNone
        .TextFileConsecutiveDelimiter = False
        .TextFileTabDelimiter = False
        .TextFileSemicolonDelimiter = False
        .TextFileCommaDelimiter = False
        .TextFileSpaceDelimiter = False
        .TextFileOtherDelimiter = sSep
        .TextFileColumnDataTypes = vDataTypes
        .TextFileTrailingMinusNumbers = True
        .Refresh False
    End With
   '
End Function


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: MadMetzger am 30.01.08 - 13:23:50
Ist es nicht sinnvoll, diesen Code in eine Klasse in einer SkriptLib zu verpacken, im initialize der Bibliothek eine globale Variable mit einem Objekt der Klasse zu besetzen und im terminate den Destruktor delete auf diesem Objekt wieder aufzurufen. So würde man unterbinden, dass dieses vergessen wird.


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: ata am 30.01.08 - 13:24:57
@Axel

... ich habe mir die Codeschnipsel von dir angesehen, ich nehm mir die mal als Baumaterial für die nächsten Funktionen - OK ?

Aus Gründen der Performance versuche ich so weit es geht auf Selection zu verzichten, da dies immer ziemlich auf die Geschwindigkeit geht...

Toni


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: ata am 30.01.08 - 13:34:47
@Markus,

... mal schaun, was daraus mal wird. Mein Ziel ist es erstmal die verschiedensten Schnipsel zu sammeln und vorzutragen. Der Code von Axel ist zunächst nicht lauffähig, da er globale Variablen verwendet - die Funktionen sind lauffähig, sie benötigen lediglich die richtigen Parameter bei deren Übergabe...

Aus Gründen der Performance versuche ich die Lib's so klein wie möglich zu halten, um nicht einen Riesen-Ballast zu laden, den ich dann gar nicht jedes Mal komplett brauche. Daher schwebt mir ein gestaffelter Aufbau von Lib's vor

Library Excel_Fundamentals => mit GetExcel, CloseExcel, ShowExcel, HideExcel...
Library Excel_Save => mit Speicherfunktionalitäten, Export aus Excel nach ASCII etc...
Library Excel_Import => Import-Funktionen
Library Excel_Formating => mit Funktionen zur Formatierung
Library Excel_Sort => verschiedene Sortierfunktionen
...

... so in der Art ungefähr...

Toni


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: Axel am 30.01.08 - 13:43:30
@Axel

... ich habe mir die Codeschnipsel von dir angesehen, ich nehm mir die mal als Baumaterial für die nächsten Funktionen - OK ?

Aber na klar doch.


Axel


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: Axel am 30.01.08 - 13:48:11
@Markus,

... mal schaun, was daraus mal wird. Mein Ziel ist es erstmal die verschiedensten Schnipsel zu sammeln und vorzutragen. Der Code von Axel ist zunächst nicht lauffähig, da er globale Variablen verwendet -
...

Richtig. Da kommt daher, dass der Code aus verschiedenen Versionen einer Klasse herauskopiert wurden.

Wenn sie losgelöst eingesetzt werden sollen, ist noch etwas Handarbeit notwendig.


Axel


Titel: Sub xlShow( ... )
Beitrag von: ata am 30.01.08 - 13:55:08
Eine Excel-Anwendung verbergen oder anzeigen

... nach einem Export anzeigen

Call xlShow( xl , True )


... eine geöffnete Excel-Anwendung unsichtbar schalten, zum Beispiel um über LotusScript einen Eingabedialog sichtbar zu machen...

Call xlShow( False )

Code:
Sub xlShow( xl As Variant , bVisible As Variant )
   ' # Excel sichtbar oder unsichtbar machen.
   ' # xl => Variant => Excel-Anwendung
   ' # bVisible => Variant => True für Anzeigen, false für Verbergen
   '
   xl.Visible = bVisible
   '
End Sub


Titel: Function xlMergeCells( ... )
Beitrag von: ata am 30.01.08 - 14:28:40
... mehrere Zellen eines Arbeitsblatts miteinander verbinden...

Ein Aufruf kann wie folgt aussehen:
Call xlMergeCells( xlSheet , "A3:D5" ) ' # verbindet im Sheet die Zellen des Bereiches zu einer Zelle

Code:
Function xlMergeCells( xlSheet As Variant , sRange As String ) As Variant
   ' # Excel-Zellen eines Bereiches miteinander verbinden.
   ' # xlSheet => Variant => Excel-Arbeitsblatt
   ' # sRange => String => z.B. "A3:D5"
   '
   xlSheet.Range( sRange ).Merge
   '
End Function


Titel: Function SetExcelColumnWidth( ... )
Beitrag von: ata am 30.01.08 - 14:46:20
... Spalten in der Breite formatieren

z.B. Die ersten drei Spalten und die 5. Spalte...
   Call SetExcelColumnWidth( xlSheet , "A:C" , 24.05 )
   Call SetExcelColumnWidth( xlSheet , 5 , 24.05 )


Code:
Function SetExcelColumnWidth( xlSheet As Variant , vRange As Variant , vColWidth As Variant )
   ' # Excel-Spalten auf eine bestimmte Breite formatieren.
   ' # xlSheet => Variant => das Excel-Arbeitsblatt
   ' # vRange => Variant => z.B. "A:C" für die ersten 3 Spalten und die 5.
   ' # vColWidth => Variant => gewünschte Breite der Spalte => z.B. 5.05
   '
   xlSheet.Columns( vRange ).ColumnWidth = vColWidth
   '
End Function


Titel: Function SetExcelCellColor( ... )
Beitrag von: ata am 30.01.08 - 15:24:01
... Excel-Zellen farbig hervorheben...

Es gibt in Excel die Zahlen 0 - 56 für Farbwerte
0 = keine Farbe
1 = schwarz
2 = weiß
3 = rot
...

Ich habe mir eine Hilfstabelle gebaut, in der alle Farben aufgeführt sind...

z.B.
Call SetExcelCellColor( xlSheet , "A1:D5" , 3 , 2 ) ' # Hintergrund rot, Schriftfabe weiß

Code:
Function SetExcelCellColor( xlSheet As Variant , sRange As String , iColBG As Integer , iColText As Integer ) As Variant
   ' # Die Text- und Hintergrundfarbe eines Bereichs in Excel bestimmen
   ' # xlSheet => Variant => das Excel-Arbeitsblatt
   ' # sRange => String => z.B. "A1:E5" für die ersten 5 Zeilen der Spalten A bis E
   ' # iColBG As Integer
   ' # iColText As Integer
   '
   xlSheet.Range( sRange ).Interior.ColorIndex = iColBG
   xlSheet.Range( sRange ).Font.ColorIndex = iColText
   '
End Function


Titel: Function xlFitRange( ... )
Beitrag von: ata am 31.01.08 - 10:34:06
... aus den bisherigen Funktionen habe ich eine dynamische Funktion zur Höhe und Breite von Spalten / Reihen gebastelt...

Ein Aufruf kann wie folgt aussehen:
Call xlFitRange( xl , xlSheet , "" , "" ) ' # Autofit des gesammten Arbeitsblattes => geht über Select des Arbeitsblattes
Call xlFitRange( xl , xlSheet , "B1:E4" , "" ) ' # Autofit Spalten "B" bis "E" und angepasste Höhe bei Zeilen "1" bis "4"
Call xlFitRange( xl , xlSheet , "B1:E1" , "50 x 40" ) ' # Spalten "B" bis "E" mit Breite "50" und nur Zeile 1 mit einer Höhe von "40"

Hinweis:
Maßangaben können unterschiedliche Auswirkungen haben, je nach Ländereinstellungen, daher sollten nur Ganzzahlen verwendet werden.
Die verschiedenen Excel-Versionen kennen unterschiedlich viele Spalten und Zeilen. Die Begrenzung auf 256 Spalten "IV" und 65536 Zeilen pro Arbeitsblatt muß je nach Excel-Version extra validiert werden.

Code:
Function xlFitRange( xl As Variant , xlSheet As Variant , vRange As Variant , vParam As Variant )
   ' # Bestimmte Excel-Bereiche auf Breite und Höhe formatieren.
   ' # xlSheet => Variant => das Excel-Arbeitsblatt
   ' # vRange => Variant => z.B. "A:E" für die ersten 5 Spalten
   ' # vParam => Variant => gewünschte Formatierung des Bereiches "Breite x Höhe" => z.B. "50,05x20,5" ( 0 = Spalte verbergen, bei Leerstring Autofit )
   '
   On Error GoTo GeneralError
   '
   Dim vWidth As Variant
   Dim vHeight As Variant
   Dim vRangeColumn As Variant
   Dim vRangeRow As Variant
   Dim vValue As Variant
   Dim i As Integer
   Dim sValue As String
   Dim sMsg As String
   '
   ' # Parsen der Parameter
   ' # ... Breite und Höhe
   If Instr( Cstr( vParam ) , "x" ) > 0 Then
      vValue = Split( Trim(Cstr(vParam)) , "x" )
      vWidth =  Trim(Cstr(vValue(0)))
      vHeight =  Trim(Cstr(vValue(1)))
   Else
      vWidth = Cstr( vParam )
      vHeight = Cstr( vParam )
   End If
   ' # ... Bereich
   If Instr( Trim(Cstr(vRange)) , ":" ) Then
      vValue = Split( Trim(Cstr( vRange )) , ":" )
      ' # Spalte von Reihe trennen
      For i = 1 to len( vValue( 0 ) )
         sValue = Mid$( vValue( 0 ) , i , 1 )
         If IsNumeric( sValue ) Then
            vRangeRow = vRangeRow + sValue
         Else
            vRangeColumn = vRangeColumn + sValue
         End If
      Next
      '
      If vRangeColumn <> "" Then vRangeColumn = vRangeColumn & ":"
      If vRangeRow <> "" Then vRangeRow = vRangeRow & ":"
      '
      For i = 1 to len( vValue( 1 ) )
         sValue = Mid$( vValue( 1 ) , i , 1 )
         If IsNumeric( sValue ) Then
            vRangeRow = vRangeRow + sValue
         Else
            vRangeColumn = vRangeColumn + sValue
         End If
      Next
      '
   Else
      For i = 1 to len( vRange )
         sValue = Mid$( vRange , i , 1 )
         If IsNumeric( sValue ) Then
            vRangeRow = vRangeRow + sValue
         Else
            vRangeColumn = vRangeColumn + sValue
         End If
      Next
      If vRangeColumn <> "" Then vRangeColumn = vRangeColumn & ":" & vRangeColumn
      If vRangeRow <> "" Then vRangeRow = vRangeRow & ":" & vRangeRow
   End If
   '
   ' # Formatieren des Bereiches nach Breite und Höhe
   If Trim(Cstr( vRange )) = "" Then
      xlSheet.Cells.Select
      xl.Selection.Columns.AutoFit
      xl.Selection.Rows.AutoFit
      xlSheet.Range( "A1" ).Select   
   Else
      If Lcase(Cstr( vParam )) = "" Then
         If vRangeColumn <> "" Then xlSheet.Columns( vRangeColumn ).AutoFit
         If vRangeRow <> "" Then xlSheet.Rows( vRangeRow ).AutoFit
      Else
         If vRangeColumn <> "" Then xlSheet.Columns( vRangeColumn ).ColumnWidth = Cdbl( vWidth )
         If vRangeRow <> "" Then xlSheet.Rows( vRangeRow ).RowHeight = Cdbl( vHeight )
      End If
   End If
   '
WayOut:
   Exit Function
GeneralError:
    xl.Visible = False
    sMsg =  "Fehler (Nr. " & err & ") in Zeile " & Erl & ": " & Error
    sMsg = sMsg & Chr(10) & Chr(10)
    sMsg = sMsg & "Parameter: " & Chr(10)
    sMsg = sMsg & "Bereich = " & Cstr( vRange ) & Chr(10)
    sMsg = sMsg & "Maßangaben = " & Cstr( vParam ) & Chr(10)
    sMsg = sMsg & "Spaltenbreite = " & Cstr( vWidth ) & Chr(10)
    sMsg = sMsg & "Reihenhöhe = " & Cstr( vHeight ) & Chr(10)
    sMsg = sMsg & "Bereich Spalten = " & Cstr( vRangeColumn ) & Chr(10)
    sMsg = sMsg & "Bereich Reihen = " & Cstr( vRangeRow ) & Chr(10)
    If Err = 213 And Error = "OLE: Automation object error" Then
       sMsg = sMsg & Chr(10) & Chr(10)
       sMsg = sMsg & "Hinweis: " & Chr(10) & "MS Excel meldet einen generellen Fehler." & Chr(10)
       sMsg = sMsg & "Überprüfen sie die Angaben des Bereiches. Sie dürfen nur maximal einen Doppelpunkt enthalten, Zeilen- und Reihenangaben müssen plausibel sein." & Chr(10)
       sMsg = sMsg & ""
    Elseif err = 213 And ( Instr( Error , "ColumnWidth" ) > 0 Or  Instr( Error , "RowHeight" ) > 0 ) Then
       sMsg = sMsg & Chr(10) & Chr(10)
       sMsg = sMsg & "Hinweis: " & Chr(10) & "Die Maßangaben müssen dem lokalen Zahlenformat entsprechen." & Chr(10)
       sMsg = sMsg & "Das Zahlenformat für Breite oder Höhe kann vermutlich nicht interprteiert werden."
    End If
    MsgBox sMsg  , 16 ,  "Fehler in Funktion xlFitRange()"
    xl.Visible = True
    Resume Next
End Function


Titel: Function xlFormatFont( ... )
Beitrag von: ata am 31.01.08 - 12:46:48
... eine Funktion zur Schrift-Formattierung eines Bereiches

Ein Aufruf kann wie folgt aussehen:
Call xlFormatFont( xl , xlSheet , "" , "Arial" ) ' # das gesamte Tabellenblatt in Arial
Call xlFormatFont( xl , xlSheet , "" , "Arial => 10" ) ' # das gesamte Tabellenblatt in Arial Größe 10 - verwendet Select
Call xlFormatFont( xl , xlSheet , "" , "Arial => 10 => 3" ) ' # das gesamte Tabellenblatt in Arial Größe 10 in roter Schriftfarbe
Call xlFormatFont( xl , xlSheet , "A1:E1" , "Arial => 14 => 3 => Bold => Italic" )  '# der ausgewiesene Bereich in fetter roter Kursiv-Schrift "Arial in Größe 14
Call xlFormatFont( xl , xlSheet , "A1:E1" , "Arial => 14 => 5 => => Italic" ) '# der ausgewiesene Bereich in blauer Kursiv-Schrift "Arial in Größe 14

Hinweis:
Die Parameter für die Schriftformatierung müssen in dieser Reihenfolge verwendet werden.
Es kann kein Parameter übersprungen werden, er muß zumindest als Leer übergeben werden (s. letztes Beispiel für "Bold"-Bereich des Strings).
Leere Parameter werden nicht beachtet.

Code:
Function xlFormatFont( xl As Variant , xlSheet As Variant , vRange As Variant , vParam As Variant ) As Variant
   ' # Formatiert einen Bereich für Schrift, Größe, Farbe
   ' # xlSheet => Variant => das Excel-Arbeitsblatt
   ' # vRange => Variant => z.B. "A:E" für die ersten 5 Spalten - bei Leersting das gesamte Arbeitsblatt
   ' # vParam => Variant => gewünschte Formatierung des Bereiches "Schrift => Größe => Farbnummer => Gewicht => Kursiv"
   ' # ... => z.B. "Arial => 10 => 3 => Bold => kursiv " für Arial in Größe 10 in fetter roter Kursiv-Schrift
   ' # ... => z.B. "Arial => 10 => 3 => Normal => kursiv " für Arial in Größe 10 in roter Kursiv-Schrift
   '
   On Error GoTo GeneralError
   '
   Dim sFont As String
   Dim sSize As String
   Dim sColor As String
   Dim sWeight As String
   Dim sItalic As String
   '
   Dim Range As Variant
   Dim vValue As Variant
   Dim i As Integer
   Dim sValue As String
   Dim sMsg As String
   '
   ' # Parsen der Übergabeparameter
   ' # ... Fontangaben
   If Instr( Cstr( vParam ) , "=>" ) > 0 Then
      vValue = Split( Trim(Cstr(vParam)) , "=>" )
      sFont =  Trim(Cstr(vValue(0)))
      sSize =  Trim(Cstr(vValue(1)))
      If Ubound( vValue ) > 1 Then sColor =  Trim(Cstr(vValue(2)))
      If Ubound( vValue ) > 2 Then sWeight =  LCase( Trim(Cstr(vValue(3))))
      If Ubound( vValue ) > 3 Then sItalic =  LCase( Trim(Cstr(vValue(4))))
   Else
      sFont = Cstr( vParam )
   End If
   '
   ' # Formatieren des Bereiches
   If Trim(Cstr( vRange )) = "" Then
      xlSheet.Cells.Select
      Set Range = xl.Selection
   Else
      Set Range = xlSheet.Range( vRange  )
   End If
   If sFont <> "" Then Range.Font.Name = sFont
   If sSize <> "" Then Range.Font.Size = Cdbl( sSize )
   If sColor <> "" Then Range.Font.ColorIndex = Cdbl( sColor )
   If sWeight <> "" Then
      If sWeight = "bold" Or sWeight = "fett" Then Range.Font.Bold = True
      If sWeight = "normal" Then Range.Font.Bold = False
   End If
   If sItalic <> "" Then
      If sItalic = "italic" Or sItalic = "kursiv" Then Range.Font.Italic = True
      If sItalic = "normal" Then Range.Font.Italic = False
   End If
   '
   If Trim( Cstr( vRange ) ) = "" Then xlSheet.Range( "A1" ).Select   
  '
WayOut:
   Exit Function
GeneralError:
    xl.Visible = False
    sMsg =  "Fehler (Nr. " & err & ") in Zeile " & Erl & ": " & Error
    sMsg = sMsg & Chr(10) & Chr(10)
    sMsg = sMsg & "Parameter: " & Chr(10)
    sMsg = sMsg & "Bereich = " & Cstr( vRange ) & Chr(10)
    sMsg = sMsg & "Angaben = " & Cstr( vParam ) & Chr(10)
    sMsg = sMsg & "Schriftart = " & Cstr( sFont ) & Chr(10)
    sMsg = sMsg & "Schriftgröße = " & Cstr( sSize ) & Chr(10)
    sMsg = sMsg & "Schriftfarbe = " & Cstr( sColor ) & Chr(10)
    If Err = 213 And Error = "OLE: Automation object error" Then
       sMsg = sMsg & Chr(10) & Chr(10)
       sMsg = sMsg & "Hinweis: " & Chr(10) & "MS Excel meldet einen generellen Fehler." & Chr(10)
       sMsg = sMsg & "Überprüfen sie die Angaben des Bereiches. Sie dürfen nur maximal einen Doppelpunkt enthalten, "
       sMsg = sMsg & "Zeilen- und Reihenangaben müssen plausibel sein." & Chr(10)
       sMsg = sMsg & ""
    End If
    MsgBox sMsg  , 16 ,  "Fehler in Funktion xlFormatFont()"
    xl.Visible = True
    Resume Next
End Function


Titel: Function xlSetCell( ... )
Beitrag von: ata am 31.01.08 - 15:17:58
... dynamische Funktion zum Beschreiben von Excel-Zellen.

Ein Aufruf kann wie folgt aussehen:
' # Zeile 2, Spalte 1, Erstellungsdatum des Dokumentes im Format "dd.mm.yyyy hh:nn"
Call xlSetCell( xl , xlSheet , 2 , 1 , doc.Created , "TT.MM.JJJJ hh:mm" )

' # Zeile 2, Spalte 2, angenommene Postleitzahl als Text in die Zelle schreiben - um führende Nullen nicht zu verlieren
Call xlSetCell( xl , xlSheet , 2 , 2 , doc.PLZ(0) , "@" )

' # Zeile 2, Spalte 3 , Formel für den Inhalt => A2 + ", " + B2
row = 2
Call xlSetCell( xl , xlSheet , row , 3 , {=VERKETTEN(A} & row & {;", ";B} & row &{)}  , "" ) ' # Formelsprache beachten...


Hinweis:
Es gibt für Excel auch einen Parameter, mit dem man die Formelsprache für englische Formelsprache erzwingen kann - dann dürfen aber nur noch solche verwendet werden. Notwendig wird dies, wenn unterschiedliche Excel-Versionen und Ländereinstellungen vorliegen.

Der Parameter wird später nachgereicht - bin noch am suchen  :P

Zitat
Function xlSetCell( xl As Variant , xlSheet As Variant , row As Long , column As Variant , vValues As Variant , sDataFormat As String ) As Variant
   ' # Einen Wert oder eine Formel in eine Zelle schreiben unter Berücksichtigung eines speziellen Formates.
   ' # xl => Variant => die Excel-Anwendung
   ' # xlSheet => Variant => das Excel-Arbeitsblatt
   ' # row => Zahl => die Zeilennummer
   ' # column => Zahl => die Spaltennummer
   ' # vValue => Text-Array oder TextString => die eigentlichen Werte. Bei einem Array werden alle Elemente mit einem LineFeed (Chr(10)) als Textstring verkettet.
   ' # ... beginnt der Textstring mit einem Gleichheitszeichen, dann wird der String als Formel in die Zelle geschrieben.
   ' # ... bei Formeln muß beachtet werden, daß es bei unterschiedlichen Excel-Versionen zu Abweichungen in der Syntax kommen kann.
   ' # ... die engliche Formlsprache ist vorzuziehen
   ' # sDataFormat => Text-String => das zu verwendende Zell-Format. Bei Leerstring findet keine Formatierung statt.
   ' # ... ACHTUNG: Hier gibt es je nach Länder- und Excel-Version unterschiedliche Formtierungsparameter - gilt für vor allem für Zahlen und Datums-/Zeitformatierungen
   ' # ... "@" => Zelle wird explicit als Text formatiert
   ' # ... "#.##0,00" => Zelle wird als Zahl mit 2 Nachkomma-Stellen und möglichem Tausender-Trennzeichen "." formatiert
   ' # ... "TT.MM.JJJJ hh:mm:ss" => Zelle wird als Datums-/Zeit-Wert formatiert, hier z.B. "31.01.2008 13:54:00" => deutsche Excel-Version 2003
   '
   Dim i As Integer
   Dim sValue As String
   Dim sMsg As String
   '
   On Error GoTo GeneralError
   '
   If IsArray( vValues ) Then
         For i = LBound( vValues ) To Ubound( vValues )
            sValue = sValue + vValues( i ) + Chr(10)
         Next
         sValue = Left( sValue , Len( sValue ) - 1 ) ' # letzten LF bereinigen
         xlSheet.Cells( row , column ).Value = sValue
   Else
      If Left( Cstr( vValues ) , 1 ) = "=" Then
         sValue = Cstr( vValues )
         xlSheet.Cells( row , column ).FormulaLocal = sValue
      Else
         If sDataFormat <> "" Then xlSheet.Cells( row , column ).NumberFormat = sDataFormat
         sValue = Cstr( vValues )
         xlSheet.Cells( row , column ).Value = vValues
      End If
   End If
   '
WayOut:
   Exit Function
GeneralError:
    xl.Visible = False
    sMsg =  "Fehler (Nr. " & err & ") in Zeile " & Erl & ": " & Error
    sMsg = sMsg & Chr(10) & Chr(10)
    sMsg = sMsg & "Parameter: " & Chr(10)
    sMsg = sMsg & "Zeile = " & Cstr( row ) & Chr(10)
    sMsg = sMsg & "Spalte = " & Cstr( column ) & Chr(10)
    sMsg = sMsg & "Werte = " & Cstr( sValue ) & Chr(10)
    sMsg = sMsg & "Format = " & Cstr( sDataFormat ) & Chr(10)
    If Error = "OLE: Automation object error" Then
       sMsg = sMsg & Chr(10) & Chr(10)
       sMsg = sMsg & "Hinweis: " & Chr(10) & "MS Excel meldet einen generellen Fehler." & Chr(10)
       sMsg = sMsg & "Überprüfen sie die oben angegebenen Parameter auf ihre Plausibilität." & Chr(10)
       sMsg = sMsg & ""
    End If
    MsgBox sMsg  , 16 ,  "Fehler in Funktion xlSetCell()"
    xl.Visible = True
    Resume Next
End Function


Titel: Function xlAutoFilter( ... )
Beitrag von: ata am 04.02.08 - 21:14:10
... aktivieren des Autofilters in einer bestimmten Zeile.

Ein Aufruf kann wie folgt aussehen:
' # 5. Zeile für den Autofilter aktivieren
Call xlAutoFilter( xlSheet , 5 )

Code:
Function xlAutoFilter( xlSheet As Variant , row As Long ) As Variant
   ' # Setzt in der angegebenen Zeile den Autofilter
   ' # xlSheet => Variant => das Excel-Arbeitsblatt
   ' # row => Zahl => die Zeilennummer
   '
   xlSheet.Rows( row ).Select
   xl.Selection.AutoFilter
   '
End Function


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: jBubbleBoy am 05.02.08 - 06:22:06
... meine Funktion zum hochzählen der Spalten, die habe ich in deiner Liste noch nicht gesehen oder machst du das anders ;)

Code:
Function getNextColumn( column As String ) as string
      Dim fi$, la$
      If Len(column)>1 Then
          fi=Left(column,1)
          la = Right(column, 1)
      Else
            la = column
      end if
      If Asc( la ) = 90 Then
            If fi<>"" Then
                  getNextColumn = Chr( Asc( fi  ) +1 )      + "A"
            Else
                  getNextColumn = "AA"
            End If
      Else
            getNextColumn = fi & Chr( Asc( la ) +1 )
      End If
End Function


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: ata am 05.02.08 - 07:11:31
... es gibt ja bekanntlich immer viele Wege nach Rom - ich mach es über Evaluate, Permutation und ein Array - kommt noch im Laufe des Tages...


Toni


Titel: Function xlGetColumnNames( )
Beitrag von: ata am 05.02.08 - 08:54:38
... Funktion zum Ermitteln der Spaltennamen.  Die Funktion gibt ein Text-Array zurück. Erstes Element ist der Buchstabe "A"

Eine Verwendung kann wie folgt aussehen:
Dim vColName As Variant
vColName = xlGetColumnNames( )

Print "Die fünfte Spalte hat den Buchstaben " & vColName( 5 )



Code:
Function xlGetColumnNames( ) As Variant
   ' # übergibt die möglichen 256 Excel-Spalten-Namen als Array
   Dim vCol As Variant
   Dim sDummy( 0 ) As String
   vCol = Evaluate( |vA := "A":"B":"C":"D":"E":"F":"G":"H":"I":"J":"K":"L":"M":"N":"O":"P":"Q":"R":"S":"T":"U":"V":"W":"X":"Y":"Z";@Subset(("" :vA) *+ vA;256)|)
   xlGetColumnNames = ArrayAppend( sDummy , vCol )
End Function


Titel: Function xlSaveAs( xlWbk As Variant , sFilePath As String ) As Variant
Beitrag von: ata am 06.06.08 - 12:09:57
... Funktion zum Speichern einer Excel-Datei.

Eine Verwendung kann wie folgt aussehen:

Call xlSaveAs( xlWbk , "C:\Temp\demo.xls" )


Code:
Function xlSaveAs( xlWbk As Variant , sFilePath As String ) As Variant
   If sFilePath <> "" Then Call xlWbk.SaveAs( sFilePath )
End Function


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: WildVirus am 07.07.08 - 22:41:26
Interessant dürfte auch die Funktion pagesetup sein:

Code:
'#######################
' Seiteneinstellungen
'#######################
With xl.ActiveSheet.PageSetup
'Variablen
'&A - Gesamtseitenzahl
'&B - Blattname
'&D - Datum
'&I - Bild
'&N - Dateiname
'&P - Speicherort
'&S - Seite
'&U - Uhrzeit
.Orientation = 2
.LeftHeader = ""
.CenterHeader = "&""Arial,Bold""&18"+db.Title
.RightHeader = ""
.LeftFooter = "&""Arial""&8&P-&N"
.CenterFooter = "&""Arial""&8Seite &S von &A"
.RightFooter = "&""Arial""&8&D - &U"
.PrintArea = ("A1:H5")
.PaperSize = 9
.CenterHorizontally = True         
.FitToPagesTall =False
.zoom = False
.FitToPagesWide=1
.PrintTitleRows=xl.Rows("1:1").Address
End With

Was mir noch nicht gelingen will, ist der Zeilenumbruch innerhalb eines Feldes, z.B. CenterFooter, aber wahrscheinlich bin ich nur zu müde.

Der Excel-Makrorekorder nimmt chr(10), gebe ich das aus LN mit, kommt es als Text an.


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: ata am 08.07.08 - 08:40:24
... danke - ich schau mir das die Tage mal an und werde es mit einbauen...

Toni


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: bikerboy am 27.04.10 - 16:35:57
Habe die ganzen Funktionen mal in einer Klasse zusammengefasst. Hoffe ich kann damit jemanden Weiterhelfen und ich hoffe ich gewinne das Fleisskärtchen.



Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: Axel am 27.04.10 - 18:59:10
Erstmal vielen Dank für deine Mühen. Ich werde mir das bei Gelegenheit mal genauer anschauen. Überflugmäßig sieht's ganz gut aus.

Ich hoffe, dass ich irgendwann mal die Zeit finde mal ein BP-Artikel draus zumachen.

Axel


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: Fedaykin am 22.06.10 - 11:52:46
Hallo zusammen

Wäre besser Select zu vermeiden (nur verwenden wo wirklich was angesprungen werden muss). Vorteile sind dabei es wird schneller und nerviges rumgehüpfe verschwindet.

Zum Beispiel besser so:
Code:
With objSheet.Cells
   .Columns.AutoFit
   .Rows.AutoFit
End With

Als:
Code:
objSheet.Cells.Select
Selection.Columns.AutoFit
Selection.Rows.AutoFit

Gruss
Remo


Titel: Details bei einer Gruppierung verstecken
Beitrag von: Performance am 18.10.11 - 13:17:34

die Funktion in Excel "ActiveSheet.Outline.ShowLevels RowLevels:=0, ColumnLevels:=1"
kann ich aus Notes nicht übergeben, bzw. ich habe googleweit nichts gefunden.

ich habs dann über "hide" gemacht, nicht ganz elegant aber es funktioniert
z.B:

Excel.Range("A1:E1").Select
With Excel.application.Selection
   .Columns.Group
   .Columns.Hidden = True
End With


cu


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: ata am 18.10.11 - 16:53:49
... mal kurz ins blaue - um auf Remo's Anregung einzugehen - hast du es auch ohne Selection versucht?

Also ungefähr so:

With Excel.Range("A1:E1")
   .Columns.Group
   .Columns.Hidden = True
End With

Das müsste besser sein für die Performance...


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: Performance am 20.10.11 - 13:25:11
aus dem blauen  ;D

ohne selection geht es ..... ???  , perfomance spielt hier keine Rolle, hatte in altem Code ein Paar Änderungen vorgenommen

danke für den Tip

cu


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: StefanP1962 am 06.05.13 - 16:44:08
Hab da noch was gefunden ...

Suchte nach einer Funktion, um die benannten Zellen (Einfügen - Name) in einer Exceltabelle auszulesen.

' Felder holen
   Set excelwb = objExcel.activeworkbook
   
   Forall nn In excelwb.Names
      
      Redim Preserve excelField( en ) As String
      excelField( en ) = nn.Name
      en = en + 1
      
   End Forall
   


Titel: Re: COM-Schnittstelle MS Excel
Beitrag von: ata am 06.05.13 - 17:07:20
... danke für die Routine - werde ich mal nach dem obigen Muster einarbeiten. Hatte ich bislang noch nicht benötigt - aber man weiß ja nie ;)

Toni