öffnet Stammdaten
Datensicherung
Quelle: dmt
Datum: 02.2005
Mittels einer Access-Anwendung an anstehende Datensicherungen zu erinnern sowie diese auch anzustoßen, hat sich bereits mehrfach bewährt.
In strobel.mdb (Access 2.0) wird eine Novell-Arcserve-Backup-Client-Anwendung geöffnet und per SendKeys ferngesteuert.
In bea.mdb wird ein Winzip-Kommandozeilen-Utility auf das Verzeichnis "c:\eigene dateien" losgelassen, um eine Datums-benannte Zip-Datei anzulegen.
Der Code in bea.mdb sieht so aus (bitte auch die neuere Version aus dmt.mdb weiter unten beachten):
Function Datensicherung()
On Error GoTo err_Datensicherung
Dim v As Variant, NameDatum As String
' Hinterlegte Kommando-Angaben aus der Tabelle holen
v = Get_BesitzerWert("Winzip_Kommando", "Vorgaben")
' Datum umbauen: JahrMonatTag
NameDatum = Year(Date) & Format(Month(Date), "00") & Format(Day(Date),"00")
' XYZ in Kommando-Angabe ersetzen durch das umgebaute Datum
v = ReplaceInString(v, "XYZ", NameDatum)
' Benutzer fragen und evtl. abrechen
Beep
If MsgBox("Wollen Sie die aktuelle Datensicherungs-Zipdatei '" & NameDatum & ".zip' jetzt anlegen ?", vbQuestion + vbOKCancel, "Datensicherung") = vbCancel Then Exit Function
' Betriebssystem aufrufen und Kommando absetzen
v = Shell(v, vbMaximizedFocus)
' Pause, um abzuwarten, bis die DOS-Box sich vollständig aufgebaut hat.
Pause 2
' Tastendruck abschicken, um bei Lizenzmeldung weiterzumachen
SendKeys "{ENTER}", True
exit_Datensicherung:
Application.Quit acQuitPrompt
Exit Function
err_Datensicherung:
Fehler "Datensicherung"
Resume exit_Datensicherung
End Function
Winzip-Kommando:
c:\tools\winzip\wzzip.exe -P -r -whs c:\save\XYZ.zip @c:\save\savelist.txt
* * * *
Und so geht das in der dmt.mdb (Access 2.0, 16Bit):
Private Sub Datensicherung ()
On Error GoTo err_Datensicherung
Dim v As Variant
Dim sCdDrive As String, NameDatum As String, BackupDir As String, TempDir As String, sModus As String
Dim ZipCommand As String, ZipDir As String, ZipFile As String, SaveList As String, CR As String, sTab As String
Const CD_DRIVE_NAME1 = "HL-DT-ST DVDRAM GSA-4082B"
Const CD_DRIVE_NAME2 = "HP CD-Writer+ 8100"
Const REL_PATH_TO_ZIP_DIR = "\tools\packer\zip32"
Const SCRIPT_SUB_DIR = "script"
Const ZIP_DRIVE = "G:"
' **** Modus checken ****
If InStr(Me!ExterneDateien, "manuell") > 0 Or InStr(Me!ExterneDateien, "große") > 0 Then
sModus = "vollständigen"
ZipCommand = "save_nt.bat"
Else
sModus = "kleinen"
ZipCommand = "save_nt2.bat"
End If
' **** Benutzer fragen ****
Beep
sTab = Chr$(9)
CR = Chr$(13) & Chr$(10)
v = "Schließen Sie vor dem Start der " & sModus & " Datensicherung alle anderen Anwendungen "
v = v & "und legen Sie eine geeignete CD in das CD-Brenner-Laufwerk ein." & CR & CR
v = v & "Wollen Sie das schnellere der verfügbaren Brenner-Laufwerke benutzen ?" & CR & CR
v = v & "Ja" & sTab & sTab & CD_DRIVE_NAME1 & ": 24-fach" & CR
v = v & "Nein" & sTab & sTab & CD_DRIVE_NAME2 & ": 4-fach" & CR
v = v & "Abbrechen" & sTab & "bricht den Vorgang ab"
v = MsgBox(v, 67, "Datensicherung")
Select Case v
Case 6: sCdDrive = Chr$(34) & CD_DRIVE_NAME1 & Chr$(34)
Case 7: sCdDrive = Chr$(34) & CD_DRIVE_NAME2 & Chr$(34)
Case Else: Exit Sub
End Select
' **** Betriebssystem abfragen und ab geht's ****
If API_Is_WindowsNT_Running() = False Then
Beep
MsgBox "Der Betrieb unter Nicht-NT wurde noch nicht getestet !", 64, "Datensicherung"
Exit Sub
End If
If CheckRohling(sCdDrive) = False Then Exit Sub
' Datum umbauen: JahrMonatTag
NameDatum = Year(Date) & Format(Month(Date), "00") & Format(Day(Date), "00")
TempDir = NameDatum & ".tmp"
' Um etwaigen Beschränkungen der Länge von Kommandozeilen-Befehlen zu entgehen, werden
' auf den jeweils verschiedenen Laufwerken die aktiven Arbeitsverzeichnisse eingestellt.
BackupDir = GetDesktopDir()
v = ForceDir(BackupDir) ' jeweiliger Desktop als aktives Laufwerk / Verzeichnis
MkDir TempDir ' Temp-Verzeichnis anlegen
ChDir TempDir ' und zum aktiven machen
BackupDir = BackupDir & "\" & TempDir ' und dessen Laufwerksbuchstaben als Batch-Parameter übernehmen
ZipDir = ZIP_DRIVE & REL_PATH_TO_ZIP_DIR & "\" & SCRIPT_SUB_DIR
v = ForceDir(ZipDir)
' **** Backup-Verzeichnis zur Identifikation nach erneutem Programmstart hinterlegen ****
DoCmd SetWarnings False
DoCmd RunSQL ("UPDATE vorgaben SET last_backup_dir = '" & BackupDir & "'")
DoCmd SetWarnings True
' **** Zip-Batch aufrufen ****
ZipCommand = ZipDir & "\" & ZipCommand & " " & BackupDir & " " & SCRIPT_SUB_DIR & " " & NameDatum & ".zip" & " " & sCdDrive
v = Shell(ZipCommand, 3)
Application.Quit
exit_Datensicherung:
Exit Sub
err_Datensicherung:
If Err = 75 Then
Resume Next
Else
Fehler "Datensicherung"
Resume exit_Datensicherung
End If
End Sub
Dahinter stecken noch ein paar Kleinigkeiten:
Die Datensicherung wurde um eine Möglichkeit erweitert, zwischen verschiedenen Brennern auswählen zu können.
CheckRohling() checkt entsprechend dieser Auswahl einen CD-Rohling im gewählten Brenner-Laufwerk.
Für die CD-bezogenen Funktionen wird im vorliegenden Falle eine per Kommandozeile steuerbare Brennersoftware (Nero 6) benutzt.
Entsprechende Aufrufe erfolgen durch verschiedene, weiter unten gelistete DOS-Batchdateien.
Private Function CheckRohling (CdDrive As String) As Integer
On Error GoTo err_CheckRohling
Dim FF As Integer, iPos1 As Integer, iPos2 As Integer, iFreeMB As Long, LastBackupSize As Integer
Dim v As Variant
Dim s As String, sWarnung As String, sCdType As String, sCdProtected As String
Dim CR As String * 2, sTab As String * 1, sFreeMB As String, sBlocksFree As String
Dim BurnToolDrive As String * 1, CheckCommand As String
Const CHECKBAT = "info.bat"
Const TEMPFILE = "~info.txt"
Const PATH_TO_BURN_TOOL = "tools\cd"
Const CDTYPE = "CD-R"
Const CDPROTECTED = "not writable"
Const BLOCKSFREE = " blocks free"
Const BYTEFACTOR = 2048
BurnToolDrive = "m"
sTab = Chr$(9)
CR = Chr$(13) & Chr$(10)
' **** CD-Medium-Informationen checken ****
FF = FreeFile
v = ForceDir(BurnToolDrive & ":\" & PATH_TO_BURN_TOOL)
CheckCommand = CHECKBAT & " " & CdDrive & " " & TEMPFILE
v = Shell(CheckCommand, 1)
WaitForActiveTask
Open TEMPFILE For Input As #FF
Line Input #FF, s
Close #FF
Kill TEMPFILE
If InStr(s, "error") > 0 Then
Beep
If MsgBox("Die CD konnte nicht ausgelesen werden !" & CR & CR & "Evtl. kann die CD dennoch beschrieben werden (durch manuelle Bedienung einer Brenner-Software)." & CR & CR & "Soll die Datensicherung dennoch erstellt werden ?", 36, "CheckRohling") = 6 Then
CheckRohling = True
End If
Exit Function
End If
iPos1 = InStr(s, ",")
sCdType = Mid$(s, 1, iPos1 - 1)
If sCdType <> CDTYPE Then
sWarnung = "Ungültiger Medientyp:" & sTab & sTab & "'" & sCdType & "' anstelle von '" & CDTYPE & "'"
End If
iPos2 = InStr(iPos1 + 1, s, ",")
sCdProtected = Mid$(s, iPos1 + 2, iPos2 - iPos1 - 2)
If sCdProtected = CDPROTECTED Then
If sWarnung <> "" Then sWarnung = sWarnung & CR
sWarnung = sWarnung & "Die CD ist nicht beschreibbar:" & sTab & "'" & sCdProtected & "'"
End If
sBlocksFree = Mid$(s, iPos2 + 2)
iFreeMB = (Val(sBlocksFree) * BYTEFACTOR) / 1024
iFreeMB = iFreeMB / 1024
sFreeMB = "Freier Platz auf der CD:" & sTab & sTab & iFreeMB & " MB"
If sWarnung <> "" Then
Beep
MsgBox "Die CD ist unbrauchbar !" & CR & CR & sWarnung & CR & sFreeMB, , "CheckRohling"
Exit Function
End If
' **** Größe der letzten Backup-Datei checken ****
If InStr(Me!ExterneDateien, "manuell") Or InStr(Me!ExterneDateien, "groß") Then
LastBackupSize = DLookup("last_backup_size", "vorgaben")
Else
LastBackupSize = DLookup("last_small_backup_size", "vorgaben")
End If
LastBackupSize = LastBackupSize + (LastBackupSize / 10) ' zum Abschätzen um 10% erhöhen
Beep
If LastBackupSize > iFreeMB Then
If MsgBox("Die CD verfügt wahrscheinlich nicht über den benötigten Speicherplatz !" & CR & CR & sFreeMB & CR & "Grob geschätzter Platzbedarf:" & sTab & LastBackupSize & " MB" & CR & CR & "Es ist wahrscheinlich ratsam, die CD zur besseren Lesbarkeit mittels einer geeigneten Brennsoftware zu 'fixieren'." & CR & CR & "Soll der Brennvorgang trotzdem gestartet werden ?", 260, "CheckRohling") = 6 Then
CheckRohling = True
End If
Else
If MsgBox("Der verfügbare Platz auf der CD sollte ausreichen." & CR & CR & sFreeMB & CR & "Grob geschätzter Platzbedarf:" & sTab & LastBackupSize & " MB" & CR & CR & "Soll der Brennvorgang jetzt gestartet werden ?", 4, "CheckRohling") = 6 Then
CheckRohling = True
End If
End If
Exit Function
err_CheckRohling:
Fehler "CheckRohling"
Exit Function
End Function
**** Und hier noch ein paar der beteiligten Batchdateien: ****
Die info.bat, die als Parameter die Laufwerkskennung sowie den Namen einer temporären Ergebnisdatei entgegennimmt.
Die Ausgabe des CD-Checks erfolgt dann in eben dieser Datei.
Die info.bat habe ich in dem Verzeichnis abgelegt, in dem die Brenner-Software liegt.
@echo off
rem **** Die Ausgabe dieser Datei wird extern ausgewertet und sollte zumindest am Anfang nicht ver„ndert werden ****
rem Parameter:
rem %1: Laufwerksbuchstabe
rem %2: Ausgabe-Datei
echo.
echo die CD wird berprft ...
echo.
echo Laufwerks-Kennung: %1
echo.
nerocmd.exe --cdinfo --drivename %1 > %2
echo.
Unter dem Verzeichnis meiner Winzip-Installation liegt ein script-Verzeichnis, in dem folgende Dateien liegen:
dont_nt.txt:
; *** Diese Dateien nicht sichern ****
I:\_burn\*.*
I:\_temp\*.*
I:\websites\php\phpmyadmin\*.*
list_nt.txt:
; **** Liste der durch winzip zu sichernden Dateien ****
; e:\*.mdb -> wird in den Batches extra verarbeitet.
i:\*.*
list_nt1.txt:
; **** Konfigurationsdateien Not-NT ****
h:\winnt\system32\config\*.*
h:\winnt\profiles\administrator\ntuser.dat
sowie die eigentlichen Batches zur Ablaufsteuerung:
Interessant ist hier der Aufruf eines NT4-bezogenen Microsoft-Tools zur Sicherung der NT4-Registry-Dateien.
Das Programm rdisk.exe wird mit dem Parameter /s aufgerufen.
Nur so werden auch die SAM und SECURITY-Dateien gesichert.
save_nt.bat:
@echo off
rem
rem **** Um mehrere Sicherungstasks anstoáen zu k”nnen, wird das in einer DOS-Batch erledigt ****
rem
rem **** Parameter ****
rem %1: Vollst„ndiger Pfad zu dem Verzeichnis, in dem das Zip-Backup erstellt wird.
rem %2: Unterverzeichnis, in dem diese Scripte liegen, z.B. "script".
rem %3: Name der Tages-aktuellen zip-Datei.
rem %4: Name des Brenner-Laufwerkes, da z.B. der DVD-Brenner nicht über seinen DOS-Laufwerksbuchstaben erkannt wird.
rem
rem **** Bedeutung der wichtigsten Parameter fr wzzip ****
rem -a+ fge Dateien hinzu und setze Archiv-Bit zurck
rem -b... Pfad fr einen alternativen Pfad fr die zip-temp-Datei
rem -ex maximale Kompression
rem -P speichert vollst„ndige Pfadnamen
rem -r rekursives Abarbeiten von Unterverzeichnissen
rem -whs auch versteckte und System-Dateien
rem
rem Wechsle in das zip-Programm-Verzeichnis
cd ..
echo.
echo **** DMT-Datensicherung, vollst„ndig ****
echo.
echo Sichern der aktuellen Konfiguration des NT-Servers (Benutzereingriff beachten)
echo.
rem GOTO BURN
pause
echo.
echo Die aktuelle Konfiguration wird gesichert ...
echo.
J:\WINNTSRV\system32\rdisk.exe /s
echo Best„tigen Sie den Fortgang der Sicherungs-Routine ...
echo.
pause
echo.
echo - sichere Konfiguration NT Server ...
echo.
wzzip.exe -a+ -b%1 -ex -P -whs %1\nt_serv.zip @%2\list_nt3.txt
echo.
echo - sichere Konfiguration NT Not ...
echo.
wzzip.exe -a+ -b%1 -ex -P -whs %1\nt_not.zip @%2\list_nt1.txt
echo.
echo - sichere Konfiguration NT Brenner ...
echo.
wzzip.exe -a+ -b%1 -ex -P -whs %1\nt_burn.zip @%2\list_nt2.txt
echo.
echo - sichere Stammverzeichnis des Bootlaufwerkes c:\ ...
echo.
wzzip.exe -a+ -b%1 -ex -P -whs %1\c_root.zip c:\*.*
echo.
echo - sichere ge„nderte mdb-Dateien auf e:\ ...
echo.
wzzip.exe -b%1 -ex -i -P -r -whs %1\e_mdb.zip e:\*.mdb
echo.
echo - sichere komplettes Windaten-Laufwerk ...
echo.
rem hier wird eine Ausschluá- und eine Einschluáliste sowie obendrein das Desktop-Temp-Verzeichnis angegeben.
wzzip.exe -a+ -b%1 -ex -P -r -whs %1\%3 -x@%2\dont_nt.txt @%2\list_nt.txt %1\*.*
echo.
:BURN
echo - Der Brenn-Vorgang wird gestartet ...
echo.
m:
cd \tools\cd\
call nerocmd.bat %4 %1\%3
echo.
:READY
echo šberprfen Sie, ob der Brennvorgang samt Verifizierung erfolgreich war.
echo.
pause
rem Die Anwendung wieder starten
start e:\access\msaccess.exe i:\daten\office4\dmt\dmt.mdb /ini e:\windows\msacc20.ini /cmd BackupIsReady
und save_nt2.bat:
@echo off
rem
rem **** Um mehrere Sicherungstasks anstoáen zu k”nnen, wird das in einer DOS-Batch erledigt ****
rem
rem **** Parameter ****
rem %1: Vollst„ndiger Pfad zu dem Verzeichnis, in dem das Zip-Backup erstellt wird.
rem %2: Unterverzeichnis, in dem diese Scripte liegen, z.B. "script".
rem %3: Name der Tages-aktuellen zip-Datei.
rem %4: Name des Brenner-Laufwerkes, da z.B. der DVD-Brenner nicht über seinen DOS-Laufwerksbuchstaben erkannt wird.
rem
rem **** Bedeutung der wichtigsten Parameter fr wzzip ****
rem -i fge nur Dateien hinzu, deren Archiv-Bit inzwischen wieder gesetzt wurde und setze dieses zurck
rem -b... Pfad fr einen alternativen Pfad fr die zip-temp-Datei
rem -ex maximale Kompression
rem -P speichert vollst„ndige Pfadnamen
rem -r rekursives Abarbeiten von Unterverzeichnissen
rem -whs auch versteckte und System-Dateien
rem
rem Wechsle in das zip-Programm-Verzeichnis
cd ..
echo.
echo **** DMT-Datensicherung, ge„nderte Dateien auf 'bigshit' und 'windaten' ****
echo.
pause
echo.
echo - sichere ge„nderte mdb-Dateien auf e:\ ...
echo.
wzzip.exe -a+ -b%1 -ex -i -P -r -whs %1\e_mdb.zip e:\*.mdb
echo.
echo - sichere ge„nderte Daten auf dem Windaten-Laufwerk ...
echo.
rem hier wird eine Ausschluá- und eine Einschluáliste sowie obendrein das Desktop-Temp-Verzeichnis angegeben.
wzzip.exe -b%1 -ex -i -P -r -whs %1\%3 -x@%2\dont_nt.txt @%2\list_nt.txt %1\*.*
echo.
:BURN
echo - Der Brenn-Vorgang wird gestartet ...
echo.
m:
cd \tools\cd\
call nerocmd.bat %4 %1\%3
echo.
:READY
echo šberprfen Sie, ob der Brennvorgang samt Verifizierung erfolgreich war.
echo.
pause
rem Die Anwendung wieder starten
start e:\access\msaccess.exe i:\daten\office4\dmt\dmt.mdb /ini e:\windows\msacc20.ini /cmd BackupIsReady2
Dokumentenverwaltung
Quelle: dmt
Datum: 03.2004
DOKUMENTENVERWALTUNG:
einfach, aber effektiv, sogar mit automatischem Auslesen der win.ini-Extensions-Einträge. Das möchte ich aber nicht unter Win9x+ probieren. Egal. s. bestatt.mdb
Download begleiten
Quelle: dmt
Datum: 06.2004
Im konkreten Beispiel kann in einer Access97-Anwendung der download einer Antiviren-Definitionsdatei gestartet und die danach nötigen, manuellen Schritte (zum Auspacken und implementieren) erledigt werden:
Eine Access2.0-Version findet sich in dmt.mdb.
Option Compare Database
Option Explicit
Const MYCAPTION = "Antiviren-Download"
Const DOWNLOAD_SITE = "http://download.mcafee.com/updates/4xa.asp?as=false&ref=5"
Const MYDESKTOPDIR = "c:\windows\desktop"
Const ANTIVIR_CHECKFILE = "scan.dat"
Dim Antivir_Dir As String, Antivir_File As String, Antivir_OldDate As Variant
Private Sub Form_Open(Cancel As Integer)
On Error GoTo err_Form_Open_Antivir
Dim bDauer As Byte
Cancel = Not Set_Antivir_Data(Antivir_File, Antivir_Dir)
Antivir_OldDate = FileDateTime(Antivir_File)
' Evtl. wird das Überprüfen des Alters der Antiviren-Prüfdaten angefordert
If Not IsNull(Me.OpenArgs) Then
If Me.OpenArgs = "check" Then
bDauer = Now - FileDateTime(Antivir_File) - 1
If bDauer > DLookup("Antiviren_Ablaufdauer", "Vorgaben") Then
Beep
MsgBox "Die vorhandenen Viren-Prüfdaten vom " & Format$(FileDateTime(Antivir_File), "dd.mm.yyyy") & " sind " & bDauer & " Tage alt." & vbCrLf & vbCrLf & "Starten Sie die Aktualisierung der Antiviren-Prüfdaten !", vbExclamation, MYCAPTION
Else
Cancel = True
End If
End If
End If
Exit Sub
err_Form_Open_Antivir:
If Err = 68 Then
Exit Sub
Else
Fehler "Form_Open_Antivir"
End If
Exit Sub
End Sub
Private Sub pbStart_Click()
On Error GoTo err_pbStart
Dim v As Variant, sDownloadFile As String, s As String, sTempDir As
String
Beep
If MsgBox("Stellen Sie sicher, daß eine online-Verbindung besteht, indem Sie sich in das Internet einwählen." & vbCrLf & vbCrLf & "Schließen Sie danach das Browser-Fenster und fahren mit Punkt 2. fort." & vbCrLf & vbCrLf & "Wollen Sie die online-Verbindung jetzt aufbauen ?", vbQuestion + vbOKCancel, MYCAPTION) = vbCancel Then GoSub exit_pbStart
v = Shell("c:\programme\internet explorer\iexplore.exe", vbNormalFocus)
If MsgBox("Rufen Sie die Download-Webseite auf und klicken Sie im unteren Bereich der Seite auf die Download-Schaltfläche." & vbCrLf & vbCrLf & "Speichern Sie die angebotene Datei in dem vorgeschlagen Desktop-Verzeichnis ab." & vbCrLf & vbCrLf & "Warten Sie, bis die Daten vollständig übertragen wurden und schließen Sie danach das Browser-Fenster. Die online-Verbindung kann danach beendet werden." & vbCrLf & vbCrLf & "Wollen Sie die Download-Seite jetzt aufrufen ?", vbQuestion + vbOKCancel, MYCAPTION) = vbCancel Then GoSub exit_pbStart
v = Shell("c:\programme\internet explorer\iexplore.exe" & " " & DOWNLOAD_SITE, vbNormalFocus)
If MsgBox("Bestätigen Sie den erfolgreichen Download der Antiviren-Prüfdatei.", vbExclamation + vbOKCancel, MYCAPTION) = vbCancel
Then GoSub exit_pbStart
sDownloadFile = Dir(MYDESKTOPDIR & "\*dat.exe")
If sDownloadFile = "" Then
MsgBox "Im Desktop-Verzeichnis liegt keine Antiviren-Datei !", vbCritical, MYCAPTION
GoSub exit_pbStart
End If
sTempDir = MYDESKTOPDIR & "\temp"
MkDir sTempDir
FileCopy MYDESKTOPDIR & "\" & sDownloadFile, MYDESKTOPDIR & "\temp\" & sDownloadFile
Meldung "Die Antiviren-Daten werden ausgepackt ..."
v = Shell(sTempDir & "\" & sDownloadFile & " /E", vbHide)
Meldung "Die Antiviren-Daten werden kopiert ..."
' Die Dateien müssen innerhalb von Access einzeln angefasst werden
s = Dir(sTempDir)
Do While s <> ""
' Aktuelles und übergeordnetes Verzeichnis ignorieren.
If s <> "." And s <> ".." And s <> sDownloadFile Then
FileCopy sTempDir & "\" & s, Antivir_Dir & "\" & s
End If
s = Dir
Loop
Kill sTempDir & "\*.*"
RmDir sTempDir
' Desktop-Datei löschen, wenn das Datum der Checkdatei nicht veraltet ist
If (Now - FileDateTime(Antivir_File) - 1) > DLookup("Antiviren_Ablaufdauer", "Vorgaben") Then
Beep
MsgBox "Die Viren-Prüfdaten konnten nicht erneuert werden !", vbCritical, MYCAPTION
Else
Kill MYDESKTOPDIR & "\" & sDownloadFile
MsgBox "Die Aktualisierung der Viren-Prüfdaten war erfolgreich !", vbInformation, MYCAPTION
DoCmd.Close acForm, Me.Name
End If
exit_pbStart:
Meldung ""
Exit Sub
err_pbStart:
Fehler "pbStart"
Resume exit_pbStart
End Sub
Fehler
Quelle: dmt
Datum: 01.2005
FEHLER: Fehlerbehandlung / Fehlernummern
Eine Standard-Fehlerbehandlungsroutine a'la Schaltflächen-Assistent sieht so aus:
Sub Sau_Click
On Error Goto Err_Sau_Click
...
...
Exit_Sau_Click:
Exit Sub
Err_Sau_Click:
Msgbox Error$
Resume Exit_Sau_Click
End Sub
Wenn für ein Programm selbstdefinierte Fehlernummern vergeben werden sollen, so ist zu beachten, daß in Access bis jetzt die Nummern von 1 bis ca. 8.000 bereits vergeben sind und daß zukunftige Access-Versionen an diese Nummern anschließen werden. Um sicher zu gehen, sollten eigene Fehlernummern aus dem Zahlenbereich kleiner als 32.767 abwärts vergeben werden.
* * * *
FEHLERMELDUNG:
Bewährt ist die einheitliche Standardfehlermeldung über folgende Routine:
Sub Fehler (Titel As String)
Dim CR As String, F As String
Beep
CR = Chr$(13) + Chr$(10)
F = "Fehler: " + Error$ + CR + CR + "Code: " & Err
MsgBox F, 16, Titel
End Sub
Im neueren Access97-Stil sieht das dann so aus:
Sub Fehler(s As String)
Beep
MsgBox "Fehler Nr. " & Err & vbCrLf & vbCrLf & Error$, vbCritical, s
End Sub
Wird einfach mit 'Fehler "Modulname"' aufgerufen und erinnert sich sogar noch an
die Fehler-Werte. Allerdings darf die Fehlerprozedur selbst keinen Errorhandler besitzen, weil bei dessen Invokation die vorhandenen Fehlerinformationen zurückgesetzt werden.
Für idiotensichere Programmierung kann mit Blick auf die 'Fehler 88'-Technik in
Open Access auch ein vereinfachtes 'Weird "Variable " & Variable, SubName' in
einem Case else oder sonstwo herhalten.
Sub Weird (sText As String, sSub As String)
Beep
MsgBox sText, 16, "Ungültiger Zustand in " & sSub
End Sub
Fortschritts-Anzeige
Quelle: dmt
Datum: 05.2006
STATUSANZEIGER / FORTSCHRITTSBALKEN:
Sub StatusAnzeige (Titel As String, Wert As Integer, Gesamt As Integer, iAccess As Integer)
' **** ULTIMATIVES STATUS-TOOL ****
Dim sF As String, ProzWert As Integer, i As Integer
Dim C1 As Control, C2 As Control, C3 As Control, C4 As Control, C5 As Control
sF = "Status_Anzeige"
' **** Plausibilitätsprüfung ****
If Wert > Gesamt Or Wert < 0 Or Gesamt < 0 Then
Beep
MsgBox "Ungültige Werte-Kombination '" & Wert & "' und '" & Gesamt & "'.", 16, "Statusanzeige"
Exit Sub
End If
' **** Statusanzeige bei Bedarf öffnen oder schließen ****
If Not ExistsForm(sF) Then
DoCmd OpenForm sF, , , , , , "StandAlone"
ElseIf Wert = 0 And Gesamt = 0 Then
DoCmd Close A_FORM, sF
Exit Sub
End If
' **** Objektvariablen setzen ****
Set C1 = Forms(sF)!Gruen
Set C2 = Forms(sF)!Rot
Set C3 = Forms(sF)!txt_Wert
Set C4 = Forms(sF)!txt_Text
Set C5 = Forms(sF)!txt_Prozent
' **** Zeiger bei Bedarf verstecken oder Wert berechnen ****
If Wert = 0 Then
ProzWert = 0
C1.Visible = False
Else
ProzWert = Int(100 / (Gesamt / Wert))
C1.Visible = True
End If
' **** Erscheinungsbild Grün auf Rot oder Access 2.0 ****
If iAccess = True Then
C1.BackColor = 16711680
C2.Visible = False
If ProzWert > 49 Then
C3.ForeColor = 16777215
C4.ForeColor = 16777215
C5.ForeColor = 16777215
Else
C3.ForeColor = 0
C4.ForeColor = 0
C5.ForeColor = 0
End If
Else
C1.BackColor = 65280
C2.Visible = True
C3.ForeColor = 0
C4.ForeColor = 0
C5.ForeColor = 0
End If
' **** Steuerelemente einstellen ****
C1.Width = C2.Width * (ProzWert / 100)
C3.Caption = ProzWert
C4.Caption = Titel
End Sub
Folgende Routine demonstriert das Handling:
Sub Test_StatusAnzeige ()
Dim i As Integer, Summe As Integer, AccessModus As Integer, s As String
s = "Fortschritt"
Summe = 100
Nochmal:
For i = 0 To Summe
DoEvents
StatusAnzeige s, i, Summe, AccessModus
Next i
For i = Summe To 0 Step -1
DoEvents
StatusAnzeige s, i, Summe, AccessModus
Next i
If AccessModus = False Then
AccessModus = True
Else
GoSub Exit_Test_Statusanzeige
End If
GoSub Nochmal
Exit_Test_Statusanzeige:
StatusAnzeige "", 0, 0, 0
End Sub
Wenn die Status-Anzeige (Aktualisierung Fortschrittsbalken) nur ruckelig aktualisiert wird, hilft folgendes:
Forms!Pflege_Ausgabe.Repaint
In diesem Beispiel findet der Code witzigerweise in einem eigenen Modul statt, während das Repaint auf das Formular bezogen ist, in dem der Code lediglich angestoßen wurde. Das funktioniert aber trotzdem wunderbar und der Fortschrittsbalken läuft brav in einzelnen Prozent-Schritten hoch.
größter Wert, Tabellenfeld
Quelle: dmt
Datum: 03.2004
Wie lang ist der größte/längste Wert der angegebenen Felder / Tabelle ?
Private Function Biggest_Char (Tabelle As String, Feld As String) As Integer
On Error GoTo err_Biggest_Char
Dim DB As Database, RS As Recordset, i As Integer, iMax As Integer
Set DB = DBEngine.Workspaces(0).Databases(0)
Set RS = DB.OpenRecordset(Tabelle)
Do While Not RS.EOF
If Not IsNull(RS(Feld)) Then
i = Len(RS(Feld))
If i > iMax Then
iMax = i
End If
End If
RS.MoveNext
Loop
Biggest_Char = iMax
Exit Function
err_Biggest_Char:
Fehler "Biggest_Char"
Exit Function
End Function
Hilfe, Info
Quelle: dmt
Datum: 03.2004
HILFE / INFO:
Ein eigenes Hilfesystem, daß vom Anwender selbst editiert werden kann, ist nach meiner Ansicht hip. Die Positionier-Merkgeschichten können in hp_vhp.mdb und auch in laserjob.mda bewundert werden.
Einen sehr einfachen Weg geht der Schnellschuß in bestatt.mdb, der (nur) für Formulare deren Namen ausliest und einen neuen Info-Datensatz anlegt bzw. den gewünschten darstellt.
In der ersten Fassung konnte das sogar steuerelement-spezifisch gemacht werden, aber das führt dann doch zu weit.
Die vereinfachte, formularbezogene Form ist komplett in bestatt.mdb zu finden.
Eine Positioniermerkung kann bei Bedarf leicht aus laserjob.mda übernommen werden.
Function Hilfe ()
On Error GoTo err_Hilfe
Dim v As Variant
Dim sForm As String, sControl As String
sForm = Screen.ActiveForm.Name
sControl = Screen.ActiveControl.Name
' **** Hilfe-Datensatz schon vorhanden ? ****
v = DLookup("Info", "Info", "Formular='" & sForm & "' AND Steuerelement='" & sControl & "'")
If IsNull(v) Then
Beep
If MsgBox("Wollen Sie einen neuen Info-Datensatz für " & sForm & " - " & sControl & " anlegen ?", 33, "Neuer Info-Datensatz") = 1 Then
DoCmd OpenForm "Info", , , , , , sForm & "|" & sControl
End If
Else
DoCmd OpenForm "Info", , , "Formular='" & sForm & "' AND Steuerelement='" & sControl & "'"
End If
Exit Function
err_Hilfe:
Fehler "Hilfe"
Exit Function
End Function
Leerzeichen, löschen
Quelle: dmt
Datum: 03.2004
In Anlehnung an ClearStringFrom() werden hier alle Datensätze einer Tabelle durchlaufen, deren Feldinhalte des übergebenen Feldes von z.B. Leerzeichen befreit werden.
s.a. ReplaceInString()
Private Sub Delete_all_Blanks (Tabelle As String, Feld As String)
On Error GoTo err_Delete_all_Blanks
Dim DB As Database, RS As Recordset, i As Integer, iMax As Integer
Set DB = DBEngine.Workspaces(0).Databases(0)
Set RS = DB.OpenRecordset(Tabelle)
Do While Not RS.EOF
If Not IsNull(RS(Feld)) Then
RS.Edit
RS(Feld) = ClearStringFrom(RS(Feld), " ")
RS.Update
End If
RS.MoveNext
Loop
Exit Sub
err_Delete_all_Blanks:
Fehler "Delete_all_Blanks"
Exit Sub
End Sub
Meldungsfenster
Quelle: dmt
Datum: 03.2004
Klassische Routine für 'bitte warten ...'-Meldungen:
Sub Meldung (sText As String)
' Gebundenes Meldungs-Fenster; mit gegebenem Text öffnen
' oder mit leerem Text schließen; auch Statuszeile.
On Error Resume Next ' evtl. Status-Clear-Fehler
Dim v As Variant
If sText = "" Then
DoCmd Close A_FORM, "Meldung"
v = SysCmd(SYSCMD_CLEARSTATUS)
Else
If SysCmd(SYSCMD_GETOBJECTSTATE, A_FORM, "Meldung") = OBJSTATE_OPEN Then
Forms!Meldung!txt.Caption = sText ' Wenn geöffnet, tritt Form_Open
Else ' nicht ein.
DoCmd OpenForm "Meldung", , , , , , sText
End If
v = SysCmd(SYSCMD_SETSTATUS, sText)
Forms!Meldung.Repaint ' wegen zeitkrit.
End If ' Eventualitäten
End Sub
Eine erweiterte Variante kann sogar die Schriftgröße des Meldungstextes in
Abhängigkeit von der Anzahl der darzustellenden Zeichen verändern:
Meldung (sText As String)
' Gebundenes Meldungs-Fenster; mit gegebenem Text öffnen
' oder mit leerem Text schließen; auch Statuszeile.
On Error Resume Next ' evtl. Status-Clear-Fehler
Dim v As Variant
If sText = "" Then
DoCmd Close A_FORM, "Meldung"
v = SysCmd(SYSCMD_CLEARSTATUS)
Else
If SysCmd(SYSCMD_GETOBJECTSTATE, A_FORM, "Meldung") = OBJSTATE_OPEN Then
Forms!Meldung!txt.Caption = sText ' Wenn geöffnet, tritt Form_Open
Else ' nicht ein.
DoCmd OpenForm "Meldung", , , , , , sText
End If
v = SysCmd(SYSCMD_SETSTATUS, sText)
If Len(Forms!Meldung!txt.Caption) > 28 Then
Forms!Meldung!txt.Fontsize = 8
Else
Forms!Meldung!txt.Fontsize = 12
End If
Forms!Meldung.Repaint ' wegen zeitkrit.
End If ' Eventualitäten
End Sub
Menüaktionen
Quelle: dmt
Datum: 03.2004
Zuweilen praktisch ist auch die Code-mäßige Nachbildung von MENÜAKTIONEN bzw. MENÜOPTIONEN, die sich schon länger in einem eigenen Modul MENU_VER20 präsentieren (s.a. DataToClipboard):
Sub Copy2ClipBoard ()
On Error GoTo err_Copy2ClipBoard
DoCmd DoMenuItem A_FORMBAR, A_EDITMENU, A_COPY, , A_MENU_VER20
Exit Sub
err_Copy2ClipBoard:
Fehler "Copy2ClipBoard"
Exit Sub
End Sub
*
Sub Datensatz_speichern ()
DoCmd DoMenuItem A_FORMBAR, A_FILE, A_SAVERECORD, , A_MENU_VER20
End Sub
*
Sub PasteFromClipboard ()
On Error GoTo err_PasteFromClipboard
DoCmd DoMenuItem A_FORMBAR, A_EDITMENU, A_PASTE, , A_MENU_VER20
Exit Sub
err_PasteFromClipboard:
Fehler "PasteFromClipboard"
Exit Sub
End Sub
*
Sub Rueckgaengig_Feld ()
DoCmd DoMenuItem A_FORMBAR, A_EDIT, A_UNDOFIELD, , A_MENU_VER20
End Sub
* * * *
Wie übertrage ich z.B. WERTE von Basic-VARIABLEN in die Windows-ZWISCHENABLAGE ?
Sub DataToClipboard(cClip As Control, vDaten As Variant, cFocus As Control)
On Error GoTo err_DataToClipboard
' Vorausgesetzt wird ein vorhandenes dummy-Steuerelement, das sichtbar gemacht und mit einem
' übergebenen Wert versehen wird. Danach wird dieser Wert in die Zwischenablage eingefügt,
' das Element wieder unsichtbar gemacht und ein anderes, gewünschtes Steuerelement fokussiert.
cClip.Visible = True
cClip = vDaten
cClip.SetFocus
DoCmd.RunCommand acCmdCopy
' Aufhebung der Abhängigkeit von einem evtl. nicht vorhandenen Makro
'DoCmd.RunMacro "Menübefehle.Zwischenablage_einfügen"
cFocus.SetFocus
cClip.Visible = False
Exit Sub
err_DataToClipboard:
Fehler "DataToClipboard"
Exit Sub
End Sub
Einlesen der Wert aller Text-orientierten Formular-Felder mit formatierter
Übergabe an die Zwischenablage (vorausgesetzt wird auch hier ein dummy-Feld):
Sub pbClipboard_Click ()
On Error GoTo err_pbClipboard_Click
Dim i As Integer, s As String, sTab As String, CR As String, C As Control
sTab = Chr$(9)
CR = Chr$(13) & Chr$(10)
' Daten relevanter Feldtypen, die nicht leer sind, einsammeln
For i = 0 To Me.Count - 1
Set C = Me(i)
If Not IsNull(C) Then
If TypeOf C Is CheckBox Then
s = s & CR & C.Name & ":" & sTab & C.Value
ElseIf TypeOf C Is ComboBox Then
s = s & CR & C.Name & ":" & sTab & C.Value
ElseIf TypeOf C Is ListBox Then
s = s & CR & C.Name & ":" & sTab & C.Value
ElseIf TypeOf C Is OptionButton Then
s = s & CR & C.Name & ":" & sTab & C.Value
ElseIf TypeOf C Is TextBox Then
s = s & CR & C.Name & ":" & sTab & C.Value
ElseIf TypeOf C Is ToggleButton Then
s = s & CR & C.Name & ":" & sTab & C.Value
End If
End If
Next i
' an dummy-Feld zuweisen und an Zwischenablage übergeben
If s <> "" Then
Set C = Me!dummy_clipboard
C.Visible = True
C = s & CR
C.SetFocus
DoCmd DoMenuItem A_FORMBAR, A_EDITMENU, A_COPY
Me!pbClipboard.SetFocus
C = Null
C.Visible = False
Beep
End If
exit_pbClipboard_Click:
Set C = Nothing
Exit Sub
err_pbClipboard_Click:
If Err <> 2427 Then
Fehler "pbClipboard_Click"
Resume exit_pbClipboard_Click
Else
Resume Next
End If
End Sub
MODUL: Arrays
Quelle: dmt
Datum: 06.2004
ARRAYS:
Hinweis: Das Modul läßt sich nicht 1 zu 1 in Access 2.0 einsetzen, da es z.B. bei der Übergabe von Arrays als Parameter-Variable in der aufgerufenen Prozedur (z.B. CountArrayValues()) zu Kompilierungsfehlern kommt.
Erst die Entfernung des Parameters und Ansprechen eines als mind. Modulweit deklarierten Arrays macht die Routine wieder benutzbar.
Option Compare Database
Option Explicit
Function CountArrayValues(vArray As Variant) As Variant
On Error GoTo err_CountArrayValues
CountArrayValues = UBound(vArray) - LBound(vArray) + 1
Exit Function
err_CountArrayValues:
If Err = 9 Then
CountArrayValues = 0
Else
Fehler "CountArrayValues"
End If
Exit Function
End Function
Function CountInArray(v As Variant, sPattern As String, Optional iWo As Integer) As Integer
On Error GoTo err_CountInArray
Dim a As Integer, z As Integer, i As Integer, iAnz As Integer
' Der optionale Parameter iWo wurde eingeführt, um String-Vergleiche am Anfang, am Ende oder
' irgendwo mittendrin durchzuführen, um z.B. ".htm" nicht in die ".html"-Falle tappen zu lassen.
' iWo = 0 steht für irgendwo mittendrin, 1 für vorne und 2 für hinten.
a = LBound(v)
z = UBound(v)
' Um ständige if-Abfragen zu vermeiden, wird der Schleifen-Durchlauf redundant hinterlegt.
If iWo = 0 Then
For i = a To z
If InStr(v(i), sPattern) > 0 Then
iAnz = iAnz + 1
End If
Next i
ElseIf iWo = 1 Then
For i = a To z
If Left$(v(i), Len(sPattern)) = sPattern Then
iAnz = iAnz + 1
End If
Next i
ElseIf iWo = 2 Then
For i = a To z
If Right$(v(i), Len(sPattern)) = sPattern Then
iAnz = iAnz + 1
End If
Next i
Else
Beep
MsgBox "Ungültiger Wert für Parameter iWo = " & iWo & " !", vbCritical, "Modul: Arrays - CountInArray"
End If
CountInArray = iAnz
Exit Function
err_CountInArray:
Fehler "CountInArray"
Exit Function
End Function
Sub SortiereArray(vArray As Variant)
On Error GoTo err_SortiereArray
Dim a As Integer, z As Integer, i1 As Integer, i2 As Integer
Dim Wert1 As String, Wert2 As String
If IsEmpty(vArray) Then Exit Sub
a = LBound(vArray)
z = UBound(vArray)
For i1 = a To z
For i2 = i1 + 1 To z
Wert1 = vArray(i1)
Wert2 = vArray(i2)
If Wert2 < Wert1 Then
vArray(i1) = Wert2
vArray(i2) = Wert1
End If
Next i2
Next i1
Exit Sub
err_SortiereArray:
If Err <> 9 Then
Fehler "SortiereArray"
End If
Exit Sub
End Sub
MODUL: Listenfelder
Quelle: dmt
Datum: 03.2004
LISTENFELDER:
Option Compare Database
Option Explicit
Function GetListFieldAsString(cListField As Control) As String
On Error GoTo err_GetListFieldAsString
Dim i As Integer, s As String
For i = 0 To cListField.ListCount - 1
s = s & cListField.ItemData(i) & " "
Next i
GetListFieldAsString = Trim$(s)
Exit Function
err_GetListFieldAsString:
Fehler "GetListFieldAsString"
Exit Function
End Function
Function GetListFieldRowSourceFromArray(vArray As Variant) As String
On Error GoTo err_GetListFieldRowSourceFromArray
Dim s As String, a As Integer, z As Integer, i As Integer
If IsEmpty(vArray) Then Exit Function
a = LBound(vArray)
z = UBound(vArray)
For i = a To z
s = s & vArray(i) & ";"
Next i
GetListFieldRowSourceFromArray = s
Exit Function
err_GetListFieldRowSourceFromArray:
If Err = 9 Then
GetListFieldRowSourceFromArray = ""
Else
Fehler "GetListFieldRowSourceFromArray"
End If
Exit Function
End Function
Function HasListfieldSelections(cListField As Control) As Boolean
On Error GoTo err_HasListfieldSelections
If cListField.ItemsSelected.Count = 0 Then
Beep
MsgBox "In der Liste '" & cListField.Name & "' wurde kein Eintrag ausgewählt !", vbExclamation, "HasListfieldSelections"
Else
HasListfieldSelections = True
End If
Exit Function
err_HasListfieldSelections:
Fehler "HasListfieldSelections"
Exit Function
End Function
Function GetListFieldRowSourceWithAnzahlFromArray(vSubdaten As Variant, vTopdaten As Variant) As String
On Error GoTo err_GetListFieldRowSourceWithAnzahlFromArray
Dim s As String, a As Integer, z As Integer, i As Integer
If IsEmpty(vSubdaten) Then Exit Function
a = LBound(vSubdaten)
z = UBound(vSubdaten)
For i = a To z
s = s & vSubdaten(i) & ";" & CountInArray(vTopdaten, "." & vSubdaten(i), 2) & ";"
Next i
GetListFieldRowSourceWithAnzahlFromArray = s
Exit Function
err_GetListFieldRowSourceWithAnzahlFromArray:
If Err = 9 Then
GetListFieldRowSourceWithAnzahlFromArray = ""
Else
Fehler "GetListFieldRowSourceWithAnzahlFromArray"
End If
Exit Function
End Function
Function SelectListFieldElements(cListField As Control, bolAlle As Boolean)
On Error GoTo err_SelectListFieldElements
Dim i As Integer
If cListField.ListCount = 0 Then
Beep
MsgBox "Die Liste der '" & cListField.Name & "' enthält keinen Eintrag !" & vbCrLf & vbCrLf & "Starten Sie die Ermittlung der Dateitypen in einem gewünschten Verzeichnis.", vbExclamation, "SelectListFieldElements"
Exit Function
End If
For i = 0 To cListField.ListCount - 1
cListField.Selected(i) = bolAlle
Next i
Exit Function
err_SelectListFieldElements:
Fehler "SelectListFieldElements"
Exit Function
End Function
MODUL: Verzeichnisse rekursiv
Quelle: dmt
Datum: 12.2004
VERZEICHNISSE REKURSIV DURCHSUCHEN ("Verzeichnisse_rekursiv_durchsuchen"):
Komplettes Modul (Access 97):
Option Compare Database
Option Explicit
Private Sub Beispiel_Aufruf()
Dim i As Integer, a As Integer, z As Integer, v As Variant
' v nimmt als Array die rekursiv ermittelten Dateinamen auf
' gesucht wird im übergebenen Pfad
' Ein Substring wird als Namensteil zur Filterung benutzt.
' AllFiles bewirkt bei nein, daß nur tagesaktuelle Dateien ermittelt werden.
Meldung "Die Verzeichnisinhalte werden durchsucht ..."
CrawlDirs v, "C:\Eigene Dateien\homepage\websites\blummer", ".ht", Null
Meldung ""
If IsEmpty(v) Then
Beep
MsgBox "Es konnten keine Array-Daten ermittelt werden.", vbCritical, "pbReadData"
'GoSub exit_pbReadData
End If
a = LBound(v)
z = UBound(v)
For i = a To z
Debug.Print v(i)
Next i
End Sub
Sub CrawlDir(vArray As Variant, Pfad As String, Pattern As String, Optional iWo As Integer)
' Beispiel-Aufruf:
' Dim v()
' CrawlDir v, "I:\websites\breitenbuecher\info\myway\javascript", "htm"
' Der optionale Parameter iWo wurde eingeführt, um String-Vergleiche am Anfang, am Ende oder
' irgendwo mittendrin durchzuführen, um z.B. ".htm" nicht in die ".html"-Falle tappen zu lassen.
' iWo = 0 steht für irgendwo mittendrin, 1 für vorne und 2 für hinten.
On Error GoTo err_CrawlDir
Dim i As Integer, sPfad As String, sName As String
sPfad = Pfad & "\"
sName = Dir(sPfad, vbDirectory) ' Ersten Eintrag abrufen
Do While sName <> "" ' Schleife beginnen
If sName <> "." And sName <> ".." Then ' Aktuelles und übergeordnetes Verzeichnis ignorieren
' Mit bit-weisem Vergleich sicherstellen, daß sName eine Datei und kein Verzeichnis ist.
If (GetAttr(sPfad & sName) And vbDirectory) <> vbDirectory Then
If (Pattern = "" Or HasPattern(sName, Pattern, iWo) = True) Then ' InStr(sName, Pattern) > 0) Then
ReDim Preserve vArray(i)
vArray(i) = Pfad & "\" & sName ' komplett mit Pfad
i = i + 1
End If
End If
End If
sName = Dir ' Nächsten Eintrag abrufen
Loop
SortiereArray vArray
Exit Sub
err_CrawlDir:
Fehler "CrawlDir"
Exit Sub
End Sub
Sub CrawlDirs(vArray As Variant, Pfad As String, NamensTeil As String, vLastCheckDatum As Variant, Optional iNoSort As Boolean, Optional iWo As Integer, Optional DontReduce As Boolean)
On Error GoTo err_CrawlDirs
' Der optionale Parameter iWo wurde eingeführt, um String-Vergleiche am Anfang, am Ende oder
' irgendwo mittendrin durchzuführen, um z.B. ".htm" nicht in die ".html"-Falle tappen zu lassen.
' iWo = 0 steht für irgendwo mittendrin, 1 für vorne und 2 für hinten.
'Dieser Source stammt von http://www.activevb.de und kann frei verwendet werden.
'Für eventuelle Schäden wird nicht gehaftet.
'Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
'Ansonsten viel Spaß und Erfolg mit diesem Source !
'Autor: R. Mueller
'Email: r.mueller@sz-online.de
'Beitrag zum Thema Ordner und Laufwerke nach bestimmten oder allen Dateien rekursiv durchsuchen.
'Beide dargestellten Varianten benutzen keine API sondern die Function Dir$.
'1.Variante: Liste speichern in Datei
'2.Variante: Liste speichern Datenfeld
' Anmerkung: Die Ausgabe erfolgt zu Testzwecken sowohl im Debug-Fenster als auch und in der Datei "C:\Test.txt"
' Die vorliegende Version wurde angepaßt von Thomas Breitenbücher www.breitenbuecher.de
' Zusätzliche Parameter erlauben Vergleiche mit dem Dateidatum sowie Abschalten der Sortierung der Treffer
Dim xpath$ 'Pfad durchsuchen
Dim xSF$ 'gesuchte Files keine Platzhalter
Dim xfn&
Dim xdn$ 'Dateiname zum Speichern der Liste
Dim xArray$()
Dim xln& 'Array index
xpath$ = Pfad
xSF$ = NamensTeil
xSF$ = UCase(xSF$)
Call xDirArray(xpath$, xArray$(), xln&, xSF$, vLastCheckDatum, iWo)
If iNoSort = False Then
Sortiere2DArrayDirsFiles vArray, xArray$(), "Verzeichnisse", "Dateinamen", DontReduce
Else
ReduziereArray vArray, xArray$()
End If
Exit Sub
err_CrawlDirs:
Fehler "CrawlDirs"
Exit Sub
End Sub
Sub CrawlDirsOnlyDirs(vArray As Variant, Pfad As String, NamensTeil As String, vLastCheckDatum As Variant, Optional iWo As Integer)
On Error GoTo err_CrawlDirsOnlyDirs
'Dieser Source stammt von http://www.activevb.de und kann frei verwendet werden.
'Für eventuelle Schäden wird nicht gehaftet.
'Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum.
'Ansonsten viel Spaß und Erfolg mit diesem Source !
'Autor: R. Mueller
'Email: r.mueller@sz-online.de
'Beitrag zum Thema Ordner und Laufwerke nach bestimmten oder allen Dateien rekursiv durchsuchen.
'Beide dargestellten Varianten benutzen keine API sondern die Function Dir$.
'1.Variante: Liste speichern in Datei
'2.Variante: Liste speichern Datenfeld
'Anmerkung: Die Ausgabe erfolgt zu Testzwecken sowohl im Debug-Fenster als auch und in der Datei "C:\Test.txt"
Dim xpath$ 'Pfad durchsuchen
Dim xSF$ 'gesuchte Files keine Platzhalter
Dim xfn&
Dim xdn$ 'Dateiname zum Speichern der Liste
ReDim xArray$(0) 'Datenfeld zum Speichern der Liste
Dim xln& 'Array index
Dim xi&
'gesamtes Laufwerk durchsuchen
'xpath$ = "D:"
'Pfad durchsuchen z.B.
xpath$ = Pfad
'gesuchter Filename enthält folgenden String z.B.:
'xSF$ = ".EXE" 'oder
'xSF$ = ".v" 'oder
'xSF$ = ".doc"
xSF$ = NamensTeil
xSF$ = UCase(xSF$)
' '1.Variante: Liste speichern in Datei
' xdn$ = "C:\Test.txt" 'Dateiname zum Speichern der Liste
' xfn& = FreeFile
' Open xdn$ For Output As xfn&
' Call xDirFile(xpath$, xfn&, xSF$)
' Close xfn&
'2.Variante: Liste speichern Datenfeld
Call xDirArrayOnlyDirs(xpath$, xArray$(), xln&, xSF$, vLastCheckDatum, iWo)
'Ausgabe Array inhalt z.B.:
'For xi& = 1 To UBound(xArray$)
' Debug.Print xArray$(xi&)
'Next xi&
' xMain = xArray$
'ReDim Preserve RekursiveTreffer$(xln&)
SortiereArray xArray$()
TransferArray xArray$(), vArray
'vArray = xArray$()
'xi& = xi&
Exit Sub
err_CrawlDirsOnlyDirs:
Fehler "CrawlDirsOnlyDirs"
Exit Sub
End Sub
Private Sub xDirFile(xpath$, xfn&, xSF$, Optional iWo As Integer)
Dim xa&
Dim xDir$
ReDim xt$(0)
Dim xi&
Dim xAc$
'nur die nichtdokumentierte 63 liefert alle file auch Hidden- und System-Dateien
xDir$ = Dir$(xpath$ & "\*.*", 63)
xa& = 0
If Not xDir$ = "" Then
xt$(0) = xDir$
End If
Do While Not xDir$ = ""
xDir$ = Dir$
If Not xDir$ = "" And Not xDir$ = "." And Not xDir$ = ".." Then
xa& = xa& + 1
ReDim Preserve xt$(xa&)
xt$(xa&) = xDir$
End If
Loop
For xi& = 0 To xa&
If xt$(xi&) = "" Then
Exit For
ElseIf Not xt$(xi&) = "." And Not xt$(xi&) = ".." Then
If Not Dir$(xpath$ & "\" & xt$(xi&), 63) = "" Then 'Alle Files "\*.*" darf nicht verändert werden
If Not GetAttr(xpath$ & "\" & xt$(xi&)) = vbDirectory Then 'vbDirectory =16
If Len(xSF$) > 0 Then
If HasPattern(UCase(xt$(xi&)), xSF$, iWo) = True Then 'InStr(1, UCase(xt$(xi&)), xSF$) > 0 Then
xAc$ = xpath$ & "\" & xt$(xi&)
Print #xfn&, xAc$
End If
End If
End If
End If
Call xDirFile(xpath$ & "\" & xt$(xi&), xfn&, xSF$)
End If
Next xi&
End Sub
Private Sub xDirArray(xpath$, xArray$(), xln&, xSF$, vLastCheckDatum As Variant, Optional iWo As Integer)
On Error GoTo err_xDirArray
Dim bolInsert As Boolean
Dim xa&
Dim xDir$
ReDim xt$(0)
Dim xi&
'Nur die nichtdokumentierte 63 liefert alle file auch Hidden- und System-Dateien
If GetAttr(xpath$) = vbDirectory Then
xDir$ = Dir$(xpath$ & "\*.*", 63) '"\*.*" darf nicht verändert werden
Else
'xDir$ = xpath$
End If
xa& = 0
If Not xDir$ = "" Then
xt$(0) = xDir$
End If
Do While Not xDir$ = ""
xDir$ = Dir$
If Not xDir$ = "" And Not xDir$ = "." And Not xDir$ = ".." Then
xa& = xa& + 1
ReDim Preserve xt$(xa&)
xt$(xa&) = xDir$
End If
Loop
For xi& = 0 To xa&
If xt$(xi&) = "" Then
Exit For
ElseIf Not xt$(xi&) = "." And Not xt$(xi&) = ".." Then
If Not Dir$(xpath$ & "\" & xt$(xi&), 63) = "" Then
If Not GetAttr(xpath$ & "\" & xt$(xi&)) = vbDirectory Then 'vbDirectory =16
If Len(xSF$) > 0 Then
If HasPattern(UCase(xt$(xi&)), xSF$, iWo) = True Then 'InStr(1, UCase(xt$(xi&)), xSF$) > 0 Then
GoSub insert_xDirArray
End If
Else ' kein SearchPattern
GoSub insert_xDirArray
End If
End If
End If
Call xDirArray(xpath$ & "\" & xt$(xi&), xArray$(), xln&, xSF$, vLastCheckDatum)
End If
Next xi&
Exit Sub
insert_xDirArray:
bolInsert = False
If Not IsNull(vLastCheckDatum) Then
If IsDate(vLastCheckDatum) Then
If CVDate(vLastCheckDatum) <= CVDate(FileDateTime(xpath$ & "\" & xt$(xi&))) Then
bolInsert = True
End If
Else
Beep
MsgBox "ungültiges LastCheckDatum: " & vLastCheckDatum
End If
Else
bolInsert = True
End If
If bolInsert = True Then
ReDim Preserve xArray$(1, xln&)
xArray$(0, xln&) = xpath$ & "\" & xt$(xi&)
xArray$(1, xln&) = xpath$
xln& = xln& + 1
End If
Return
err_xDirArray:
Fehler "xDirArray: " & xpath$
Exit Sub
End Sub
Private Sub xDirArrayOnlyDirs(xpath$, xArray$(), xln&, xSF$, vLastCheckDatum As Variant, Optional iWo As Integer)
Dim xa&
Dim xDir$
ReDim xt$(0)
Dim xi&
'Nur die nichtdokumentierte 63 liefert alle file auch Hidden- und System-Dateien
xDir$ = Dir$(xpath$ & "\*.*", 63) '"\*.*" darf nicht verändert werden
xa& = 0
If Not xDir$ = "" Then
xt$(0) = xDir$
End If
Do While Not xDir$ = ""
xDir$ = Dir$
If Not xDir$ = "" And Not xDir$ = "." And Not xDir$ = ".." Then
xa& = xa& + 1
ReDim Preserve xt$(xa&)
xt$(xa&) = xDir$
End If
Loop
For xi& = 0 To xa&
If xt$(xi&) = "" Then
Exit For
ElseIf Not xt$(xi&) = "." And Not xt$(xi&) = ".." Then
If Not Dir$(xpath$ & "\" & xt$(xi&), 63) = "" Then
If GetAttr(xpath$ & "\" & xt$(xi&)) = vbDirectory Then 'vbDirectory =16
' If Len(xSF$) > 0 Then
' If InStr(1, UCase(xt$(xi&)), xSF$) > 0 Then
xln& = xln& + 1
If Not IsNull(vLastCheckDatum) Then
If IsDate(vLastCheckDatum) Then
If CVDate(vLastCheckDatum) - 1 <= CVDate(FileDateTime(xpath$ & "\" & xt$(xi&))) Then
ReDim Preserve xArray$(xln&)
xArray$(xln&) = xpath$ & "\" & xt$(xi&)
End If
Else
Beep
MsgBox "ungültiges LstCheckDatum: " & vLastCheckDatum
End If
Else
ReDim Preserve xArray$(xln&)
xArray$(xln&) = xpath$ & "\" & xt$(xi&)
End If
' End If
' End If
Call xDirArrayOnlyDirs(xpath$ & "\" & xt$(xi&), xArray$(), xln&, xSF$, vLastCheckDatum)
End If
End If
End If
Next xi&
End Sub
Private Function HasPattern(v As Variant, vPattern As Variant, iWo As Integer) As Boolean
On Error GoTo err_HasPattern
If iWo = 0 Then
HasPattern = InStr(v, vPattern) > 0
ElseIf iWo = 1 Then
HasPattern = Left$(v, Len(vPattern)) = vPattern
ElseIf iWo = 2 Then
HasPattern = Right$(v, Len(vPattern)) = vPattern
End If
Exit Function
err_HasPattern:
Fehler "HasPattern"
Exit Function
End Function
Sub Show_Files(Pfad As String, Suchmuster As String, Optional OutputFile As String, Optional PathNotToPrint As String, Optional UnixSlashes As Boolean)
On Error GoTo err_Show_Files
Dim i As Integer, a As Integer, z As Integer, FF As Integer, s As String, v As Variant
' Bei überlangen Inhalten kann die Dateiliste nicht im Info-Fenster bearbeitet werden.
' In diesem Falle kann die Ausgabe alternativ in eine Textdatei erfolgen.
Meldung "Die Verzeichnisinhalte werden durchsucht ..."
CrawlDirs v, Pfad, Suchmuster, Null
Meldung ""
If IsEmpty(v) Then
Beep
MsgBox "Es konnten keine Array-Daten ermittelt werden.", vbCritical, "Show_Files"
Exit Sub
End If
Meldung "Lese Arraydaten aus ..."
a = LBound(v)
z = UBound(v)
For i = a To z
If PathNotToPrint <> "" Then v(i) = ReplaceInString(v(i), PathNotToPrint, "")
If UnixSlashes = True Then v(i) = ReplaceInString(v(i), "\", "/")
s = s & v(i) & vbCrLf
Next i
If Suchmuster = "" Then Suchmuster = "*.*"
If OutputFile = "" Then
ZeigeInhalte Suchmuster & "-Dateien im Verzeichnis " & Pfad, s, "", "", i
Else
FF = FreeFile
Open OutputFile For Output As FF
Print #FF, ""
Print #FF, i & " " & Suchmuster & "-Dateien im Verzeichnis " & Pfad
Print #FF, ""
Print #FF, s
Close #FF
End If
Beep
Meldung ""
Exit Sub
err_Show_Files:
If FF > 0 Then
Close #FF
Meldung ""
End If
Fehler "Show_Files"
Exit Sub
End Sub
Normalisierung
Quelle: dmt
Datum: 03.2004
NORMALISIERUNG / TOOLS:
Ein großes Wort gelassen niedergeschrieben.
Typischer Fall:
In den Literatur-dBase-Tabellen der SEL Alcatel-Stiftung wurden jahrelang Mehrfach-Nennungen von Personen, Körperschaften und Schlagworten in jeweils einem Feld vorgenommen. Als Trennzeichen wurden in wahlfreier Manier '*', ';'
oder ',' verwandt.
Ein von mir (von wem sonst ?) geschriebenes Tool durchläuft eine Datenquelle, zerlegt diese Strings in einzelne Begriffe und legt mit Nennung des Herkunfts-IDs einzelne Begriffsdatensätze an.
Function Extract_Strings_to_Table ()
Exit Function
' On Error GoTo err_Extract_Strings_to_Table
' **** durchläuft für jeden Quell-Datensatz alle Zeichen der ****
' **** der Schlagwort-Kette und legt einzelne Schlagwort- ****
' **** Datensätze in einer Zuordnungstabelle an. ****
Dim i As Integer, iPos As Integer, iTrenn As Integer, iStart As Integer
Dim v As Variant, s As String, sTrenn As String, sSchlagwort As String
Dim DB As Database, RSQ As Recordset, RST As Recordset
' **** Variablen vereinbaren ****
Set DB = DBEngine.Workspaces(0).Databases(0)
Set RSQ = DB.OpenRecordset("Verlorene_Seelen_Q") ', DB_OPEN_TABLE)
Set RST = DB.OpenRecordset("Schlagwort_Zuordnungen", DB_OPEN_TABLE)
' **** sTrenn enthält Zeichen, die als Trennzeichen gewertet werden ****
sTrenn = "*;,"
' **** Anzahl der Datensätze in Quelltabelle ermitteln ****
RSQ.MoveLast
v = SysCmd(SYSCMD_INITMETER, "öffne Datenquelle ...", RSQ.RecordCount)
RSQ.MoveFirst
' **** Schleife durch alle Quelldaten ****
Do While Not RSQ.EOF
i = i + 1
iStart = 1
If IsNull(RSQ.Schlagwort) Then
s = ""
Else
s = RSQ.Schlagwort
End If
' **** String zeichenweise durchlaufen ****
For iPos = 1 To Len(s)
iTrenn = InStr(sTrenn, Mid$(s, iPos, 1))
If iTrenn > 0 Then
GoSub Set_Schlagwort
iStart = iPos + 1
End If
Next iPos
GoSub Set_Schlagwort ' verbleibende Strings o. kein Trennzeichen
RSQ.MoveNext
v = SysCmd(SYSCMD_UPDATEMETER, i)
Loop
' **** Zuordnungstabelle öffnen ****
DoCmd OpenTable RST.Name
exit_Extract_Strings_to_Table:
v = SysCmd(SYSCMD_CLEARSTATUS)
Exit Function
Set_Schlagwort:
If Len(s) = 0 Then Return
sSchlagwort = Trim$(Mid$(s, iStart, iPos - iStart))
If Len(sSchlagwort) > 0 Then
RST.AddNew
RST.Ident = RSQ.Ident
RST.Schlagwort = sSchlagwort
RST.Update
End If
Return
err_Extract_Strings_to_Table:
Fehler "Extract_Strings_to_Table"
GoSub exit_Extract_Strings_to_Table
End Function
Für den Fall, daß unerwarteterweise Fehler auftreten und ein teilweise erfolgreicher Export nicht gelöscht werden soll, kann mit Hilfe der folgenden Abfrage eine Überprüfung verwaister Datensätze vorgenommen werden:
Verlorene_Seelen_Q:
SELECT LITSTG.Schlagwort AS Schlagwort, Schlagwort_Zuordnungen.Schlagwort, LITSTG.IDENT
FROM LITSTG LEFT JOIN Schlagwort_Zuordnungen ON LITSTG.IDENT = Schlagwort_Zuordnungen.Ident
WHERE LITSTG.Schlagwort<>Null AND Schlagwort_Zuordnungen.Schlagwort=Null;
zeigt alle Datensätze der linken Seite 'LITSTG' (deswegen LEFT JOIN), die zwar ein Schlagwort enthalten, zu denen aber in der Tabelle Schlagwort_Zuordnungen keine Auflösungs-Datensätze bestehen.
Das sind dann genau die, die aus irgendeinem Grund von der vorigen Routine übergangen wurden.
Normalisierung, Tippfehler
Quelle: dmt
Datum: 03.2004
Auch sehr beliebt sind bei Normalisierungen die unüberschaubare Anzahl von Tippfehlern, Schreibvariationen etc. p.p., die dem Chef mit entsprechenden Group by / Having - Abfragen so richtig schön unter die Nase gerieben werden können, so daß den erstmal der Schlag trifft.
Del_Brackets entfernt z.B. für jeden Wert im angegebenen Feld der angegebenen Tabelle das angegebene, unerwünschte Zeichen. Das mit der vollmundig angekündigten Transaktion kann bei den traditionell beschränkten Resourcen, Heaps und Stacks und was auch sonst immer überlaufen mag, bei einer großen Menge an Daten auch schief gehen, aber in diesem Fall wurden an den bis zum Abbruch durchlaufenen Daten auch keine Änderungen vorgenommen. Hat zwar dann so nicht geklappt, aber trotzdem Bravo !
Sub Del_Brackets (sTabelle, sFeld)
On Error GoTo err_Del_Brackets
' **** entfernt für jeden Datensatz im sFeld in sTabelle die ****
' **** eckigen Klammern [ und ], und das mit Transaktion ! ****
Dim WS As WorkSpace, DB As Database, RS As Recordset
Dim sReturn As String, i As Integer, v As Variant
Set WS = DBEngine.Workspaces(0)
Set DB = WS.Databases(0)
Set RS = DB.OpenRecordset(sTabelle, DB_OPEN_TABLE)
' **** Anzahl der Datensätze in Quelltabelle ermitteln ****
RS.MoveLast
v = SysCmd(SYSCMD_INITMETER, "Öffne Datenquelle ...", RS.RecordCount)
RS.MoveFirst
'WS.BeginTrans
' **** Schleife durch alle Quelldaten ****
Do While Not RS.EOF
i = i + 1
sReturn = ClearStringFrom(RS("Standort"), "[")
sReturn = ClearStringFrom(sReturn, "]")
If sReturn <> RS("Standort") Then
RS.Edit
RS("Standort") = sReturn
RS.Update
End If
RS.MoveNext
v = SysCmd(SYSCMD_UPDATEMETER, i)
Loop
'WS.CommitTrans
exit_Del_Brackets:
v = SysCmd(SYSCMD_CLEARSTATUS)
Exit Sub
err_Del_Brackets:
'WS.Rollback
Fehler "Del_Brackets"
GoSub exit_Del_Brackets
End Sub
Protokoll
Quelle: dmt
Datum: 03.2004
BENUTZEREINGABEN ÜBERWACHEN / PROTOKOLL / PROTOKOLLIEREN
Die Funktion Protokoll wird in den Formularereignissen VorAktualisierung mit =Protokoll("geändert") und BeimLöschen mit =Protokoll("gelöscht") aufgerufen.
NachLöschBestätigung ist es zu spät, da MS-Access bereits den nächsten Datensatz angesteuert hat.
Das jeweilige, zu überwachende Formular muß allerdings an einer Stelle in der Routine hinterlegt werden.
Im geändert-Fall (tritt auch beim Neuanlegen von Datensätzen ein) werden alle Felder durchlaufen und ihre OldValues mit deren aktuellen gegenübergestellt und in ein Memo-Feld geschrieben. Die Erkennung neuer Datensätze in dieser Schleife wurde wegen diverser OLDVALUE-Problematiken fallengelassen, ebenso wie der Versuch, die Routine vollstaendig unabhängig von expliziten Formular-Verweisen zu machen. Spätestens beim Aufrufen der Protokolldatensätze, um, wenn möglich, die Originaldatensätze wieder anzuzeigen, muß bekannt sein, welches Feld mit welchem Wert zur Identifikation herangezogen werden soll.
Deswegen wird an einer Stelle auf das zu überwachende Formular explizit verwiesen. Hier wird entschieden, wie das Ident-Feld heißt, ob bei Ident=NULL ein neuer Datensatz vorliegt und was im Löschenfall alles in das Protokoll-Memo geschrieben werden soll.
Leider mußte auch die Kröte geschluckt werden, daß editierte Datensätze VorAktualisierung nicht mehr als NEU oder GEÄNDERT identifiziert werden können. Deshalb muß formularbezogen leider auch eine explizite Nennung der Datenherkunfts-Domäne erfolgen, um in einer DLookup-Anweisung anhand Feld, Domäne und Wert die Existenz des Datensatzes zu überprüfen.
Function Protokoll (sModus As String)
' Aufruf aus VorAktualisierung: =Protokoll("geändert")
' Aufruf aus NachLöschen: =Protokoll("gelöscht")
On Error GoTo err_Protokoll1
DoCmd Hourglass True
Dim F As Form
Dim DB As Database, RS As Recordset
Dim s As String, CR As String, sId As String, sTabelle As String
Dim i As Integer, iLog As Integer
Set F = Screen.ActiveForm
CR = Chr$(13) & Chr$(10)
' **** Plausibilitäten ****
If FlascheLeer(F.RecordSource) Then
Beep
MsgBox "Formular mit ungültiger Datenherkunft '" & F.Name & "' !", 16, "Protokoll"
Resume exit_Protokoll
End If
Select Case sModus
Case "geändert": ' nix
Case "gelöscht": iLog = True: GoSub Protokoll_Log
Case Else: Beep
MsgBox "Ungültiger Wert '" & sModus & "' !", 16, "Protokoll"
Resume exit_Protokoll
End Select
' **** Steuerelemente durchlaufen ****
For i = 0 To F.Count - 1
If Variant_Verschieden(F(i).OldValue, F(i)) = True Then
iLog = True
s = s & F(i).Name & ": '" & F(i).OldValue & "' -> '" & F(i) & "'" & CR
End If
Protokoll_weiternudeln:
Next i
' **** Gegebenenfalls Protokolldatensatz anlegen ****
On Error GoTo err_Protokoll2
If Len(s) > 2 Then s = Left$(s, Len(s) - 2) ' lösche letztes CR
Protokoll_Log:
If iLog = True Then
' **** Formular-Identfeld zuweisen ****
Select Case F.Name
Case "Termine": sId = "ID"
sTabelle = "Termine"
If sModus = "gelöscht" Then
s = F!Suchname & " - " & F!Grund & " - " & F!Datum_von & " - " & F!Zeit_von & " - erl.: " & F!erledigt & CR & CR & F!Notiz
End If
Case Else: Beep
MsgBox "Ungültiges Formular '" & F.Name & "' !", 16, "Protokoll"
GoSub exit_Protokoll
End Select
' **** Datensatz anlegen und Werte zuweisen ****
Set DB = DBEngine.Workspaces(0).Databases(0)
Set RS = DB.OpenRecordset("Protokoll", DB_OPEN_TABLE)
RS.AddNew
RS("Aktion") = sModus
RS("Benutzer") = GetUser()
RS("Formular") = F.Name
RS("ID") = sId
RS("Wert") = F(sId)
RS("Info") = s
If sModus = "geändert" Then
If IsNumeric(F(sId)) = False Then
s = sId & "='" & F(sId) & "'"
Else
s = sId & "=" & F(sId)
End If
If IsNull(DLookup(sId, sTabelle, s)) Then
RS("Aktion") = "neu"
End If
End If
RS.Update
End If
exit_Protokoll:
DoCmd Hourglass False
Exit Function
err_Protokoll1:
If Err = 2455 Or Err = 2427 Then
Resume Protokoll_weiternudeln
Else
Fehler "Protokoll"
End If
Resume exit_Protokoll
err_Protokoll2:
Fehler "Protokoll"
Resume exit_Protokoll
End Function
Statusanzeige
Quelle: dmt
Datum: 03.2004
STATUSLEISTE / STATUSZEILE per Code einstellen:
Ein vereinfachtes Handling der Statuszeilen-Problematik:
Sub Statuszeile (Inhalt As String)
On Error GoTo err_Statuszeile
Dim v As Variant
If Inhalt <> "" Then
v = SysCmd(SysCmd_SetStatus, Inhalt)
Else
v = SysCmd(SysCmd_ClearStatus)
End If
Exit Sub
err_Statuszeile:
Fehler "Statuszeile"
Exit Sub
End Sub
Damit können z.Bsp. auch einheitliche Statuszeilen-Texte für die Seitenansicht von Berichten eingestellt werden, um den Anwender über praktischen ShortCuts zu informieren.
Im Ereignis Activate kann dann
Statuszeile_Berichte
und in Deactivate
Statuszeile ""
stehen.
Sub Statuszeile_Berichte ()
On Error GoTo err_Statuszeile_Berichte
Statuszeile "Seitenansicht: schließt Zoom drucken verschieben in vergrößerter Darstellung"
Exit Sub
err_Statuszeile_Berichte:
Fehler "Statuszeile_Berichte"
Exit Sub
End Sub
Stichwortlisten
Quelle: dmt
Datum: 03.2004
STICHWORTLISTEN erstellen:
Dauert zwar sehr lange, tut aber. Per Distinct-Abfrage und in neue Tabelle einspielen können diese Daten zusammengefasst bearbeitet werden.
Private Sub Stichwortliste (sQuelltabelle As String, sQuellfeld As String)
On Error GoTo err_Stichwortliste
Dim DB As Database, RSQ As Recordset, RST As Recordset
Dim v As Variant, i As Integer, iNumWords As Integer, iWord As Integer
v = SysCmd(SYSCMD_SETSTATUS, "Tabellen werden geöffnet ...")
Set DB = DBEngine.Workspaces(0).Databases(0)
Set RSQ = DB.OpenRecordset(sQuelltabelle, DB_OPEN_TABLE)
Set RST = DB.OpenRecordset("Stichwortliste", DB_OPEN_TABLE)
RSQ.MoveLast
v = SysCmd(SYSCMD_INITMETER, "Daten werden ausgelesen ...", RSQ.RecordCount)
RSQ.MoveFirst
Do While Not RSQ.EOF
i = i + 1
iWord = 1
v = RSQ(sQuellfeld)
If Not IsNull(v) Then
iNumWords = SumWordsInStr(CStr(v))
Do While iWord <= iNumWords
RST.AddNew
RST("Stichwort") = GetWordFromStr(iWord, CStr(v))
RST.Update
iWord = iWord + 1
Loop
End If
v = SysCmd(SYSCMD_UPDATEMETER, i)
RSQ.MoveNext
Loop
v = SysCmd(SYSCMD_REMOVEMETER)
Exit Sub
err_Stichwortliste:
Fehler "Stichwortliste"
Exit Sub
End Sub
Später werden diese Daten per DISTINCT-Abfrage zusammengefasst und gegebenenfalls bereinigt in eine finale Stichworttabelle kopiert.
Tastaturbelegung anzeigen
Quelle: dmt
Datum: 05.2006
TASTATURBELEGUNGEN anzeigen:
Das Bereitstellen von Tastaturbelegungs-Makroeinträgen sowie eigenen Stammdaten-Menü, die in selbstgeschriebenen Standard-Menüs enthalten sind, bieten dem interessierten Anwender starke Möglichkeiten. Im Gegensatz zu relativ übersichtlichen Pulldown-Menü bleiben die eigenen ShortCuts aber im Dunkeln, so er denn keine gelben Klebezettel z.B. am Monitor hat.
Abhilfe schafft da diese Routine, die die entsprechenden Daten aus einer des MS-Access-Systemtabellen ausliest und in einer MsgBox anzeigt:
Function ShowShortCuts ()
On Error GoTo err_ShowShortCuts
Dim DB As Database, RS As Recordset
Dim s As String, CR As String
Set DB = DBEngine.Workspaces(0).Databases(0)
Set RS = DB.OpenRecordset("SELECT Comments FROM MSysMacros WHERE ScriptName = 'Tastaturbelegung' And Comments <> '' ORDER BY Label")
CR = Chr$(13) & Chr$(10)
Do While Not RS.EOF
s = s & RS.Comments & CR
RS.MoveNext
Loop
s = Left$(s, Len(s) - 2)
MsgBox s, 64, "Liste der Tastaturbelegungen"
Exit Function
err_ShowShortCuts:
Fehler "ShowShortCuts"
Exit Function
End Function
Wenn jetzt noch im Kommentar-Makro-Eigenschaften-Feld die Tastaturkürzel a'la <Strg+Shift+x> gefolgt von Tabulatoren angegeben werden, kommt das in der MessageBox dann auch so richtig gut. s.a. bestatt.mdb
Umgebungsvariablen
Quelle: dmt
Datum: 03.2004
Mal wieder was Positives:
UMGEBUNGSVARIABLEN können per Environ$(x) bequem ausgelesen werden. Der Index beginnt unlogischerweise bei 1, naja, aber die Zahl kann beliebig sein (wird gerundet), es werden immerhin sauber begrenzte Strings (oder "") geliefert und man kann die Funktion wahlweise per Index oder Umgebungsvariablen-Name-String ansprechen.
Wenn also ein Environ$("Path") einen leeren String zurückgibt, dann wurde eben keine Path-Variable gesetzt bzw. sie enthält keinen Wert und man muß keine aufwendigen Index-Durchnudelungen vornehmen, um festzustellen, ob ein Eintrag auch enthalten ist, bevor man ihn fehlerlos abfragen darf.
Die folgende Routine dient nur noch zu Demonstrationszwecken:
Private Sub Show_Environment ()
Dim i As Integer, s As String
Do
i = i + 1
s = Environ$(i)
If s <> "" Then
MsgBox "'" & s & "'", , "Environment-Eintrag No." & i
MsgBox "'" & Environ$(Left$(s, InStr(s, "=") - 1)) & "'", , "Wert der Umgebungsvariable '" & Left$(s, InStr(s, "=") - 1) & "'"
Else
Exit Do
End If
Loop
End Sub
Verzeichnisse
Quelle: dmt
Datum: 03.2004
ALLGEMEINES zu UNTERVERZEICHNISSEN und DATEI-OPERATIONEN
Das AKTUELLE ARBEITSVERZEICHNIS und SYSCMD_ACCESSDIR:
Die beiden Dinge ergeben leider nicht immer dasselbe.
Das aktuelle Arbeitsverzeichnis ist das, das uns z.Bsp. als Laufwerk/Pfad im Dialog 'Datei öffnen' präsentiert wird.
SYSCMD_ACCESSDIR liefert uns Laufwerk/Pfad, in dem die ausführbare Datei von MS-ACCESS bzw. Runtime-Modul (msarsch.exe) steht.
Das führt bei dem Versuch, Verzeichnis-Kacke innerhalb von MS-ACCESS und ausgelieferten Runtime-Installationen auf die Reihe zu kriegen, natürlich zu Problemen.
SYSCMD_ACCESSDIR liefert den Pfad, in dem die ausführbare ACCESS-Exe-Datei steht. Wenn aber auf das Verzeichnis Bezug genommen werden soll, in dem die MDB-Datei steht, in der die aktuelle Anwendung abläuft (that's where things are going on), sollte man sich darauf besser nicht verlassen. Das Abfragen der Eigenschaft 'Name' des Objektes
DBEngine.Workspaces(0).Databases(0)
bringt hier das gewünschte Ergebnis. Für Unterverzeichnis-Operationen, für die genau das gebraucht wird, muß der String aber erst noch bereinigt werden, weil er hinten raus den Namen der Datenbank beeinhaltet.
siehe auch DataBase_Dir ().
Verzeichnisse, Datenbank
Quelle: dmt
Datum: 06.2004
Die folgende Funktion liefert Pfad der aktuellen Datenbank a'la 'C:\DAT013KL':
Function Database_Dir () As String
On Error GoTo err_Database_Dir
Dim DB As Database, p As Integer, x As Integer, s As String
Set DB = DBEngine.Workspaces(0).Databases(0)
s = DB.Name
Do
p = InStr(p + 1, s, "\")
If p > 0 Then
x = p
Else
Exit Do
End If
Loop
Database_Dir = Left$(s, x - 1)
exit_Database_Dir:
Set DB = Nothing
Exit Function
err_Database_Dir:
Fehler "Database_Dir"
Resume exit_Database_Dir
End Function
Die folgende Funktion liefert den Namen der aktuellen Datenbank a'la 'TRANSACT.MDB':
Function Database_Filename () As String
On Error GoTo err_Database_Filename
Dim DB As Database, p As Integer, x As Integer, s As String
Set DB = DBEngine.Workspaces(0).Databases(0)
s = DB.Name
Do
p = InStr(p + 1, s, "\")
If p > 0 Then
x = p
Else
Exit Do
End If
Loop
Database_Filename = Right$(s, Len(s) - x)
Exit Function
err_Database_Filename:
Fehler "Database_Filename"
Exit Function
End Function
Eine allgemeine Funktion, die den reinen DATEINAMEN aus einer vollständigen Angabe wie z.B. 'e:\access\bosch\dat013kl\dat013kl.txt' ermittelt -> 'dat013kl.txt', ist:
Function Get_Filename (s As String) As String
On Error GoTo err_Get_Filename
Dim p As Integer, x As Integer
Do
p = InStr(p + 1, s, "\")
If p > 0 Then
x = p
Else
Exit Do
End If
Loop
Get_Filename = Right$(s, Len(s) - x)
Exit Function
err_Get_Filename:
Fehler "Get_Filename"
Exit Function
End Function
und dementsprechend für PFADE: (auch sinnvollerweise GetPathName benennbar)
Function Get_Dirname (s As String) As String
On Error GoTo err_Get_Dirname
Dim p As Integer, x As Integer
Do
p = InStr(p + 1, s, "\")
If p > 0 Then
x = p
Else
Exit Do
End If
Loop
Get_Dirname = Left$(s, x - 1)
Exit Function
err_Get_Dirname:
Fehler "Get_Dirname"
Exit Function
End Function
Verzeichnisse, Existenz
Quelle: dmt
Datum: 03.2004
Verzeichnis auf Existenz prüfen:
Function Exists_Dir(sDir As String) As Integer
On Error GoTo err_Exists_Dir
' mußte geändert werden, da bei Dateinamen ohne Pfadbeigabe
' die Anweisung InStr(sFile, Dir$(sFile)) fälschlicherweise 1 ergibt.
Dim s As String
s = Dir$(sDir, vbDirectory)
If InStr(sDir, s) And Len(s) > 0 Then
Exists_Dir = True
End If
Exit Function
err_Exists_Dir:
Fehler "Exists_Dir"
Exit Function
End Function
Verzeichnisse, Inhalt
Quelle: dmt
Datum: 03.2004
DIR$ / VERZEICHNISINHALT ANZEIGEN:
Das folgende Beispiel arbeitet abhängig von einem positiven Ergebnis der Suchmuster-Angabe die Namen der ersten sowie aller weiteren Dateien, die dem eingangs verwendetem Dateikriterium entsprechen.
Dim s As String
s = Dir$(DataBase_Dir() & "\*.bmp")
If Len(s) > 0 Then
Do
MsgBox s
s = Dir
Loop Until Len(s) = 0
MsgBox "Keine weiteren Übereinstimmungen gefunden."
Else
MsgBox "Die angegebene Datei konnte nicht gefunden werden."
End If
Einleuchtender finde ich die Version:
sFile = Dir$(sImportPattern)
If sFile <> "" Then ' Datei gefunden
Do
' **** Dateianweisungen ****
sFile = Dir
Loop Until sFile = "" ' weitermachen
Else
End If
Eine Access97-Version mit Übergabe an ein sortiertes Array findet sich unter CrawlDir().
Verzeichnisse, prüfen, anlegen
Quelle: dmt
Datum: 03.2004
UNTERVERZEICHNIS prüfen, anlegen:
CheckDir prüft das Vorhandensein eines angegebenen Unterverzeichnisses unter dem Datenbank-Verzeichnis und bietet bei gesetztem Parameter das Anlegen an. Um ganz sicher zu gehen, wird zuerst das Laufwerk und dann das Verzeichnis auf das Datenbank-Verzeichnis gesetzt.
Function CheckDir (Dirname As Variant, iCreate As Integer) As Integer
' **** wechselt vom Datenbank-Verzeichnis testweise ****
' **** in das angegebene Unterverzeichnis, um fest- ****
' **** zustellen, ob es existiert und legt es bei ****
' **** Bedarf an.
On Error GoTo err_CheckDir
Dim sDBDir As String
sDBDir = Database_Dir()
Start_CheckDir:
ChDrive sDBDir
ChDir sDBDir
ChDir Dirname
ChDir sDBDir
CheckDir = True
Exit Function
err_CheckDir:
If Err = 76 Then
If iCreate = True Then
Beep
If MsgBox("Das Unterverzeichnis '" & Dirname & "' existiert nicht." & Chr$(13) & Chr$(10) & Chr$(13) & Chr$(10) & " Möchten Sie dieses Verzeichnis anlegen ?", 36, "Unterverzeichnis anlegen") = 6 Then
MkDir Dirname
Resume Start_CheckDir
Else
Exit Function
End If
Else
Beep
MsgBox "Das Unterverzeichnis '" & sDBDir & "\" & Dirname & "' existiert nicht !", 16, "Verzeichnis nicht vorhanden"
Exit Function
End If
Else
Fehler "CheckDir"
Exit Function
End If
End Function
* * * *
MkDir legt direkt ein angegebenes Verzeichnis auf dem angegebenen Datenträger an, aber leider nur mit einer 'Tiefe' von 1. Das kann im Bedarfsfall ganz schön schwierig werden und wenn die Daten nicht in einer aufbereiteten, sortierten Form a'la dmt.mdb / Formular Pflege_Ausgabe vorliegen, wo sie der Reihe und Tiefe nach abgearbeitet werden können, muß wohl umständlich mit CheckDir gearbeitet werden.
Verzeichnisse, rekursiv
Quelle: dmt
Datum: 03.2004
VERZEICHNIS-INHALTE / DATEIEN REKURSIV AUSLESEN / DURCHSUCHEN
Ein keineswegs profanes Thema.
Die Beispiele zeigen das Zusammenspiel der Routinen CrawlDirs und xDirArray:
Hier wird sogar ein zweidimensionales Array gebildet, um Verzeichnisnamen zum Vor-Sortieren sowie komplette Angaben (Pfad und Dateiname) getrennt handhaben zu können.
Grund war die Umsetzung des Wunsches, Dateien in Verzeichnissen sortiert in einem Array zu halten. Eine simple Sortierung konnte die Verzeichnis-Ebenen-Tiefe der Dateiliste nicht berücksichtigen.
So wurde das entsprechende "Arbeits"-Array
um eine Dimension erweitert, in der nur die Verzeichnis-Namen stehen.
Durch zwei Sortiervorgänge (erst nach Verzeichnissen und dann pro Verzeichnis nach den Inhalten der ersten Dimension) konnte das gewünschte Ziel erreicht werden.
Rund gemacht wird das Ganze in SortiereArray() mit anschließender Rückführung zu einem eindimensionalen Array in ReduziereArray().
Siehe auch das komplette Modul: (Access97 aus webmanag.mdb)
Verzeichnisse, übergeordnete
Quelle: dmt
Datum: 07.2004
Die Funktion nennt den Namen des Verzeichnis, das die Anzahl der angegebenen Ebenen über dem genannten liegt.
Function GetUpperDirectory (sDir As String, iLevel As Integer) As String
On Error GoTo err_GetUpperDirectory
Dim s As String, i As Integer, iPosLastSlash As Integer
Const PATH_SEPARATING_SLASH = "\"
' **** Wie lautet das Verzeichnis, das die Anzahl von iLevel Ebenen über dem angegebenen steht ? ****
s = sDir
If Right$(s, 1) = PATH_SEPARATING_SLASH Then ' evtl. Slash am Ende entfernen
s = Left$(s, Len(s) - 1)
End If
' Die Schleife wird ab iLevel=1 oder höher abgearbeitet.
' Ein zu hohes iLevel erzeugt den Fehler 5.
Do While i < iLevel
i = i + 1
iPosLastSlash = LastInStr(s, PATH_SEPARATING_SLASH)
s = Left$(s, iPosLastSlash - 1)
Loop
GetUpperDirectory = s
Exit Function
err_GetUpperDirectory:
If Err = 5 Then
Beep
MsgBox "Die Anzahl der angegebenen Ebenen (" & iLevel & ") ist zu hoch !" & Chr$(13) & Chr$(10) & Chr$(13) & Chr$(10) & "Das angegebene Verzeichnis lautet: '" & sDir & "'.", 16, "GetUpperDirectory"
Else
Fehler "GetUpperDirectory"
End If
Exit Function
End Function
Verzeichnisse, wechseln
Quelle: dmt
Datum: 03.2004
Oft ist es sinnvoll, ein bestimmtes Verzeichnis gesichert zum aktiven zu machen.
Was gab's da schon Ärger, wenn z.B. zip-executables in ihrem temp-Verzeichnis korrekt aufgerufen wurden und diese sich dann in ein ganz anderes Verzeichnis hinein auspacken wollten, weil dieses gerade das aktive Verzeichnis war.
ChDrive wechselt, wenn möglich, zum ermittelten Laufwerk, ChDir dann mit einer Eindringtiefe > 1 in das gewünschte Verzeichnis. Per Rückgabewert ist dann auch bekannt, ob die Sache erfolgreich war. Bei Diskette-nicht-im-Laufwerk-Fehler gibt's sogar Wiederholmöglichkeiten.
Function ForceDir (sDir As String) As Integer
On Error GoTo err_ForceDir
' **** Wechselt auf jeden Fall in das vorhandene Verzeichnis sDir, ****
' **** auch wenn es auf einem anderen Laufwerk liegen sollte. ****
ChDrive sDir
ChDir sDir
ForceDir = True
Exit Function
err_ForceDir:
If Err = 71 Or Err = 76 Then
Beep
If MsgBox("Das (Disketten)-Laufwerk '" & sDir & "' ist nicht bereit." & Chr$(13) & Chr$(10) & Chr$(13) & Chr$(10) & "Legen Sie bitte den entsprechenden Datenträger in das Laufwerk ein.", 53, "Laufwerk nicht bereit") = 4 Then
Resume
End If
Else
Fehler "ForceDir"
End If
Exit Function
End Function
Vorlage, Standard, Datensätze, Schleife
Quelle: dmt
Datum: 07.2006
STANDARD-DURCHLAUFEN von DATENSÄTZEN:
So richtig schön mit Statuszeiger und Errorhandler:
On Error goto err_Standard
Dim i As Integer, v As Variant
Dim DB As Database, RS As Recordset
' **** Variablen vereinbaren ****
Set DB = DBEngine.Workspaces(0).Databases(0)
Set RS = DB.OpenRecordset("Tabelle") ', DB_OPEN_TABLE)
' **** Anzahl der Datensätze in Quelltabelle ermitteln ****
RS.MoveLast
v = SysCmd(SYSCMD_INITMETER, "öffne Datenquelle ...", RS.RecordCount)
RS.MoveFirst
' **** Schleife durch alle Quelldaten ****
Do While Not RS.EOF
i = i + 1
' **** ANWEISUNG ****
RS.MoveNext
v = SysCmd(SYSCMD_UPDATEMETER, i)
Loop
exit_Standard:
v = SysCmd(SYSCMD_CLEARSTATUS)
Exit Sub
err_Standard:
Fehler "Standard"
Resume exit_Standard
Vorlage, Standard, Sub, Objektvariablen
Quelle: dmt
Datum: 07.2006
VORLAGEN:
Standard-Sub mit Datenbank- und Recordset-Deklaration, Fehlerhandler sowie Access2- und -97-kompatiblen Destruktoren für die Objekt-Variablen:
Private Sub XYZ ()
On Error GoTo err_XYZ
Dim DB As Database, RS As Recordset
Dim s As String, CR As String, sTab As String, v As Variant, i As Integer
sTab = Chr$(9)
CR = Chr$(13) & Chr$(10)
Set DB = DBEngine.Workspaces(0).Databases(0)
Set RS = DB.OpenRecordset("test", DB_OPEN_TABLE)
v = SysCmd(SYSCMD_INITMETER, "Die Daten werden verarbeitet ...", RS.RecordCount)
Do While Not RS.EOF
i = i + 1
v = SysCmd(SYSCMD_UPDATEMETER, i)
RS.MoveNext
Loop
exit_XYZ:
v = SysCmd(SYSCMD_REMOVEMETER)
Set RS = Nothing
Set DB = Nothing
Exit Sub
err_XYZ:
Fehler "XYZ"
Resume exit_XYZ
End Sub
Wählhilfe
Quelle: dmt
Datum: 03.2004
Die WÄHLHILFE / TELEFONIEREN über Access:
Geht, und zwar mit Hilfe des Wählhilfe-Assistenten. Was da wirklich passiert und welche Dateien man dazu braucht, steht natürlich nirgends. Schließlich werden da so interessante Dinge wie Umgang mit COM-Ports u.ä. abgecheckt, was ja laut Aussagen von microsoft selbst mit 'neueren' Visual Basic's Probleme bereiten soll oder mit Access-VB-Bordmitteln auch gar nicht geht.
Was kann bisher gesagt werden:
Der Aufruf erfolgt über eine Funktion wlib_Autodial, die einen String-Parameter erwartet.
Diese Funktion versucht, den übergebenen String zu bereinigen und einer globalen Variablen zuzuweisen. Anschließend wird nur ein Formular wlib_frmAutoDial geöffnet, in dem dann auch eine ganze Menge geschieht (bis zum Hinterlegen von Benutzereinstellungen für den ComPort in der win.ini).
Das Ganze steht komplett in wzlib.mda, die Funktion im Modul wlib_Entry.
Den Gedanken ans Extrahieren dieser ganzen Geschichte (von wegen Triumph des Willens) habe ich angesichts der Komplexität (Auslesen eigener Fehlertabellen, API ohne Ende und undurchsichtigstes Spiel mit globalen Variablen, schnell bleiben lassen, da schließlich alles schon in wzlib.mda steht, die meist wegen nützlicher Sachen wie
-Zoom-Fenster eh' schon (illegal) mitgeliefert wird.
Falls es mir aber doch einmal zu langweilig sein sollte, kann mit der Sub 'myDial' im Formular 'wlib_frmAutoDial' experimentiert werden. Ausser einem eigenem Datentyp sowie einer weiteren Sub und ein paar API-Funktionen passiert da gar nicht so viel, zudem muß dann auch nicht mit dem Wählhilfe-Dialog gearbeitet werden, der obendrein bei jedem 'Ok' die aktuellen Einstellungen in die win.ini reinschreibt, auch wenn gar nichts geändert wurde !
Empfohlen wird folgende Vorgehensweise:
Aufruf der Funktion wlib_Autodial an geeigneter Stelle innerhalb der Anwendung.
Da das Säubern des übergebenen Strings (wird in Access automatisch mit markiertem Text übernommen) in der Funktion etwas Scheiße ist ("Du 20-fach dumme Sau 88!" wird zu "20-"), kann man ja einfach eine intelligentere Routine vorschalten und wzlib.mda dann den Rest erledigen lassen. Selbst ein Vorgaben-Tools-Aufruf ist per i=wlib_Autodial("") kein Problem und man kann auch per Menüleiste z.B.an die Com-Einstellungen (Nebenstelle etc.) heran.
Zum Säubern der Strings (Telefonnummern-Bereinigung) empfehlen wir eine Funktion a'la
Function Clean_and_Dial (v As Variant) As String
On Error GoTo err_CleanDialString
' **** entferne aus Parameter alle Nicht-Zahlen ****
Dim i As Integer, s As String, sDial As String
If Not IsNull(v) Then
For i = 1 To Len(v)
s = Mid$(v, i, 1)
If (Asc(s) >= 48 And Asc(s) <= 57) Then
sDial = sDial & s
End If
Next i
End If
If Len(sDial) = 0 Then
Beep
Else
i = wlib_AutoDial(sDial) ' wzlib.mda-Wählhilfe-Funktion
End If
Exit Function
err_CleanDialString:
Fehler "CleanDialString"
Exit Function
End Function
, die auf einer Seite sehr restriktiv ist, da sie ALLE Nicht-Zahlen eliminiert, aber auf der anderen Seite auch Eingaben wie 'pr. 12345 abends' korrekt auswertet und zuläßt und wenn denn was übrig geblieben ist, die wzlib-Wählhilfe startet.
Zeit, Funktionen
Quelle: dmt
Datum: 09.2009
ZEITFUNKTIONEN werden manchmal besser auch durch eigene erweitert:
(mittlerweile zusammengefasst in einem Modul Datumsfunktionen, z.B. in bestatt.mdb; siehe auch ZEITFUNKTIONEN)
Function CDate (vDatum As Variant) As Single
' Wertet Datumsparameter div. Formate aus
' und gibt Datumsanteil als Single zurück.
On Error GoTo err_CDate
If IsNull(vDatum) Then
CDate = 0
Else
CDate = CSng(DateValue(Format(vDatum, "dd.mm.yyyy")))
End If
Exit Function
err_CDate:
Fehler "CDate"
Exit Function
End Function
und
Function CTime (Datum As Variant) As Single
' Wertet Datumsparameter div. Formate aus
' und gibt Zeitwert als Single zurück.
On Error GoTo err_CTime
If IsNull(Datum) Then
CTime = 0
Else
CTime = CSng(TimeValue(Format(Datum, "hh:nn")))
End If
Exit Function
err_CTime:
Fehler "CTime"
Exit Function
End Function
sowie eine Funktion, die Angaben im Format h:nn oder 1,5 oder 1.5 umwandelt.
Somit erfolgt eine bequeme Umwandlung dezimaler bzw. 60er-basierter Angaben von Stunden und Minuten.
Function Zeitumwandlung (v As Variant) As Variant
On Error GoTo err_Zeitumwandlung
Dim h As Variant, n As Variant
' **** Umwandlung von Zeitwerten, die Stunden und Minuten enthalten ****
' erlaubte Eingabeformate: h:nn oder dezimal mit Komma oder Punkt
' die Ausgabe erfolgt korrespondierend als h:nn oder Komma-dezimal mit gerundeten Minutenwerten
' Plausibilitätsprüfung: ist der übergebene Wert ein Zeitwert?
If IsNumeric(v) Then
' IsNumeric zuerst abfragen, um auch 1.1 als Wert zu erkennen (und nicht als Datum)
v = ReplaceInString(v, ".", ",") ' Wert 100%ig im deutschen Format weiterverarbeiten
h = Fix(v)
n = Format((v - h) * 60, "00")
v = h & ":" & n
ElseIf IsDate(v) Then
v = CVDate(v)
h = DatePart("h", v)
n = Format(DatePart("n", v) / 6 * 10, "00")
v = h & "," & n
Else
Beep
v = 0
MsgBox "'" & v & "' ist weder ein Datum noch ein numerischer Wert!", 16, "Zeitumwandlung"
End If
Zeitumwandlung = v
Exit Function
err_Zeitumwandlung:
Fehler "Zeitumwandlung"
Exit Function
End Function
Zeit, Jahr 2000, Y2k
Quelle: dmt
Datum: 04.2006
Fast untrennbar verbunden mit Zeit- und Datums-Problematiken ist das Jahr2000 oder auch y2k-Problem.
Laut Microsoft sollte man bei Datums-Eingabe-Feldern das Eingabeformat auf 4-stellige Jahreszahlen umstellen, das wars dann schon !
1999 wurden dann dll-Patches rausgebracht, die 2-stellige Jahreszahlen von 00-29 '20' voranstellen und '30-99' als zu 1900 zugehörig behandeln. Ausgetauscht werden hierfür alle msabc200.dll und msaju200.dll. Aus die Maus.
Beispiel zum Berechnen und Umwandeln von Zeit- und Datumswerten:
'------------------------------------------------------------------
' This function calculates the elapsed time between two values and
' formats the result in four different ways.
'
' The function accepts interval arguments such as the following:
'
' #5/12/95 6:00:00AM# - #5/11/95 10:00:00PM#
'
' -or-
'
' [End Time]-[Start Time]
'------------------------------------------------------------------
Function ElapsedTime (Interval)
Dim x
x = Int(CSng(Interval * 24 * 3600)) & " Seconds"
Debug.Print x
x = Int(CSng(Interval * 24 * 60)) & ":" & Format(Interval, "ss")_
& " Minutes:Seconds"
Debug.Print x
x = Int(CSng(Interval * 24)) & ":" & Format(Interval, "nn:ss") _
& " Hours:Minutes:Seconds"
Debug.Print x
x = Int(CSng(Interval)) & " days " & Format(Interval, "hh") _
& " Hours " & Format(Interval, "nn") & " Minutes " & _
Format(Interval, "ss") & " Seconds"
Debug.Print x
End Function
3. Im Direktfenster:
? ElapsedTime(#6/1/93 8:23:00PM#-#6/1/93 8:12:12AM#) eingeben
Ausgabe:
43848 Seconds
730:48 Minutes:Seconds
12:10:48 Hours:Minutes:Seconds
0 days 12 Hours 10 Minutes 48 Seconds
Und dann noch was zu dem leidigen Thema:
Comparing Date Data
Because dates and times are stored together as double-precision numbers, you may receive unexpected results when you compare Date/Time data. For example, if you type the following expression in the Debug window (or the Immediate window in earlier versions), you receive a false (0) result even if today's date is 3/31/95:
? Now()=DateValue("3/31/95")
The Now() function returns a double-precision number representing the current date and time. However, the DateValue() function returns an integer number representing the date but not a fractional time value. As a result, Now() equals DateValue() only when Now() returns a time of 00:00:00 (12:00:00 A.M.).
To receive accurate results when you compare date values, use one of the functions below. To test each function, type it in the Debug window (or the Immediate window), substitute the current date for 3/31/95, and then press ENTER:
To return an integer value, use the Date()-function:
? Date()=DateValue("3/31/95")
To remove the fractional portion of the Now() function, use the Int()-function:
? Int(Now())=DateValue("3/31/95")
Comparing Time Data
When you compare time values, you may receive inconsistent results because a time value is stored as the fractional portion of a double-precision, floating-point number. For example, if you type the following expression in the Immediate window, you receive a false (0) result even though the two time values look the same:
NOTE: The time values that fail depend on the version of Visual Basic for Applications.
Access 2.0:
var1 = #2:00:00 PM#
var2 = DateAdd("n", 10, var1)
? var2 = #2:10:00 PM#
Access 95 and 97:
var1 = #2:01:00 PM#
var2 = DateAdd("n", 10, var1)
? var2 = #2:11:00 PM#
When Microsoft Access converts a time value to a fraction, the calculated result may not be the exact equivalent of the time value. The small difference caused by the calculation is enough to produce a false (0) result when you compare a stored value to a constant value.
To receive accurate results when you compare time values, use one of the methods below. To test each method, type it in the Immediate window, and then press ENTER:
Add an associated date to the time comparison:
var1 = #1/1/90 2:00:00 PM#
var2 = DateAdd("n", 10, var1)
? var2 = #1/1/90 2:10:00 PM#
Convert the time values to String data types before you compare them:
var1 = #2:00:00 PM#
var2 = DateAdd("n", 10, var1)
? CStr(var2) = CStr(#2:10:00 PM#)
Use the DateDiff() function to compare precise units such as seconds:
var1 = #2:00:00 PM#
var2 = DateAdd("n", 10, var1)
? DateDiff("s", var2, #2:10:00 PM#) = 0
Zufallsgenerator
Quelle: dmt
Datum: 11.2004
Eine Funktion zur Ermittlung einer Zufallszahl im angegebenen Bereich.
Erlaubt auch negative Werte, allerdings muß der Unten-Wert tatsächlich kleiner als der oben-Wert sein.
Function ZufallsInteger (Unten, Oben)
' **** Gibt eine Zufallszahl im angegebenen Bereich zurück ****
On Error GoTo err_ZufallsInteger
' Plausibilitäten
If Not IsNumeric(Unten) Or Not IsNumeric(Oben) Then
Beep
MsgBox "Die Werte für Unten='" & Unten & "' und Oben='" & Oben & "' müssen beide numerisch sein !", 16, "Zufallsinteger"
Exit Function
End If
If Unten > Oben Then
Beep
MsgBox "Der Wert für Unten='" & Unten & "' darf nicht größer als der Wert für Oben='" & Oben & "' sein !", 16, "Zufallsinteger"
Exit Function
End If
' Zufallswert ermitteln
Randomize
ZufallsInteger = Int((Oben - Unten + 1) * Rnd + Unten)
Exit Function
err_ZufallsInteger:
Fehler "ZufallsInteger"
Exit Function
End Function