infobase: EDV - MS-Access
- Allgemein
- Access beenden
- allgemein
- Auflösung
- Ausdrücke
- Dateien, Klein- und Großschreibung
- Datenbank, Bibliothek
- Datenbank, externe
- Datenbank, externe anlegen
- Datenbank, externe, BETRIEVE
- Datenbank, reparieren
- Datenbankobjekte listen
- DDE
- DDE: Beispiele
- Grafiken & Dimensionen
- Lizenz-Fehler
- Objekte manipulieren
- Objekte, Existenz prüfen
- Objekte, löschen, austauschen
- odbc
- Stammdaten
- Statuszeile
- Systemobjekte
- Timer
- Tuning
- Vergleich von Access mit Excel
- Verzögerung
|
Allgemein
Access beenden
Quelle: dmt
Datum: 01.2008
Das BEENDEN einer Applikation per Application.Quit
kann zum mittleren Drama werden, wenn man edlerweise einen Dialog zwischenschalten will, der z.B. ein Datensicherungsmenü oder wenigstens eine Nachfrage anbietet und dies wahlweise per Schaltfläche, aber auch beim
<Strg+F4>-Schließen des Formulares ausgelöst werden soll.
Ruckzuck werden Ereignisse mehrfach aufgerufen, aller Versuche mit Formular-globalen Variablen scheitern, da diese beim Ereignis FORM_UNLOAD scheinbar vergessen werden, und übrig bleibt nur Frust.
Kommt Zeit, kommt Rat, aber meistens ist guter Rat teuer:
Die wohl beste Lösung zum Thema 'Schließen einer Anwendung' sieht aus wie folgt:
Einem Steuerelement 'pb_Ende' wird folgender Code zugeordnet:
Sub pb_Ende_Click ()
On Error GoTo err_Ende
DoCmd Close A_FORM, Me.Name
Exit Sub
err_Ende:
Me!pb_Ende.SetFocus
Exit Sub
End Sub
Wenn bei Form_Unload das Schließen verneint wird ('Abbrechen' gewählt), tritt für die Close-Anweisung ein Fehler und oft auch ein Fokusverlust ein, der durch den Fehlerhandler behoben wird.
Fürs Entladen des Formulares gilt:
Sub Form_Unload (Cancel As Integer)
Cancel = DontQuitApp()
End Sub
Die erweiterte Funktion DontQuitApp unterscheidet zwischen Runtime- und Entwicklungsumgebung und bietet im Access-Fall das vollständige Beenden oder das Verbleiben innerhalb von MS-Access an:
Private Function DontQuitApp () As Integer
' **** Beendet die Anwendung oder Access in Access- oder Runtime-Umgebung ****
Beep
If SysCmd(SYSCMD_RUNTIME) Then
Select Case MsgBox("Wollen Sie die Anwendung beenden ?", 33, "Programmende")
Case 1: Application.Quit
Case Else: DontQuitApp = True
End Select
Else
Select Case MsgBox("Wollen Sie die Anwendung komplett beenden oder in Access verbleiben?", 35, "Programmende")
Case 6: Application.Quit
Case 7: DontQuitApp = False
Case Else: DontQuitApp = True
End Select
End If
End Function
Das kann selbstverständlich auch so implementiert werden, daß sich die Anwendung in der Laufzeitumgebung kommentarlos schließt, während in der normalen Accessumgebung ein Fragedialog erscheint.
Diese Lösung beherrscht ALLE Varianten des Schließens wie über Schaltfläche, <Strg+F4>, <Alt+F4> sowie Doppelklicken des Systemmenü-Symboles im Formular und auch im Anwendungsfenster und ist somit anwendersicher !
Selbst wenn Windows beendet wird, obwohl die Access-Anwendung noch geöffnet ist, erscheint nach Bestätigen des Windows-Schließen-Dialoges der Access-Formular-Unload-Dialog. Wird das Schließen der Anwendung verneint, wird auch der Windows-Beenden-Vorgang abgebrochen. Genialer gehts nimmer.
Durch den Wert 33 werden 'OK' und 'Abbrechen' angezeigt; das ist auf den ersten Blick nicht so einleuchtend wie 'Ja' und 'Nein', aber es ermöglicht die komplette Steuerung des Vorganges per <Return> und <Esc>. 1 ist dann der
Rückgabewert für 'OK'. Im erweiterten Fall zeigt 35 'Ja', 'Nein' und 'Abbrechen' an, was immerhin den Rückschritt per <Esc> erlaubt.
Obendrein wird automatisch zwischen Runtime und Access unterschieden. Das Runtime-Modul wird geschlossen, in Access verbleibt man im Datenbankfenster (wenn man will). YES !
* * * *
Unterbinden von <Alt+F4> zum Beenden von Applikation bzw. Access:
Das Beispiel zeigt, wie bei einem gebundenen Formular der Hotkey <Alt+F4>, der u.a. das Ereignis Unload auslöst, durch setzen des Cancel-Parameters unwirksam gemacht werden kann. Ein dafür vorgesehener PushButton kann einen Flag setzen, der das Schließen doch noch erlaubt. Das funktioniert so gut, daß ich beim Probieren mehrfach per Windows-Applikations-Warmstart Access schließen mußte, das es aus dem Formular kein Entrinnen gab. Geil !
Sub Form_Unload (Cancel As Integer)
On Error GoTo err_Form_Vollbild_Unload
' Beenden über wird durch Cancel=true abgefangen.
' Damit es per pb noch geht, wird ein Flag Ende benutzt.
If Ende = False Then Cancel = True
If Cancel = True Then
' Der Bezug auf Screen.ActiveControl.Name erzeugt einen
' gewollten Fehler, der so extra behandelt werden kann.
x% = IsNull(Screen.ActiveControl.Name)
End If
Exit Sub
err_Form_Vollbild_Unload:
If Err = 2474 Then
' fokussiere das erste Steuerelement in der Auflistung
Me(0).SetFocus
Else
Fehler "Form Vollbild Unload"
End If
Resume Next
End Sub
allgemein
Quelle: dmt
Datum: 03.2004
Unter OA3 standen nach dem Ausführen einer Abfrage die Eigenschaften 'Anzahl der Daten-sätze' und 'Datensatznummer' sofort zur Verfügung. In Access kann das nur im Nachhinein mit Hilfe peinlicher Move-ereien ermittelt werden. Vereinzelt kam es aber bereits vor, daß die Anzahl der Recordset-Datensätze nach Evaluierung bekannt war.
Versucht man aber innerhalb eines Berichtes davon Gebrauch zu machen, muß man feststellen, daß das hier nicht möglich ist. Dafür werden andere (faule) Lösungen angeboten:
Der Ausdruck =Anzahl([BNr]) & " von " & DomAnzahl("BNr";"Ventile") & " Ventildatensätzen"
ermittelt innerhalb eines Berichtes in der Eigenschaft Steuerelementinhalt eines Textfeldes die Anzahl der Datensätze des Berichtes, in denen kein NULL-Wert enthalten ist. Stark !
Und da wir gerade bei Berichten sind: Es ist nicht nur möglich, die Nummer der aktuellen Seite anzeigen zulassen, nein, sogar die Gesamtzahl der benötigten Seiten kann bereits auf der ersten Seite vermerkt werden !
Das ist wirklich eine Leistung !
Und das geht so:
Eigenschaft Steuerelementinhalt eines Textfeldes: ="Blatt " & [Seite] & " von " & [Seiten]
Wenn innerhalb des Modul-Programmier-Fensters in der Element-Auswahlliste ein bisher noch nicht mit Code versehenes Element gewählt wird, wird in der Regel eine Sub 'Element_BeforeUpdate' o.ä. geöffnet. Wählt man in der Ereignis-Auswahlliste ein anderes Ereignis, bleibt die leere, eingangs erzeugte Sub-Routine bestehen ! Im Gegensatz hierzu ist Visual Basic ist immerhin so intelligent, leere Routinen beim Speichern zu entfernen.
Aber das ist erst der Anfang einer langen, nicht enden wollenden Geschichte ...
Auflösung
Quelle: dmt
Datum: 03.2004
Tja, und dann hätten wir da auch noch die Überprüfung der Auflösung z.B. beim Programmstart, um den Anwender evtl. darauf hinzuweisen, daß er zur Zeit nicht die für diese Anwendung vorgesehene Auflösung eingestellt hat.
Private Sub Check_Resolution ()
On Error GoTo err_Check_Resolution
' **** Ist die aktuelle Auflösung 800*600 ? ****
Dim CR As String, s As String
Dim x As Integer, Y As Integer
GetResolution x, Y
If x = 800 And Y = 600 Then
' Gratulation, die optimale Auflösung ist eingestellt
Else
Beep
CR = Chr$(13) & Chr$(10)
s = "Diese Anwendung wurde für die Bildschirm-Auflösung 800*600 optimiert."
s = s & CR & CR & "Sie können mit dieser Anwendung auch in anderen Auflösungen arbeiten."
s = s & CR & CR & "Bei höheren Auflösungen werden die angezeigten Informationen "
s = s & "kleiner dargestellt und bei einer geringeren Auflösung können Sie z. Bsp. "
s = s & "die Felder des Kennlinien-Formulares nicht alle mit einem Blick erfassen."
MsgBox s, 64, "Check_Resolution"
End If
Exit Sub
err_Check_Resolution:
Fehler "Check_Resolution"
Exit Sub
End Sub
Ausdrücke
Quelle: dmt
Datum: 03.2004
BEZEICHNER IN AUSDRÜCKEN:
Im HP/VHP-Manager ergab es sich, daß ein Extra-Sortierfeld (Integer) eingeführt wurde, um bei großen Datenmengen eine schnelle Sortierung zu gewährleisten.
Leider mußte später festgestellt werden, daß in der Tabelle bei den meisten Datensätzen kein Wert zugewiesen wurde. Eine Laufzeit-Überprüfung mit '? Forms!Ventile_HRV1!Art_Sort' nennt den jeweiligen Wert. Eine Zuweisung im Code per 'Art_Sort = DLookup(...)' landet jedoch im Variablen-Nirwana. Der Ausdruck 'Forms!Ventile_HRV1!Art_Sort' müßte laut Definition auf ein Steuerelement 'Art_Sort' im genannten Formular verweisen, daß dort aber gar nicht enthalten
ist ! Wenn Access auf diese Anweisung trifft, erkennt es anscheinend automatisch, daß es sich hierbei nicht um ein Steuerelement, sondern um ein im Recordset ( SELECT * ) enthaltenes Feld handelt.
Wenn die Anweisung
Art_Sort = DLookup("Nr", "Ventile_Arten", "Titel = '" & s$ & "'")
durch
Forms(Me.Name).Art_Sort = DLookup("Nr", "Ventile_Arten", "Titel = '" & s$ & "'")
ersetzt wird, wird dem im Recordset des Formulares enthaltenen Feld 'Art_Sort' der richtige Wert zugewiesen.
Das ganze klappt auch mit den Bezeichnungsausdrücken 'Me.Art_Sort' sowie 'Me!Art_Sort', obwohl 'Art_Sort' weder ein Steuerelement noch eine Eigenschaft des Formulares ist.
Verstehe das, wer will. Am besten nix glauben und ALLES nachprüfen !
* * * *
In den meisten Fällen sind Ausdrücke im deutschsprachigen Eigenschaften-Fenster nur dann zu gebrauchen, wenn sie einfache Zusammenhänge enthalten. Dann funktioniert die Sache auch gut und schnell, da Access Steuerelement-eigenen
Eigenschaften auf eine nicht näher dokumentierte Art bevorzugt abzuarbeiten scheint.
Als Programmierer wird man jedoch meistens lieber einer Funktion schreiben, in der ausführlich auf Fallunterscheidungen etc. eingegangen werden kann.
Fairerweise muß zugunsten der Ausdrücke gesagt werden, daß u.U. auftretende Null-Werte und ähnliche Sauereien in Bezeichnern in Ausdrücken kommentarlos verdaut werden und somit manchmal einfacher gearbeitet werden kann, als mit
endlosen 'IF ISNULL(x) THEN' in selbstgeschrieben Routinen. Das deutet übrigens darauf hin, das Access die Inhalte von Steuerelementen quasi Variant-mäßig behandelt. Das macht zwar nur wenig Ärger, ist aber tempomäßig nicht das Gelbe
vom Ei.
Das folgende Beispiel ließ sich sogar NUR mit Hilfe eines Ausdruckes realisieren:
In dem i.d.R. ausgeblendetem Unterformular 'Leistungsrapport' des Formulares 'Termine' gibt es ein berechnetes Steuerelement "Dauer_brutto", das die Dauer einer Leistung, die durch die gebundenen Felder 'von' und 'bis' gegeben ist,
berechnen soll. Weil ein Termin manchmal über Mitternacht hinaus geht, kommt es wie seinerzeit bei AOS vor, das 'bis' kleiner ist als 'von'. Mit einer kleinen Routine ist das schnell erledigt, jedoch erzeugte die Zeile, in der dem
Steuerelement der korrekte Wert zugewiesen wurde, jedesmal einen Fehler ('Wert kann nicht zugewiesen werden'), obwohl (oder gerade weil ?) das Unterfomular noch nicht einmal sichtbar war. Erst als die relative einfache Bedingung in Form
eines Ausdruckes '=Wenn([bis]<[von];1-([bis]-[von]);[bis]-[von])'
a'la Excel gesetzt wurde, klappt die Sache.
* * * *
AUSWERTEN VARIABLER WERTE in BEZEICHNER FÜR AUSDRÜCKE:
Access offenbart in seiner Hilfe zu 'Bezeichner in Ausdrücken', daß explizite Verweise a'la 'FORMS!QV!BNr.xyz' auch veränderliche Elemente enthalten kann, wenn Sie mit dem Zeichen '|' eingeschlossen sind, auswertet werden, bevor der
gesamte Ausdruck verarbeitet wird.
Das klappt, wenn überhaupt, aber nur innerhalb der pseudodeutschen Syntax im Makroentwurf oder Formulareigenschaften.
Meine Experimentierfreudigkeit ( oft Rettungsanker ) wurde mit einem schnellen Treffer belohnt. In Access-Basic sieht das dann so aus:
For c% = 0 To RSQ.Fields.Count - 1
ZF(RSQ(c%).Name) = RSQ(c%)
Next c%
Hier werden den Steuerelementen des Zielformulars ZF, deren Namen gleich denen der zugeordneten Tabellenfelder sind, der Reihe nach die Feldinhalte des QuellRecordSets RSQ übergeben.
In Open Access konnte so etwas mit einem Griff ins Handbuch und 1 ! Zeile Code gelöst werden (Record-Anweisung).
Nachzulesen in HP/VHP.MDB, Modul 'Ventile', Sub 'Copy_Valve_Data'.
Dateien, Klein- und Großschreibung
Quelle: dmt
Datum: 03.2005
Wenn Access 2.0 mittels Visual Basic als 16Bit-Software eine neue Datei anlegt, wird die Datei so im Dateisystem gespeichert, daß alle Buchstaben des Dateinamens als Großbuchstaben geschrieben werden.
Im reinen Windows-Betrieb ist das eher ein kosmetisches Problem, daß beim Betrachten der Verzeichnisinhalte im Windows Explorer (ich glaube, je nach Windows-Version nicht immer ganz einheitlich) auftritt.
Spaßfrei wird es aber, wenn z.B. in einem Content-Management-System solche Dateien mit entsprechenden Verlinkungen auf einem Webserver landen. Der läuft (wie es sich gehört) zu fast 100% unter einem UNIX-ähnlichen System und dort wird eben knallhart zwischen Großschreibung und Kleinschreibung unterschieden.
Was ist zu tun, wenn man nicht jedesmal die Schreibweise der betroffenen Dateien manuell korrigieren möchte ?
Wenn die Seiten, in denen verweisende Hyperlinks stehen, auch in der 16-Bit-Anwendung erzeugt werden, reicht es aus, die Verweise auf solche zwangs-groß geschriebenen Dateinamen eben z.B: per UCase() ebenfalls in Großschreibung anzulegen.
Interessanterweise tritt das Phänomen nicht auf, wenn eine Datei mit kleingeschriebenem Namen bereits existiert und durch die 16Bit-Anwendung neu geschrieben wird. So habe ich die Datei, die die manuell navigierbare Übersicht der infobase enthält (ibnavi.htm), in Kleinbuchstaben unter meinem NT4 auf einem Fat16-Laufwerk angelegt. Entsprechend landet sie auch beim ftp-Transfer auf dem Webspace, wo die entsprechenden Links mit korrekter Kleinschreibung darauf verweisen. Diese Datei wird aber bei jedem Export aus Access 2.0 heraus neu geschrieben, wobei die Schreibweise des Dateinamens unverändert bleibt.
Falls die Situation vertrackter sein sollte, würde ich versuchen, mittels irgendeines Freeware-Tools, daß (am besten Kommandozeilen-gesteuert) z.B. alle Dateien in bestimmten Verzeichnissen einheitlich kleinschreibt. Eine Google-Recherche sollte helfen.
Datenbank, Bibliothek
Quelle: dmt
Datum: 03.2004
Die Sache mit BIBLIOTHEKs-Datenbanken / MDA-Dateien
ist sehr interessant und, wie nicht anders zu erwarten, nicht ohne Stolperfallen:
Wichtig zu wissen ist, daß die Anweisung 'Set DB=DBEngine.Workspaces(0).Databases(0)', in einer Bibliotheksdatenbank
ausgeführt NICHT auf die Bibliotheksdatenbank selbst verweist, sondern auf die Datenbank, die eigentlich geladen wurde. Siehe den Fall LaserJob, indem zuerst viel Verwirrung gestiftet wurde, als diese Anweisung in der mda-Datei nicht das
gewünschte Ergebnis erbrachte und statt dessen auf die mdb-Datei verwies, die selbst KEINEN Code enthält. In solchen Fällen muß die 'aktuelle' Bibliotheksdatenbank, in der der Code abgearbeitet wird, mit 'Set DB=CodeDB()' bestimmt werden.
Sind in dieser mda-Datei alle für die Anwendung relevanten Funktionen enthalten, das heißt, auch Tools a'la 'DataBase_Dir()', dann muß Sorge dafür getragen werden, daß in keiner Datenbank, die in dieser Sitzung unter dem aktiven
Access-Modul geladen wird, Code mit gleichlautenden Routinen-Namen enthalten ist. Das ist zwar nervig, wenn man eine Fehlermeldung nach der anderen enthält, hat aber immerhin zu einer abgespeckten transact.mdb geführt, die selbst kaum
noch Code enthält.
Nachdem zu diesem Thema Klarheit geschaffen wurde, mußten erneute Indifferenzen festgestellt werden:
Eine Abfrage der Makrodaten enthaltenden MSysmacros innerhalb einer Bibliotheksdatenbank fragt natürlich die bereits in der Bibliotheksdatenbank enthaltene Tabelle MSysmacros ab. Eine Dummy-Abfrage "FROM Adressen" findet aber zur Laufzeit sehr wohl und ganz ohne eingebundene Tabellen die Daten der Databases(0)-Datenbank, von der aus eine Bibliotheksfunktion aufgerufen wurde.
Wie einer Bibliotheks-internen Abfrage so etwas beigebracht werden sollte, kann ich mir z.Zt. nicht vorstellen, aber im Beispiel des DB_Info-Formulares in Lib_dmt.mda konnte alles über Code abgecheckt werden.
Datenbank, externe
Quelle: dmt
Datum: 05.2006
EXTERNE DATENBANK:
Viele der Klimmzüge, die per SQL-Abfragen und Code Daten beherrschbar machen, lassen sich auch mit Daten, die in Tabellen externer Datenbanken stehen, durchführen.
Das Beispiel einer Aktualisierungsabfrage zeigt, wie einfach das geht:
UPDATE AD IN "g:\public\ad20\adback.mdb" SET Briefanrede="Mister" WHERE Briefanrede="Mr";
Entsprechend läuft das auch mit SELECT * FROM Adressen IN '...'
.
Auch die Probleme mit den leidigen Domänen in den Domänen-Aggregat-Funktionen kann teilweise mit solchen Tricks behoben werden:
SELECT Max(Briefanrede) AS Maximum FROM AD IN "g:\public\ad20\adback.mdb";
liefert z.B. einen Datensatz mit einem Feld. Das kann aber genausogut auch als 'ein Wert' aufgefasst werden, der mit einer Anweisung a'la 'x=DMax("Briefanrede","AD")' partout nicht zu ermitteln ist, da 'AD' immer nur als internes Objekt aufgefasst wird.
Mit ein bißchen Quelltext läßt sich das Ergebnis aber auch per SQL ermitteln (ich liebe es immer mehr):
If Err = 3078 Then
Get_MinValue = Get_AggregatValue_per_SQL("Min(" & FN & ")", DB.Name, TN)
fängt in einem Errorhandler das Mißlingen einer Domänen-Aggregat-Funktion auf, und versucht das Ergebnis von einer SQL-basierenden Funktion zu erhalten, an die die gewünschte Funktion als vollständiger String sowie die Namen von Datenbank,
Tabelle und Feld übergeben werden.
Private Function Get_AggregatValue_per_SQL (vFunktion As Variant, vDBName As Variant, vTName As Variant)
On Error GoTo err_Get_AggregatValue_per_SQL
Dim MyDB As Database, RS As Recordset
Set MyDB = DBEngine.Workspaces(0).Databases(0)
Set RS = MyDB.OpenRecordset("SELECT " & vFunktion & "(" & vFName & ") AS Wert FROM " & vTName & " IN '" & vDBName & "';")
Get_AggregatValue_per_SQL = RS("Wert")
RS.Close
MyDB.Close
Exit Function
err_Get_AggregatValue_per_SQL:
Fehler "Get_AggregatValue_per_SQL"
Exit Function
End Function
Da hier alles variabel zusammengebaut wird, ist das Ding ziemlich potent; mehr als einen ungültigen Funktions-String zu übergeben, kann eigentlich nicht passieren.
* * * *
IMPORTIEREN / EXPORTIEREN / TRANSFERTEXT / TRANSFERDATABASE / SPEZIFIKATIONEN:
Für den Austausch mit externen Daten / Informationen, die nicht gerade in einem geeignetem Standard-Applikationsformat vorliegen, ist oftmals ein TransferText flexibler als ein TransferDatabase.
Es können eigene Exportformate (-spezifikationen) definiert werden, wenn der Menüdialog Import/Export-Einstellungen oder aber Datei / Exportieren / Text (festgelegtes Format) bemüht wird. Diese Spezifikationen werden in der Tabelle
MSysIMEXSpecs hinterlegt, die dazugehörenden, feldbezogenen Informationen in MSysIMEXColumns. Dort können auch von Hand getürkte Sachen hinterlegt werden, aber so richtig glücklich bin ich damit trotzdem nicht geworden. So werden bei
EXPORTIEREN Daten über eine definierte Länge mit Blanks oder bei AUSGABE IN mit Pseudo-Ascii-Strichen aufgefüllt oder unterteilt, was eine Datei, die mit (unnötigen) Word-Steuerdatei-Zeichen wie ';' und '"' 80 kB groß ist, zu 240 kB
anschwellen läßt. Ein Code-mäßiges TransferText erzeugt erstmal eine 80 kB große, Word-kompatible Datei. EXPORTFIXED erzeugt die Dateien in festen Breiten, siehe oben. Für EXPORTDELIM muß keine Spezifikation angegeben, kann aber angegeben werden. Da können dann wunschgemäße Dinge eingestellt werden, das Feld-Trennzeichen kann aber leider nur 1 Zeichen lang sein. Der Versuch, mehrere Zeichen einzugeben, scheitert: es wird nur 1 Zeichen ausgelesen.
Datenbank, externe anlegen
Quelle: dmt
Datum: 02.2005
Eine komplette DATENBANK ANLEGEN / INITIALISIEREN:
Sinnvoll, wenn z.B. regelmässig Analyse-Daten erzeugt werden, die von einer Access-Anwendung ausgelesen werden sollen.
Durch das wiederholte Einlesen neuer Daten schwillt die Datenbank, die die Analysedaten-Tabelle enthält, ständig an. Diese Datenbank müßte häufig komprimiert werden.
Eine einfachere Lösung besteht darin, in der Anwendungs-Datenbank eine Vorlage der Tabelle zu halten und mittels einer kleinen Routine im Anwendungsverzeichnis eine neue Datenbank anzulegen, in die die leere Tabellen-Vorlage hinein exportiert wird. Der Zugriff auf diese "externen" Daten erfolgt über eine eingebundene Tabelle. Solange die Anwendung nicht portiert wird, behält sogar der explizite Quellen-Verweis (z.B. "c:\anwendung") seine Gültigkeit und steht selbst nach Löschen und Neuanlegen der Arbeits-Datenbank im vollen funktionalen Saft.
Das folgende Beispiel (Access 97) bewältigt periphere Probleme mit z.B. einer bereits vorhandenen Arbeits-Datenbank sowie der Datenquelle eines Unterformulares, das zur Laufzeit geöffnet ist und auf eben diese Daten zugreift.
Die Datenquelle dieses Unterformulares wird in einer Variablen "gesichert", zurück- und am Ende der Routine wieder auf ihren ursprünglichen Wert gesetzt.
Function InitAnalData() As Boolean
On Error GoTo err_InitAnalData
' Um ein ewiges Aufblasen der Datenbank zu vermeiden (wiederholtes Löschen und Füllen der Tabelle
' tag_anal mit div. Memofeldern) wird die ganze Scheiße in einer dynamisch angelegten Datenbank
' abgewickelt.
Dim WS As Workspace, AnalDB As Database, sNewDB As String, sRecordSource As String
Set WS = DBEngine.Workspaces(0)
Meldung "Initialisierung ..."
sNewDB = Database_Dir() & "\" & "webanal.mdb"
sRecordSource = Me!UF_tag_anal.Form.RecordSource
Me!UF_tag_anal.Form.RecordSource = ""
Kill sNewDB ' bestehende Datenbank löschen
Set AnalDB = WS.CreateDatabase(sNewDB, dbLangGeneral) ' neue Datenbank anlegen
' Vorlagen-Tabelle für tag-Analyse-Daten exportieren
DoCmd.TransferDatabase acExport, "Microsoft Access", sNewDB, acTable, "tag_anal_default", "tag_anal", True, False
Me!UF_tag_anal.Form.RecordSource = sRecordSource
InitAnalData = True
exit_InitAnalData:
Set AnalDB = Nothing
Set WS = Nothing
Meldung ""
Exit Function
err_InitAnalData:
If Err = 53 Then
Resume Next
Else
Fehler "InitAnalData"
Resume exit_InitAnalData
End If
End Function
Datenbank, externe, BETRIEVE
Quelle: dmt
Datum: 03.2004
Novell-BETRIEVE-Tabellen können laut Doku mit MS-Access angefasst werden.
Die Hilfe dazu ist je nach Stichwortwahl sogar umfangreich; trotzdem brauchte es 2 (ZWEI!) Jahre, bis die mittlerweile Btrieve 6.x-Adressen-Daten der strobelschen Kuhnle-Schreiner-Anwendung eingelesen werden konnten.
Es hing an sehr vielem:
win.ini:
[btrieve]
Options=/u:2 /m:64 /p:4096 /b:16 /f:20 /l:40 /n:12
/t:e:\windows\system\BTRIEVE.TRN
msacc20.ini:
[Installable ISAMs]
Btrieve=E:\WINDOWS\SYSTEM\btrv200.dll
[Btrieve]
Filter=Btrieve (file.ddf)|file.ddf|
Extension=ddf
OneTablePerFile=No
IndexDialog=No
CreateDbOnExport=Yes
[Btrieve ISAM]
DataCodePage=OEM
Obendrein klappt's erst dann so einigermaßen, wenn die Dateien in meinem e:\access\btrieve-Verzeichnis auch alle im Windows-System-Verzeichnis stehen, unabhängig davon, welche Inis irgendwelche Pfadangaben auf Dateien enthalten.
Und dann müssen unglücklicherweise die btrieve-Beschreibungsdateien file.ddf UND fields.ddf herhalten. Speziell fields.ddf war im Hause Strobel nicht auffindbar (wird von der btrieve-Anwendung nicht benötigt), sondern wird laut Doku von speziellen Dienstprogrammen wie xtrieve erzeugt und konnte seinerzeit vom Anwendungs-hersteller direkt bezogen werden.
Das hat dann, nach dem beim x-ten Versuch neue Fehlermeldungen neue Maßnahmen anregten, auch zum Erfolg geführt.
Datenbank, reparieren
Quelle: access-home
Datum: 05.2005
Im schlimmsten Falle muß evtl. ein professioneller Datenretter bemüht werden.
Hilfe sowie Tipps zur Selbsthilfe bei Datenbankproblemen gibt's bei www.access-rettung.de.
Von www.access-home.de kommen folgende Hinweise:
Restaurierung defekter Datenbanken:
Gerade bei Datenbanken die beim Starten Fehler melden oder gar nicht mehr anlaufen, können folgende Schritte helfen.
- Sicherungskopie der Datenbank anlegen
- Die Datenbank reparieren
- Die Datenbank komprimieren
- Neue Datenbank anlegen und die alte Datenbank importieren
Durch diese Vorgehensweise werden nur die Objekte der Datenbank kopiert, die auch tatsächlich ausgewählt wurden. Interne, bereits gelöschte oder fehlerhafte Objekte werden nicht übernommen.
Durch diese Prozedur ist es auch möglich, einzelne defekte Objekte der Datenbank zu lokalisieren und ggf. durch eine Kopie aus einem Backup zu ersetzen.
Eine weitere Rettungsmöglichkeit ist das Konvertieren der Datenbank in vorherige oder neue Accessversion.
Weitere Informationen bei Microsoft: ACC2000: Wie Sie eine beschädigte Datenbank reparieren können (als Link natürlich nicht mehr vorhanden).
Datenbankobjekte listen
Quelle: dmt
Datum: 03.2004
Das folgende Beispiel nimmt einen Parameter a'la "Abfrage_*" entgegen und gibt für diesen Fall die Namen aller Abfragen zurück, die mit der Zeichenkette "Abfrage_" anfangen, um sie dem Anwender z.B. in einem gesonderten Kombinationsfeld zur Verfügung zu stellen. Der RowSource-String enthält die gerippten Namen und danach die Klartextnamen. Wird das Kombifeld auf 2-spaltig (mit Breite 2.Spalte=0cm) eingestellt, so sieht der Anwender nur die geschönten Namen, während die Applikation die verborgenen Klartextbegriffe auswerten kann.
Allgemein kann diese Routine auch benutzt werden für:
DATENBANKOBJEKTE AUFLISTEN:
Function List_Abfragen (sName As String) As String
On Error GoTo err_List_Abfragen
' **** Füllt die Werte-Liste des übergebenen Kombifeldes ****
' **** mit den Namen der Abfragen der angegebenen Art ****
' angezeigt werden die Zeichenketten nach sName, eine zweite
' Spalte enthält den vollständigen String, der bequem als
' Datenquelle eingestellt werden kann.
Dim DB As Database, i As Integer, s As String, v As Variant
v = SysCmd(SYSCMD_SETSTATUS, "lese Abfragenamen ein ...")
Set DB = DBEngine.Workspaces(0).Databases(0)
For i = 0 To DB.QueryDefs.COUNT - 1
If DB.QueryDefs(i).Name Like sName Then
s = s & Mid$(DB.QueryDefs(i).Name, Len(sName)) & ";" &
DB.QueryDefs(i).Name & ";"
End If
Next i
s = Left$(s, Len(s) - 1)
List_Abfragen = s
v = SysCmd(SYSCMD_CLEARSTATUS)
Exit Function
err_List_Abfragen:
v = SysCmd(SYSCMD_CLEARSTATUS)
Fehler "List_Abfragen"
Exit Function
End Function
Der folgende Aufruf
' **** Datenquelle für das Filter-Abfragen-Kombifeld einstellen ****
Me!Filterabfragen.RowSource = "alle Datensätze;'" & strSQLRecordSource &
"';" & List_Abfragen("Abfrage_*")
stellt der zu bildenden Liste sogar einen eigenen String voran.
DDE
Quelle: dmt
Datum: 05.2006
DDE oder der Wahnsinn ist überall:
Zum Thema DDE werden hier per Zufall gefundene Dokus und eigene Routinen zusammengetragen.
ALLGEMEINES zu DDE:
Zusammenarbeit mit Microsoft Word und Microsoft Excel (Häufige Frage)
Frage: Wie arbeitet Microsoft Access bei der Verwendung von OLE, DDE oder ODBC mit Microsoft Word für Windows und Microsoft Excel zusammen?
Verwenden von OLE:
Microsoft Access kann als eine OLE-Container-Anwendung fungieren. Sie können OLE-Objekte in Tabellen speichern oder sie in den Entwurf eines Formulars oder Berichts einbetten bzw. mit diesem verknüpfen. Außerdem unterstützt Microsoft
Access die OLE-Automatisierung. Sie können jedoch Microsoft Access-Objekte nicht in andere OLE-Anwendungen einbetten oder mit diesen verknüpfen.
Verwenden von DDE:
Microsoft Access kann entweder selbst einen DDE-Dialog (als DDE-Client) starten oder (als DDE-Server) auf einen DDE-Client antworten. Als DDE-Client-Anwendung kann Microsoft Access DDE-Verknüpfungen in Abfragen, Formularen und Berichten, jedoch nicht in Tabellen, enthalten. Als DDE-Server-Anwendung unterstützt Microsoft Access die folgenden DDE-Themen:
- Das Thema "System".
- Der Name einer Datenbank, Tabelle oder Abfrage.
- Eine Microsoft Access SQL-Anweisung.
Der Microsoft Access Word-Seriendruckassistent verwendet DDE, um eine DDE-Verknüpfung zwischen Microsoft Access und Word für Windows herzustellen. Sobald die Verknüpfung hergestellt ist, können Sie jederzeit Ihr Dokument in Word für
Windows öffnen und unter Verwendung der aktuellen Daten in Microsoft Access neue Serienbriefe oder Etiketten drucken.
Verwenden von ODBC:
Microsoft Word für Windows, Microsoft Excel und Microsoft Access enthalten ODBC-Treiber, die die Arbeit mit Microsoft Access-Datenbanken ermöglichen. Obwohl Microsoft Access keine ODBC-Treiber für Microsoft Word für Windows oder
Microsoft Excel enthält, können Sie mit diesen Anwendungen zusammenarbeiten, indem Sie aus dem Menü Datei einen der Befehle Importieren, Exportieren oder Ausgabe in wählen.
Sie können Microsoft Excel-Dateien (.XLS) oder Textdateien (.TXT) importieren und exportieren sowie Microsoft Word für Windows-Seriendruckdateien exportieren. Verwenden Sie den Befehl Ausgabe in, um die Ausgabe einer Tabelle, einer
Abfrage, eines Formulars, eines Berichts oder eines Moduls in einer Datei im Microsoft Excel-Format, Textdateiformat oder .RTF-Format zu speichern. Sie können dann eine Datei im Microsoft Excel-Format in Microsoft Excel und Dateien
im Textdateiformat oder .RTF-Format in Microsoft Word für Windows öffnen.
Verwenden von Microsoft Access als DDE-Server:
Microsoft Access unterstützt dynamischen Datenaustausch (DDE) sowohl als Datenziel- (Client) als auch als Quellanwendung (Server). Die folgenden Themen werden von Microsoft Access als DDE-Server unterstützt:
- das Thema "System"
- der Name einer Datenbank (Thema Datenbank)
- der Name einer Tabelle (Thema Tabellenname)
- der Name einer Abfrage (Thema Abfragename)
- eine Microsoft Access SQL-Anweisung (Thema Sqlzeichenfolge)
Jeder DDE-Dialog ist auf ein bestimmtes Thema, gewöhnlich eine Datendatei, aufgebaut und beschränkt sich im weiteren Verlauf auf die Datenelemente, die mit diesem Thema verbunden sind. Wenn Sie zum Beispiel in Microsoft Word für Windows Daten aus einer bestimmten Microsoft Access-Datenbank in Ihr Word für Windows-Dokument einfügen möchten, leiten Sie einen DDE-Dialog mit Microsoft Access ein, indem Sie einen Kanal öffnen und den Namen der Datenbank als Thema angeben. Sie können dann diesen Kanal dazu verwenden, Daten aus der Datenbank abzurufen. Nachdem Sie einmal einen DDE-Dialog eingeleitet haben, können Sie die Anweisung DDEExecute dazu verwenden, einen Befehl von der Client- an die Serveranwendung zu senden. Wenn Microsoft Access als DDE-Server verwendet wird, erkennt es die folgenden Befehle als gültig an:
- Den Namen eines Makros in der gerade geöffneten Datenbank. Jede Aktion, die Sie in Access Basic mit der Anweisung DoCmd ausführen können.
- Die Aktionen OpenDatabase und CloseDatabase, die nur für DDE-Operationen verwendet werden.
(Beispiele zur Anwendung dieser Aktionen finden Sie im nachstehenden Beispiel.)
Anmerkung: Wenn Sie eine Aktion in einem DDEExecute-Befehl angeben, folgen die Aktion und alle Argumente der Syntax von DoCmd und müssen in eckige Klammern ([]) eingeschlossen werden. Anwendungen, die DDE unterstützen, erkennen jedoch
nicht eingebaute Konstanten in DDE-Operationen. Außerdem müssen Zeichenfolgenargumente, deren Zeichenfolge ein Komma enthält, in Anführungszeichen (" ") eingeschlossen sein. Mit Ausnahme dieser Fälle sind Anführungszeichen nicht notwendig.
Das folgende Beispiel zeigt, wie Sie ein Word für Windows WordBasic-Makro erstellen können, das Microsoft Access als DDE-Server verwendet. (Damit dieses Beispiel funktioniert, muß Microsoft Access entweder geöffnet sein oder in der
Umgebungsvariablen path in Ihrer Datei AUTOEXEC.BAT aufgeführt werden.)
Sub MAIN
' Öffnen von NWIND.MDB unter Verwendung des Themas "System".
' Die Datenbank muß geöffnet sein, bevor andere DDE-Themen verwendet werden
können.
Kanal1 = DDEInitiate("MSAccess", "System")
DDEExecute Kanal1, "[OpenDatabase C:\ACCESS\BEISPIEL\NWIND.MDB]"
' Abrufen aller Daten aus der Abfrage "Kundenliste".
Kanal2 = DDEInitiate("MSAccess", "NWIND;QUERY Kundenliste")
MeineDaten$ = DDERequest$(Kanal2, "All")
DDETerminate Kanal2
' Schließen der Datenbank.
DDEExecute Kanal1, "[CloseDatabase]"
DDETerminate Kanal1
' Einfügen der Daten in eine Textdatei.
Open "DATEN.TXT" For Append As #1
Print #1, MeineDaten$
Close #1
End Sub
Informationen über die Verwendung von Microsoft Access als DDE-Client finden Sie im Kapitel 19, "Verwenden von Bildern, Diagrammen und anderen Objekten" des Microsoft Access Benutzerhandbuchs oder im Kapitel 13, "Dynamischer Datenaustausch", des Handbuchs Erstellen von Anwendungsprogrammen.
Das Thema "System":
Das Thema "System" ist ein Standardthema für alle auf Microsoft Windows basierenden Anwendungen.
Es liefert Informationen zu den von der Anwendung unterstützten Themen. Das Thema "System" unterstützt die folgenden Microsoft Access-Datenelemente:
Element liefert
SysItems Eine Liste von Elementen, die vom Thema "System" in Microsoft Access unterstützt werden.
Formats Eine Liste von Formaten, die Microsoft Access in die Zwischenablage kopieren kann.
Status "Busy" oder "Ready".
Topics Eine Liste aller geöffneten Datenbanken.
Beispiel:
' Einleiten eines DDE-Dialogs mit Microsoft Access in einem WordBasic-Makro.
Kanal1 = DDEInitiate("MSAccess", "System")
' Anfordern einer Liste der vom Thema "System" unterstützten Themen.
Ergebnis$ = DDERequest$(Kanal1, "SysItems")
' Durchführen der Aktion Open Database zum Öffnen von NWIND.MDB.
DDEExecute Kanal1, "[OpenDatabase C:\ACCESS\BEISPIEL\NWIND.MDB]"
Das Thema Datenbank:
Das Thema Datenbank ist der Dateiname einer vorhandenen Datenbank. Sie können entweder einfach den Namen der Datenbank (NWIND) oder den vollständigen Pfad mit der Erweiterung .MDB (C:\ACCESS\BEISPIEL\NWIND.MDB) eingeben. Nachdem Sie den
DDE-Dialog mit der Datenbank eingeleitet haben, können Sie eine Liste aller Objekte in der Datenbank anfordern.
Anmerkung: Sie können DDE nicht zum Abfragen der Systemdatenbank (SYSTEM.MDA) verwenden.
Das Thema Datenbank unterstützt die folgenden Datenelemente:
Element liefert
TableList Eine Liste der Tabellen
QueryList Eine Liste der Abfragen
FormList Eine Liste der Formulare
ReportList Eine Liste der Berichte
MacroList Eine Liste der Makros
ModuleList Eine Liste der Module
Beispiel:
' Einleiten eines DDE-Dialogs mit NWIND.MDB in einem WordBasic-Makro.
' Die Datenbank muß geöffnet sein.
Kanal2 = DDEInitiate("MSAccess", "Nwind")
' Anfordern einer Liste von Formularen in NWIND.MDB.
Ergebnis$ = DDERequest$(Kanal2, "FormList")
' Durchführen der Aktion OpenForm einschließlich seiner Argumente zum Öffnen des
Formulars "Personal".
DDEExecute Kanal2, "[OpenForm Personal,0,,,1,0]"
Die Themen TABLE Tabellenname, QUERY Abfragename und SQL Sqlzeichenfolge:
Diese Themen verwenden die folgende Syntax:
Datenbankname; TABLE Tabellenname
Datenbankname; QUERY Abfragename
Datenbankname; SQL [Sqlzeichenfolge]
Argument Beschreibung
Datenbankname Der Name der Datenbank, in der sich die Tabelle oder Abfrage befindet oder auf die das SQL-Argument zutrifft, gefolgt von einem Semikolon (;). Der Datenbankname kann entweder nur der Name der Datenbank (NWIND) oder auch der vollständige Pfad einschließlich der Erweiterung .MDB (C:\ACCESS\BEISPIEL\NWIND.MDB) sein.
Tabellenname Der Name einer vorhandenen Tabelle.
Abfragename Der Name einer vorhandenen Abfrage.
Sqlzeichenfolge Eine gültige SQL-Anweisung, nicht länger als 255 Zeichen und mit einem Semikolon am Ende. Wenn Sie mehr als 255 Zeichen austauschen möchten, lassen Sie dieses Argument aus, und verwenden Sie statt dessen eine Reihe von
DDEPoke-Anweisungen, um eine DDE-Anweisung zu erstellen.
Der folgende WordBasic-Code verwendet z.B. DDEPoke, um eine SQL-Anweisung zu erstellen und dann das Resultat einer Abfrage anzufordern:
Kanal1 = DDEInitiate("MSAccess", "NWIND;SQL")
DDEPoke Kanal1, "SQLText", "SELECT *"
DDEPoke Kanal1, "SQLText", " FROM Bestellungen"
DDEPoke Kanal1, "SQLText", " WHERE [Frachtkosten] > 100;"
Res$ = DDERequest$(Kanal1, "NextRow")
DDETerminate Kanal1
Die folgende Tabelle listet die gültigen Elemente der Themen TABLE Tabellenname, QUERY Abfragename und SQL Sqlzeichenfolge auf:
Element liefert
All Alle Daten in der Tabelle, einschließlich Feldnamen.
Data Alle Daten in der Tabelle, ohne Feldnamen.
FieldNames Eine einzeilige Liste der Feldnamen.
FieldNames;T Eine zweizeilige Liste von Feldnamen (erste Zeile) und deren Datentypen (zweite Zeile).
Es folgen die gelieferten gültigen Werte und die Datentypen, für die sie stehen:
0 Ungültig
1 Wahr/Falsch (nicht-Null)
2 Byte ohne Vorzeichen (Byte)
3 2-Byte-Ganzzahl mit Vorzeichen (Integer)
4 4-Byte-Ganzzahl mit Vorzeichen (Long)
5 8-Byte-Ganzzahl mit Vorzeichen (Currency)
6 4-Byte Gleitkomma einfacher Genauigkeit (Single)
7 8-Byte Gleitkomma doppelter Genauigkeit (Double)
8 Datum/Zeit (Datum als Ganzzahl, Zeit als Dezimalwert)
9 Binäre Daten, maximal 255 Bytes
10 ANSI-Text, Groß-und Kleinschreibung nicht beachtet, maximal 255 Bytes (Text)
11 Long binary (OLE-Objekt)
12 Long text (Memo)
NextRow Die Daten in der nächsten Zeile der Tabelle oder Abfrage. Beim Öffnen eines Kanals liefert NextRow die Daten in der ersten Zeile. Ist die aktuelle Zeile die letzte Zeile und Sie führen NextRow aus, so schlägt die Anfrage fehl.
PrevRow Die Daten der vorhergehenden Zeile der Tabelle oder Abfrage. Wenn PrevRow als erste Anfrage auf einem neuen Kanal angegeben wird, werden die Daten der letzten Zeile der Tabelle oder Abfrage geliefert. Wenn die erste Zeile die
aktuelle Zeile ist, so schlägt die Anfrage fehl.
FirstRow Die Daten in der ersten Zeile einer Tabelle oder Abfrage.
LastRow Die Daten in der letzten Zeile einer Tabelle oder Abfrage.
FieldCount Die Anzahl der Felder in einer Tabelle oder Abfrage.
SQLText Eine SQL-Anweisung, die für die Tabelle oder Abfrage steht. Für Tabellen gibt dieses Element eine SQL-Anweisung im Formular "SELECT * FROM Tabelle;" zurück.
SQLText;n Eine SQL-Anweisung in Abschnitten von n Zeichen, die für die Tabelle oder Abfrage steht, wobei n eine Ganzzahl bis 255 sein kann. Angenommen, für eine Abfrage steht beispielsweise die folgende SQL-Anweisung:
SELECT * FROM Kunden;"
Das Element "SQLText;7" gibt die folgenden, mit Tabulatoren getrennten Abschnitte zurück:
"SELECT "
"* FROM "
"Kunden;"
Beispiel:
Sub MAIN
' Abrufen von Daten mit einem WordBasic-Makro aus der Tabelle
' "Kategorien", der Abfrage "Katalog" und der Tabelle
' "Bestellungen" in NWIND.MDB.
' Die Datenbank muß geöffnet sein.
Kanal1 = DDEInitiate("MSAccess", "NWIND;TABLE Kategorien")
Kanal2 = DDEInitiate("MSAccess", "NWIND;QUERY Katalog")
Kanal3 = DDEInitiate("MSAccess", "NWIND;SQL SELECT * FROM Bestellungen")
Ergebnis1$ = DDERequest$(Kanal1, "All")
Ergebnis2$ = DDERequest$(Kanal2, "FieldNames;T")
Ergebnis3$ = DDERequest$(Kanal3, "FieldNames;T")
DDETerminate Kanal1
DDETerminate Kanal2
DDETerminate Kanal3
' Einfügen der Daten in eine Textdatei.
Open "DATEN.TXT" For Append As #1
Print #1, Ergebnis1$
Print #1, Ergebnis2$
Print #1, Ergebnis3$
Close #1
End Sub
DDE: Beispiele
Quelle: microsoft
Datum: 05.2006
DDE-Beispiele für die Zusammenarbeit (?) mit anderen Anwendungen:
EXCEL
DDEExecute
Beispiel
DDEExecute Kanalnummer, Befehl$
Sendet einen Befehl oder eine Reihe von Befehlen an eine Anwendung über einen DDE-Kanal (DDE = Dynamik Data Exchange/Dynamischer Datenaustausch).
Argument Erklärung
Kanalnummer Die Nummer des Kanals für den DDE-Dialog, die von der Funktion DDEInitiate() beim Öffnen des Kanals als Ergebnis geliefert wird. Entspricht die Kanalnummer keinem offenen Kanal, tritt ein Fehler auf.
Befehl$ Ein Befehl oder eine Reihe von Befehlen, die von der Server-Anwendung erkannt werden. Sie können auch das unter SendKeys beschriebene Format verwenden, um Tastenfolgen zu senden. Wenn die Server-Anwendung den angegebenen
Befehl nicht ausführen kann, tritt ein Fehler auf.
In Microsoft Excel und vielen anderen Anwendungen, die DDE unterstützen, sollte Befehl$ aus einer oder mehreren Anweisungen oder Funktionen der Makrosprache der Anwendung bestehen. In Microsoft Excel z.B. lautet die Makroanweisung zum Erstellen einer neuen Tabelle NEW(1). Um diesen Befehl über einen DDE-Kanal zu senden, verwenden Sie folgende Anweisung:
DDEExecute Kanal, "[NEW(1)]"
Beachten Sie, daß einige Anwendungen, darunter Microsoft Excel, voraussetzen, daß jeder über einen DDE-Kanal gesendete Befehl in eckigen Klammern steht. Mit einer einzigen DDEExecute-Anweisung können Sie auch mehrere Befehle senden.
Durch folgende Anweisung wird Microsoft Excel beispielsweise angewiesen, eine Tabelle zu öffnen und wieder zu schließen:
DDEExecute Kanal, "[NEW(1)][FILE.CLOSE(0)]"
Beachten Sie, daß sich zwischen den in eckigen Klammern stehenden Befehlen keine Leerstelle befindet. Eine Leerstelle würde einen Fehler hervorrufen. Die obige Anweisung ist gleichbedeutend mit den beiden folgenden Anweisungen:
DDEExecute Kanal, "[NEW(1)]"
DDEExecute Kanal, "[FILE.CLOSE(0)]"
Viele Beispiele erfordern Argumente in Form von Zeichenfolgen, die in Anführungszeichen stehen müssen. Da Anführungszeichen jedoch in WordBasic den Anfang und das Ende von Zeichenfolgen kennzeichnen, müssen Sie Anführungszeichen in Befehlszeichenfolgen mit Chr$(34) einfügen. Durch folgende Anweisung wird Microsoft Excel angewiesen, die Datei BUDGET.XLS zu öffnen:
DDEExecute Kanal, "[OPEN(" + Chr$(34) + "BUDGET.XLS" + Chr$(34) + ")]"
Beispiel:
Option Compare Database 'Verwenden der Datenbank-Sortierreihenfolge beim Vergleich von Zeichenfolgen.
Sub DDE_Excel_Beispiel ()
' Ein Request der SysItems liefert grundsätzlich folgende Themen :
' - SysItems diese Aufzählung
' - Topics System bei leerem Excel oder Arbeitsblätter-Auflistung des aktiven Dokumentes
' - Status Ready
' - Formats XLTable Microsoft Excel 5.0-Format BIFF4 Biff3 SYLK Wk1 CSV Text Rich Text Format DIF Bitmap Picture
' - Selection leer oder markierter Bereich
' - Protocols StdFileEditing Embedding
' - EditEnvItems StdHostNames StdTargetDevice StdDocDimensions
' - System leer
' Das folgende Beispiel ist wie üblich ein bißchen Scheiße, da
' z.B. der Befehl [New(1)] im deutschsprachigem Excel-Basic
' überhaupt nicht zur Verfügung steht, aber als DDEExecute
' sehr wohl funktioniert.
' Hier wurde nicht nur ein unnötiges Deutsch-Basic erfunden,
' sondern obendrein Teile der Software parallel mehrsprachig
' gehalten:
' DDEExecute Kanal, "[New(1)]" in der Access-Doku entspricht
' DDEExecute Kanal, "[AktiveArbeitsmappe.TabellenblattListe.Hinzufügen]",
' und kann wahlweise benutzt werden, wobei pikanterweise die
' 10-mal so große, deutsche Anweisung über die 4-fache Anzahl
' von Parametern verfügt, von denen scheinbar nur 'Anzahl' in
' beiden Versionen auftaucht.
' Syntax : Objekt.Hinzufügen(Vor; Nachfolgend; Anzahl; Typ)
' So auch DDEExecute Kanal, "[Select(""R1C1:R1C10"")][New(2,2)]", das
' hier in diesem Beispiel einen Bereich markiert und ein Standard-Diagramm
' in einer neuen Mappe erstellt. Die Zusammenhänge dieser Anweisung bleiben
' im Dunkeln.
' Allgemeine Kurz-Info :
' - DDEInitiate(Name,Thema) : Name der Anwendung, meist Name der ausführbaren Datei; gültiges Thema; Rückgabe Kanalnummer
' - DDEExecute Kanalnummer, Befehl : Kanalnummer; zu sendender Befehl; keine Rückgabe
' - DDERequest(Kanalnummer, Element) : Kanalnummer; Informations-Element (häufig SysItems, Topics)
' - DDEPoke Kanalnummer, Element, Daten
' - DDETerminate Kanalnummer
' - DDETerminateAll
' Es gibt eine obskure DDE-Funktion, die als Steuerelement-
' inhalt von Formular-Elementen benutzt werden kann, wie auch
' das eigentlich interessante DDESenden, deren englisches Äqui-
' valent scheinbar DDEPoke ist.
' ***********************************************************
' Dieses Beispiel erzeugt eine DDE-Verknüpfung zu Microsoft Excel, stellt
' einige Werte in die erste Zeile einer neuen Tabelle und zeichnet die
' Werte in ein Diagramm. Zuerst sendet DDEExecute Microsoft Excel den
' Befehl zum Öffnen einer neuen Tabelle. Dann startet DDEInit
' (DDEInitiate) einen DDE-Dialog und DDEPoke sendet die Daten, die
' grafisch dargestellt werden sollen. DDEAnfrage (DDERequest) fragt
' Microsoft Excel nach dem Namen der neu erstellten Tabelle.
' DDETerminate beendet dann die DDE-Verknüpfung mit Microsoft Excel, und
' DDETerminateAll beendet zuletzt alle aktiven DDE-Verknüpfungen.
On Error Resume Next ' Fehlerbehandlungsroutine einrichten.
Dim Kanal, TabName, I, Themen ' Variablen deklarieren.
Kanal = DDEInitiate("Excel", "System") ' Verknüpfung zu Excel herstellen.
If Err Then ' Wenn Fehler, war Excel nicht gestartet.
MsgBox Error
Err = 0 ' Fehlercode zurücksetzen und Microsoft Excel starten.
I = Shell("c:\windows\excel5\Excel", 1)
If Err Then Exit Sub ' Bei erneutem Fehler Programmende.
Kanal = DDEInitiate("Excel", "System") ' Verknüpfung zu Excel herstellen.
End If
DDEExecute Kanal, "[New(1)]" ' Neue Tabelle anlegen.
' DDEExecute Kanal, "[AktiveArbeitsmappe.TabellenblattListe.Hinzufügen]"
Themen = DDERequest(Kanal, "Selection") ' Themenliste und Tabellenname erhalten.
TabName = Left(Themen, InStr(1, Themen, "!") - 1)
DDETerminate Kanal ' DDE-Verknüpfung beenden.
Kanal = DDEInitiate("Excel", TabName) ' Verknüpfung zu neuer Tabelle erstellen.
For I = 1 To 10 ' Einige Werte in erste Zeile eingeben.
DDEPoke Kanal, "Z1S" & I, I
Next I
DDEExecute Kanal, "[Select(""R1C1:R1C10"")][New(2,2)]" ' Diagramm erstellen.
exit_DDE_Excel_Beispiel:
DDETerminateAll ' Alle Verknüpfungen beenden.
End Sub
Sub DDE_Word_Beispiel ()
Dim Kanal, TabName, I, Themen, s As String
Kanal = DDEInitiate("Winword", "System")' Verknüpfung zu Word herstellen.
If Err Then ' Fehler, wenn Word nicht gestartet.
Err = 0 ' Fehlercode zurücksetzen und Microsoft Word starten.
On Error GoTo err_DDE_Word_Beispiel
I = Shell("c:\windows\winword6\winword", 1)
Kanal = DDEInitiate("Winword", "System") ' Verknüpfung zu Word herstellen.
End If
On Error GoTo err_DDE_Word_Beispiel
' Anfordern einer Liste der vom Thema "System" unterstützten Themen.
Ergebnis$ = DDERequest(Kanal, "Topics")
If InStr(Ergebnis$, "C:\WINDOWS\WINWORD6\TEMPO.DOC") > 0 Then
MsgBox "Datei C:\WINDOWS\WINWORD6\TEMPO.DOC ist geöffnet"
s = "[MarkierungErweitern " & """" & "U" & """" & "]"
DDEExecute Kanal, s ' Neue Tabelle anlegen.
' Themen = DDERequest(Kanal, "Selection") ' Themenliste und Tabellenname erhalten.
'MsgBox Themen
End If
exit_DDE_Word_Beispiel:
DDETerminateAll
Exit Sub
err_DDE_Word_Beispiel:
MsgBox Error, , "DDE_Word_Beispiel"
Resume exit_DDE_Word_Beispiel
End Sub
Grafiken & Dimensionen
Quelle: dmt
Datum: 05.2005
Zum Thema Graficken (kein Tippfehler, hat auch nichts mit der Rechtschreibreform zu tun) gehören leider auch TWIPS, PUNKT und Pixel.
Kombiniert man die wie so oft wenig ergiebige Dokumentation mit meinen endlosen Bemühungen, so ergibt sich folgendes Bild:
Access-Basic gibt seine Koordinaten in sog. Twips an. Die Information, daß das Verhältnis von Twips zu Punkten 20:1 beträgt, ist quasi wertlos, da diese Punkte nichts mit den Pixeln zu tun haben, die die wahre Beschreibung der Positionen der Bildschirmpunkte beinhalten. Zu beachten ist daher das Verhältnis Twips zu Pixel 15:1.
Lizenz-Fehler
Quelle: dmt
Datum: 03.2004
Apropos Office97 und Access97:
Sehr beliebt ist der Lizenz-Fehler von Access97, öfter auch mal im Zusammenspiel mit vorangegangenen Access2000-Installationen.
Behebbar durch Einspielen folgender reg-Datei (z.B. "acc_fuck.reg"):
REGEDIT4
[HKEY_CLASSES_ROOT\Licenses]
@="Licensing: Copying the keys may be a violation of established copyrights."
[HKEY_CLASSES_ROOT\Licenses\8CC49940-3146-11CF-97A1-00AA00424A9F]
[HKEY_CLASSES_ROOT\Licenses\8CC49940-3146-11CF-97A1-00AA00424A9F\Retail]
@="yubcdcprktpjtapmmfdacmupasbhscddncgp"
[HKEY_CLASSES_ROOT\Licenses\8B7FE740-50AC-101B-A3C9-08002B2F49FB]
@="mjgcqcejfchcijecpdhckcdjqigdejfccjri"
[HKEY_CLASSES_ROOT\Licenses\F4FC596D-DFFE-11CF-9551-00AA00A3DC45]
@="mbmabptebkjcdlgtjmskjwtsdhjbmkmwtrak"
Objekte manipulieren
Quelle: dmt
Datum: 10.2004
DATENBANKOBJEKTE manipulieren:
Es ist wiederholt vorgekommen, per Code auf in Access enthaltene Datenbankobjekte zuzugreifen. Jedesmal mußte dies mit enervösem Zeitaufwand bezahlt werden. Deshalb hier eine Routine, die als Parameter Name und Container-Typ eines Datenbankobjektes erwartet und eine später benutzte Variable iObjectType in Abhängigkeit von Containers-Typ zuweist.
Es werden die Document-Objekte des angegebenen Containertyps durchlaufen. Bei einem Treffer wird das Objekt direkt löschenderweise angesprochen.
So kann z.B erreicht werden, daß ein temporäres Objekt unter einem Standardnamen angelegt werden kann, und zwar unabhängig davon, ob bereits ein gleichnamiger Vorgänger besteht oder nicht. Weitere Fallunterscheidungen oder Fehlerbehandler in der eigentlichen Routine sind nicht nötig.
Function DeleteObject (sName As String, iObjectType As Integer) As Integer
On Error GoTo err_DeleteObject
Dim DB As Database
Set DB = DBEngine.Workspaces(0).Databases(0)
DoCmd DeleteObject iObjectType, sName
DeleteObject = True
Exit Function
err_DeleteObject:
If Err = 2487 Then
Beep
MsgBox "Der angegebene Objekttyp " & iObjectType & " ist ungültig !", 16,
"Tools/DeleteObject"
ElseIf Err = 3011 Then ' wenn Objekt nicht existiert
DeleteObject = True
Else
Fehler "Tools / DeleteObject"
End If
Exit Function
End Function
Die Funktion verhält sich ruhig, wenn das angegebene Objekt nicht (mehr) existiert und kann so auch sicherheitshalber aufgerufen werden.
* * * *
Auch das Umbennen von Datenbankobjekten (sollte eher selten vorkommen) ist an sich gar nicht so schwierig:
Private Function Rename_Query (vQ As Variant) As Integer
On Error GoTo err_Rename_Query
Dim DB As Database, QD As QueryDef, s As String
Set DB = DBEngine.Workspaces(0).Databases(0)
Set QD = DB.QueryDefs(vQ)
s = InputBox$("Geben Sie den neuen Namen ein:", vQ, "dkl_")
If s <> "" Then
QD.Name = s
Rename_Query = True
End If
Exit Function
err_Rename_Query:
Fehler "Rename_Query"
Exit Function
End Function
Mit ein wenig Aufwand kann das sogar auf andere Objektarten bzw. allgemein ausgeweitet werden.
* * * *
Ein nettes Info-Tool GENERAL_INFO, aufgerufen über die Funktion ShowContextInfo kann nicht nur formularspezifische Infos in einer Tabelle anlegen, sondern über Application.CurrentObjectType- und Application.CurrentObjectName-Übergabe sogar das Aktivsein allgemeiner Access-Objekte sowie bei Bedarf deren Zustand über die Funktion SysCmd(SYSCMD_GETOBJECTSTATE) als
OBJSTATE_OPEN Geöffnet
OBJSTATE_NEW Neu
OBJSTATE_DIRTY Geändert
erkennen.
Objekte, Existenz prüfen
Quelle: dmt
Datum: 03.2004
Ja, so ist das eben; also bevor man sich auf die GETOBJECTSTATE-Variante von SysCmd verläßt, um auch geschlossene Datenbank-Objekte auf Vorhandensein zu prüfen, sollte der Zuverlässigkeit zuliebe folgendes bemüht werden:
EXISTSOBJECT:
Function ExistsObject (iArt As Integer, sName As String) As Integer
On Error GoTo err_ExistsObject
' *** Existiert das angegebene Objekt in der Datenbank ? ****
Dim DB As Database
Dim C As Container
Dim D As Document
Dim sContainerName As String
Select Case iArt
Case A_TABLE: sContainerName = "Tables"
Case A_QUERY: sContainerName = "Tables"
Case A_FORM: sContainerName = "Forms"
Case A_REPORT: sContainerName = "Reports"
Case A_MACRO: sContainerName = "Scripts"
Case A_MODULE: sContainerName = "Modules"
Case Else: Beep
MsgBox "Ungültiger Parameter iArt:'" & iArt & "'.", 16, "ExistsObject"
Exit Function
End Select
Set DB = DBEngine.Workspaces(0).Databases(0)
Set C = DB.Containers(sContainerName)
Set D = C.Documents(sName)
ExistsObject = True
exit_ExistsObject:
Set D = Nothing
Set C = Nothing
Set DB = Nothing
Exit Function
err_ExistsObject:
If Err = 3265 Then
' nix
Else
Fehler "ExistsObject"
End If
Resume exit_ExistsObject
End Function
Übergeben werden die wohl bekannten Parameter a'la A_FORM und der Name des obskuren Objektes der Begierde und als Antwortwert gibt es ein vertrautes 0 oder -1.
Und zur Auswertung und zum folgerichtigen Reagieren kann dann so etwas bemüht werden:
If ExistsObject(A_FORM, s) Then
DoCmd OpenForm s
ElseIf ExistsObject(A_TABLE, s) Then
DoCmd OpenTable A_TABLE, s
Else
Beep
MsgBox "Ungültiger Wert '" & s & "' in pb_Ok_Click", 16, "Chefdaten-Freischaltung"
End If
End if
Yes !
Objekte, löschen, austauschen
Quelle: dmt
Datum: 03.2004
Löschen z.B. eines Modules, aber nur in der eigenen Datenbank:
DoCmd.DeleteObject [Objekttyp, Objektname]
Die Methode DeleteObject verwendet die folgenden Argumente:
Argument Beschreibung
Objekttyp Eine der folgenden eingebauten Konstanten:
acDefault (Standardwert)
acForm
acMacro
acModule
acQuery
acReport
acTable
Interessanter ist DoCmd.CopyObject, das Datenbank-übergreifend arbeitet, bzw. das Arbeiten mit DoCmd.TransferDatabase.
Evtl. kann mit den Methoden des Modul-Objektes in Access97 Quelltext eines Modules entfernt und danach durch neuen ersetzt werden.
odbc
Quelle: dmt
Datum: 03.2004
ODBC
braucht nicht unbedingt DDE, um einen zu beschäftigen.
So kann es z.B. vorkommen, daß Access per odbc eingebundene Tabellendaten nicht bearbeiten kann, obwohl diese Daten zum Teil sogar durch eine Access-Anfügeabfrage in diese z.B. MySQL-Tabelle eingefügt wurden !
In mindestens diesem Fall hing das damit zusammen, daß Access beim Einbinden nach einem Feld zur eindeutigen Identifizierung der Datensätze frug. Wird der Dialog abgebrochen, scheint alles klar zu sein, nur daß halt die Datensatzgruppe schreib-geschützt ist. Bestimmt man ein halbwegs sinnvolles Feld als unique Kriterium, dann klappts auch mit dem Aktualisieren.
Stammdaten
Quelle: dmt
Datum: 03.2004
STAMMDATEN und ihre Verwaltung:
Über Maus- und Tastatur-Aktionen öffne ich für Kombinationsfelder, die hinterlegte Werte anbieten, gerne die entsprechenden Stammdatenformulare, die bei Bedarf individuell programmiert werden können. Bisher war es aber immer ein
Problem, bei evtl. Änderungen an den Stammdatensätzen eine Aktualisierung des Kombinationsfeldes vorzunehmen. Dies führte zu so rührenden Versuchen mit unsichtbaren Unterformularen und lauter so Sachen.
Eine vernünftige Lösung sieht wie folgt aus:
Ein Standardformular mit Standard-Eigenschaften (alle Versuche, Daten in Listendarstellung innerhalb eines gebundenen Formulares darzustellen, sind mit unzumutbarem Aufwand verbunden oder gar nicht möglich).
Für das Ereignis Form_Current gilt z.Bsp.:
If Me.CurrentView = 1 Then
DoCmd MoveSize 3000, 1700, 4200, 1430
Else
DoCmd MoveSize 3000, 500, 4200, 5000
End If
oder noch besser siehe CenterForm.
Hier wird für Einzel- sowie Listenansicht die Größe des Formulares getrennt eingestellt (it's not a trick, it's me). Wenn man das noch mit einer gesetzten Variable LastView vergleicht, werden die Anweisungen nur nach einem
Ansichtswechsel abgearbeitet.
In den Ereignissen De/Activate wird eine Standard-Symbolleiste (sehr geil in der LaserJob-Code-Datenbank LIB_LJ.MDA) ein- oder ausgeblendet. Beim Umschalten zu Formularen, die dieselbe Symbolleiste benutzen, ist nicht einmal ein Flackern zu bemerken.
Aufgerufen werden diese Formulare über eine Anweisung a'la 'ZeigeStammdaten xyz':
Sub ZeigeStammdaten (sFormular As String, sFeld As String, iAnsicht As Integer)
On Error GoTo err_ZeigeStammdaten
Dim v As Variant
v = Screen.ActiveControl
Application.Echo False
DoCmd OpenForm sFormular, iAnsicht
Forms(sFormular)(sFeld).SetFocus
If Not IsNull(v) Then DoCmd FindRecord v
exit_ZeigeStammdaten:
Application.Echo True
Exit Sub
err_ZeigeStammdaten:
If Err = 2102 Then
DoCmd OpenTable sFormular
Resume Next
Else
Fehler "Modul ZeigeStammdaten"
Resume exit_ZeigeStammdaten
End If
End Sub
In der neuesten Version mit Ansichtsparameter und und abgeschaltetem Applikations-Echo, um ein Aufflackern des ersten Formular-Datensatzes zu verhindern.
Hier werden sogar NULL-Werte im Mutterformular abgefangen und das ALLERGRÖßTE überhaupt besteht in dem Geschenk des Himmels, daß u.U. ALLE Manipulationen an Stammdatensätzen augenblicklich in den Kombinationsfeldern des Mutterformulares
zur Verfügung stehen, auch wenn für die betroffenen Tabellen KEINE referentiellen Beziehungen vorgesehen sind. Obendrein kann bei nicht vorhandenem Formular eine Tabelle geöffnet werden.
Unklar bleibt, warum ich mir beim Aktualisieren solcher Daten innerhalb eingebetteter Unter-formulare einen runterholen mußte, aber wie dem auch sei, dies ist einer von den ganz seltenen Augenblicken, in denen ich allen Ernstes glaube, daß man mit MS-ACCESS (2.0 !!!) Anwendungen entwickeln kann.
* * * *
Auch kommt es vor, daß Unterformulare sich auf Daten in sog. Zuordnungstabellen beziehen, in denen lediglich Idents und Namen stehen. Wenn sich aus irgendeinem Grund ungültige Einträge dorthin verirrt haben, ist es durchaus sinnvoll, vom Unterformular aus die Zuordnungstabelle zu öffnen und zu dem entsprechenden Datensatz zu wechseln:
Sub Zeige_Zuordnungsdaten (sTabelle As String, sTabellenfeld As String, vIdent As Variant, vFormularfeld As Variant)
On Error GoTo err_Zeige_Zuordnungsdaten
Meldung "synchronisiere Daten ..."
DoCmd OpenTable sTabelle
DoCmd Restore
DoCmd FindRecord vIdent
Meldung ""
DoCmd SelectObject A_TABLE, sTabelle
DoCmd GoToControl sTabellenfeld
DoCmd FindRecord vFormularfeld, , , , , , False
Exit Sub
err_Zeige_Zuordnungsdaten:
Fehler "Zeige_Zuordnungsdaten"
Exit Sub
End Sub
Für das zu bedienende Steuerelement gilt:
Sub Name_DblClick (Cancel As Integer)
Zeige_Zuordnungsdaten "Mitwirkende", "Name", Me!Ident, Me!Name
End Sub
und natürlich das bewährte
Sub Name_KeyDown (KeyCode As Integer, Shift As Integer)
If KeyCode = 32 And Shift = 2 Then
Name_DblClick (0)
End If
End Sub
und der freundliche Statuszeilenhinweis:
Name der Person: <Doppelklick/Strg+Leer> öffnet Stammdaten
Das Ganze läßt sich bei 'Untertabellen', die typische Unterformular-Zuweisungsdaten enthalten, noch erweitern. Neben der bewährten ZeigeStammdaten-Lösung kann per rechte Maustaste bzw. <Strg+Shift+Leer> auch die Zuweisungs-Untertabelle geöffnet werden.
Feld-Statuszeile:
Suchname der Institution: <Doppelklick/Strg+Leer> Stammdaten <r.Maustaste/Strg+Shift+Leer> Zuweisungstabelle
Im Zuge allgemeiner Kapselungen steht alles in einer eigenen Routine:
Sub Suchname_MouseDown (Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = RIGHT_BUTTON Then
Zeige_Projekte_Institutionen
End If
End Sub
Sub Suchname_KeyDown (KeyCode As Integer, Shift As Integer)
If KeyCode = 32 And Shift = 2 Then
Suchname_DblClick (0)
ElseIf KeyCode = 32 And Shift = 3 Then
Zeige_Projekte_Institutionen
End If
End Sub
Private Sub Zeige_Projekte_Institutionen ()
Zeige_Zuordnungsdaten "Projekte_Institutionen", "Suchname", Me!Ident, Me!Suchname
End Sub
Zu der äußerst lästigen Bitmasken-Auswertung bez. der diversen 'Shift'-Tastaturzustände muß gesagt werden, daß ich in diesem Fall die explizite Nenung bevorzuge:
1 Control
2 Shift
4 Alt
Daraus ergeben sich dann alle anderen Kombinationen:
3 Control und Shift
usw.
Statuszeile
Quelle: dmt
Datum: 08.2010
Allgemeines zur Statuszeile:
Für eine durchgehende Anwenderinformation innerhalb einer längeren Code-Routine mittels der Statuszeile empfiehlt sich ein häufiges Setzen mit
x = SysCmd(SYSCMD_SETSTATUS, "Sind die Einstellungen korrekt ?"),
damit auch Code-Unterbrechungen durch MessageBoxen nicht mit älteren Beschreibungen versehen werden.
Falls in dieser Routine 'Exit Sub/Function'-Anweisungen vorgesehen sind, sollte stattdessen ein Goto 'Exit_Routinen_Name' erfolgen, wo dann die Statuszeile mit
x = SysCmd(SYSCMD_CLEARSTATUS)
zurückgesetzt wird, damit zugewiesene Texte nicht durch den Rest der Anwendung geistern.
Sehr ominös ist die Tatsache, daß, wenn aus einem gebundenem Menü-Formular normale Formulare aufgerufen und diese wieder geschlossen werden, die StatuszeilenText-Eigenschaften der Schaltflächen des Menü-Formulares alle
verlorengegangen zu sein scheinen !
Bisher konnte noch keine Abhilfe geschaffen werden. Allerdings könnte man das Problem dadurch beheben, daß ein gebundenes Menüformular in ein normales Windows-Fenster umgewandelt wird.
Bei einer stringenten Benutzer-Fenster-Führung muß man entweder
- alle nicht benötigten Formulare ausblenden, um sich bei mehreren Fenstern nicht zu verklicken, oder gebundene Formulare schließen und wieder öffnen, anstatt sie auszublenden,
- oder eben mit dem Problem leben,
- oder Contra-Programmierung mit heftigen FormX.SetFocus-Anweisungen.
****
Statuszeile zurücksetzen per SYSCMD_CLEARSTATUS:
Hier tritt ein Fehler auf, wenn SysCmd(SYSCMD_CLEARSTATUS) nochmals ausgeführt wird, ohne daß der Statustext inzwischen neu gesetzt wurde.
Wenn sich das partout nicht umgehen läßt, kann eine formular- oder anwendungsglobale Variable definiert werden Global gStatusHasBeenCleared As Integer
, die im betreffenden Code z.B. so behandelt wird:
If xOk = True And yOk = True Then
gStatusHasBeenCleared = False
v = SysCmdSYSCMD_SETSTATUS, "..."
ElseIf gStatusHasBeenCleared = False Then
v = SysCmdSYSCMD_CLEARSTATUS
gStatusHasBeenCleared = True
End If
Systemobjekte
Quelle: dmt
Datum: 10.2004
SYSTEMOBJEKTE:
sind in der Tabelle MySysObjects hinterlegt und können per Code oder SQL abgefragt werden.
Beispiele:
Code: If (TD.Attributes And DB_SYSTEMOBJECT) then
prüft, ob ein angegebenes TableDef-Objekt als Systemtabelle definiert wurde.
SQL: SELECT Name, Type, Flags FROM MSysObjects ORDER BY Type, Name;
listet alle Einträge in der Systemobjekt-Tabelle
* * * *
Systemobjekte erkennen und unterscheiden:
Die aufgelisteten Werte sind Zuordnungswerte aus der MSysObjects-Tabelle und haben natürlich überhaupt gar nichts mit den System-weit deklarierten Konstanten wie A_TABLE zu tun (Microdoofe Schwachmaten!).
Weitere, detaillierte Beispiele z.B. zur Unterscheidung des Flag-Merkmales finden sich bei "Struktur auswerten".
Objekt Wert Zusatz
------------------------------------------------------
Tabellen 1 interne
unbekannt 2 Name: MSysDb
unbekannt 3 Objektarten: Forms, Reports etc.
Abfragen 5
Tabellen 6 eingebundene
Referenzen 8 z.B. Beziehungen zwischen Tabellen
unbekannt -32758 evtl. Benutzer
Module -32761
Berichte -32764
Makros -32766
Formulare -32768
Eine informative Umsetzung in SQL sieht dann so aus:
SELECT Name, Type, Flags,
IIF(Type=1, "Tabelle (intern)",
IIF(Type=2, "unbekannt",
IIF(Type=3, "Objektart",
IIF(Type=5, "Abfrage",
IIF(Type=6, "Tabelle (eingebunden)",
IIF(Type=8, "Referenz",
IIF(Type=-32758, "evtl. Benutzer",
IIF(Type=-32761, "Modul",
IIF(Type=-32764, "Bericht",
IIF(Type=-32766, "Makro",
IIF(Type=-32768, "Formular",
))))))))))) AS Art
FROM MSysObjects
ORDER BY Type, Name;
* * * *
Das Problem, in einer Access-Datenbank befindliche Tabellen aufzulisten, kann auf verschiedene Arten gelöst werden:
Einmal durch das wuchtige Zeige_Tabellen aus frühen Tagen, dann durch ein simples Abfragen der MSysObjects-Tabelle oder einem Durchnudeln der DBEngine.Objekte.
Me!lst_Objekte.RowSource = "SELECT Name FROM MSysObjects WHERE Type=" & Wert & " ORDER BY Name;"
weist einem Listenfeld die Datenherkunft zu, die alle internen Tabellen auflistet, wenn der Wert '1' übergeben wurde.
Zusätzlich enthält das Feld Flags weitere Informationen, z.B, ob eine Abfrage eine Aktualisierungsabfrage oder eine Tabelle eine Systemtabelle oder eine unsichtbare, temporäre Tabelle ist.
Function Zeige_Tabellen (SO As Integer, Feld As Integer)
' Wenn SO <> 0 und der obskur 'logische' Vergleich von
' If (TD.Attributes And DB_SYSTEMOBJECT) then
' durchgeht, werden auch die Systemtabellen aufgelistet.
' Da aber in TableDef.Attributes auch Flags enthalten sind, die andere als nur
' Systemtabellen-Zeiger enthalten, kann davon ausgegangen werden, daß bei
' SO = 0 evtl. auch Nicht-Systemobjekte unterschlagen werden.
Dim s1 As String * 24 ' Variable fester Länge deklarieren.
Dim s2 As String * 8 ' Variable fester Länge deklarieren.
Dim s3 As String * 19 ' Variable fester Länge deklarieren.
Dim s4 As String * 19 ' Variable fester Länge deklarieren.
Dim DB As Database
Dim TD As TableDef
Dim i As Integer
Dim i1 As Integer
Dim i2 As Integer
Dim z As Integer
Dim s As String
Dim Wert1 As String
Dim Wert2 As String
Dim W10 As String
Dim W11 As String
Dim W12 As String
Dim W13 As String
z% = 0
s$ = InputBox$("Geben Sie den Namen der Datenbank-Datei an:", "Zeige Tabellen aus Datenbank", "dmt.mdb")
If s$ = "" Then Exit Function
Set DB = DBEngine.Workspaces(0).OpenDatabase(s$, True, True)
ReDim Tabellen(3, DB.TableDefs.Count - 1)
For i% = 0 To DB.TableDefs.Count - 1
Set TD = DB.TableDefs(i%)
If (TD.Attributes And DB_SYSTEMOBJECT) And (SO = 0) Then GoTo ZEIGE_TABELLEN_WEITER
s1 = TD.Name
RSet s2 = Format$(TD.RecordCount, "#,0")
RSet s3 = TD.DateCreated
RSet s4 = TD.LastUpdated
Tabellen(0, z%) = s1 ' strukturierte Strings
Tabellen(1, z%) = s2 ' an Array übergeben,
Tabellen(2, z%) = s3 ' um daran weiter zu
Tabellen(3, z%) = s4 ' operieren.
z% = z% + 1 ' Zähler für Aufrücken in Array
ZEIGE_TABELLEN_WEITER:
Next i%
' ************** Sortieren der Arraydaten *******************
If Feld = -1 Then GoTo ZEIGE_TABELLEN_AUSGABE
For i1% = 0 To z% ' Das Array sortieren:
For i2% = i1% + 1 To z% - 1 ' Eine Schleife zählt vom
Wert1 = Tabellen(Feld, i1%)
Wert2 = Tabellen(Feld, i2%)
W10 = Tabellen(0, i1%)
W11 = Tabellen(1, i1%)
W12 = Tabellen(2, i1%)
W13 = Tabellen(3, i1%)
If Wert2 < Wert1 Then
Tabellen(0, i1%) = Tabellen(0, i2%)
Tabellen(1, i1%) = Tabellen(1, i2%)
Tabellen(2, i1%) = Tabellen(2, i2%)
Tabellen(3, i1%) = Tabellen(3, i2%)
Tabellen(0, i2%) = W10
Tabellen(1, i2%) = W11
Tabellen(2, i2%) = W12
Tabellen(3, i2%) = W13
End If
Next i2%
Next i1%
' ********************** Ausgabe ****************************
ZEIGE_TABELLEN_AUSGABE:
Debug.Print
Debug.Print Str$(DB.TableDefs.Count) & " Tabellen in '" & s$ & "':" &
Str$(z%) & "normale und" & Str$(i% - z%) & " Systemtabellen"
Debug.Print
Debug.Print " Tabellenname Anz.DS erstellt am
letzte Änderung """
Debug.Print
For i% = 0 To z%
Debug.Print " " & Tabellen(0, i%) & Tabellen(1, i%) & " " &
Tabellen(2, i%) & " " & Tabellen(3, i%)
Next i%
' **********************************************************
DB.Close
End Function
* * * *
Eigene SYSTEMOBJEKTE erzeugen / unsichtbare bzw. versteckte Tabellen:
Es kann durchaus sinnvoll sein, z. B. eine System-Tabelle zum Hinterlegen interner Informationen zu benutzen. Wie üblich schlugen sämtliche Versuche, so etwas auf der Basis der Dokumentation zu lösen, fehl. Zwar wird versprochen, daß
Tabellen-Attribute beschreibbar sind, wenn das Tabellen-Objekt noch nicht der Auflistung vorhandener Tabellen hinzugefügt wurde, aber die Werte DB_SYSTEMOBJECT und DB_HIDDENOBJECT wollten sich partout nicht zuweisen lassen.
Unklar bleibt somit auch, wie dann sogenannte unsichtbare TObjekte zur temporären Verwendung erzeugt werden sollen.
Die Lösung war ebenso einfach wie unkonventionell. Bei angezeigten Systemobjekten wird z.B. die Tabelle "MSySToolbars" (für die übrigens KEINE Entwurs-Änderungsrechte bestehen) kopiert und wieder eingefügt. Das eingefügte Tabellenobjekt verfügt nun über den begehrten Systemstatus, ist aber witzigerweise NICHT mehr entwurfsgeschützt und kann daher nach Herzenslust bearbeitet werden.
Beim Erstellen von Abfragen, Formularen oder Berichten steht diese Tabelle wie die echten Systemobjekte nicht mehr in den diversen Klappfenstern oder Assistenten zur Verfügung. Wird jedoch der Name dieser Systemtabelle explizit angegeben (z.B. auch im Code), kann das Objekt trotzdem angesprochen werden.
* * * *
MAKRO / SYSTEMOBJEKTE / MSysMacros / Systemtabellen:
Eine Reihe von Access-Internas (Makros, relationale Referentiellitäten etc.) werden in Systemtabellen verwaltet. Klar, daß auch diese Sachen nicht in der mitgelieferten Dokumentation behandelt werden.
In MSysMacro stehen die Einträge für Makros sowie deren Elemente. Es ist zwar ein Mehrfelder-Index hinterlegt (Scriptname und Label, jeweils aufsteigend sortiert), die Daten erscheinen aber ohne eindeutiges ID, das die Bezüge untereinander herstellen könnte, untereinander in der Reihenfolge der Anlage der Makros (mit vergebenem Scriptname) und dann ohne Scriptname in der Reihenfolge der Makroelemente, wie sie in der Entwurfsansicht des Makros zu sehen sind. Die Einstellungen der Makro-Elemente-Eigenschaften werden in diesen Folge-Datensätzen in diversen 'Argumentx'-Feldern gespeichert.
So enthält ein Versuchsmakro 'Drucken_Aktion' das Element 'Drucken' mit diversen Eigenschaften-Einstellungen. In der Tabelle MSysMacros erscheinen dann am unteren Ende der Datensatzliste (zumindest optisch beim Öffnen der Tabelle) zwei Datensätze: Der erste mit Scriptname=Makroname und der folgende ohne Scriptname mit den Element-informationen, z.B. enthält das Argument5 für ein Element mit der Aktion 'Drucken' den Wert der Aktions-Eigenschaft 'Exemplare'. Da mit diesen Informationen nur korrekt angelegte Objekte ausgelesen und im schlimmsten Falle bearbeitet werden sollen, können die nicht nachvollziehbaren korrespondierenden Einträge in MSysObjects hoffentlich vernachlässigt werden.
Timer
Quelle: dmt
Datum: 03.2004
TIMER:
Das Aktivieren eines Timers im Hauptformular für Termin-Erinnerungen kann zu seltsamen Effekten führen, wenn u.a. eine Dos-Task läuft. In diesem Fall kann es vorkommen, daß mittels <Alt + Tab> nicht per Task-Manager umgeschaltet werden kann.
Unter Windows-Applikationen scheint es keine Probleme zu geben.
Kompromiß: In Vorgabeeinstellungen sollte angeboten werden, die Timer-Option automatisch an- oder auszuschalten.
Tuning
Quelle: dmt
Datum: 03.2004
BESCHLEUNIGEN:
Datei MSACC20.INI
Abschnitt [ISAM]
MaxBufferSizes=4096
ReadAheadPages=5
Abschnitt [Options]
DebugLibraries=False
Abschnitt [Libraries]
so weit abspecken wie möglich
Das großzügige Abspecken geladener Assistenten etc. (per Hand oder Add-In-Manager) reduziert Arbeitsspeicherbedarf und Ladezeiten.
Es gilt ferner natürlich alles, was Windows beschleunigt:
z.B.:
- nicht zu viele Programme gleichzeitig.
- Hintergrundbilder
- aufwendige Bildschirmschoner
- virtueller Speicher incl. RAM min. 25 MB !
- Auslagerungsdatei permanent und 32-Bit (nach Möglichkeit)
- Festplatte scandisk und defrag
- RAM ist durch nichts zu ersetzen
- bei wenig RAM nicht zuviel Smartdrv-WinCache oder gar RAM-Disk
- Buffers in config.sys min. 40 (eigentlich mit Smartdrv unnötig)
- Datenbank lokal halten und exklusiv öffnen, wenn nicht in Mehrbenutzerumgebung
Abfragen:
- wenig Indizes; sinnvoll für Felder, mit denen Tabellen verknüpft werden (auch referentielle Sachen)
- Reihenfolge der Felder in Abfrage gemäß der in Mehr-Felder-Indizes
- Sortierung vor allem nach nicht indizierten Feldern vermeiden.
- Daten aus verteilten Tabellen sollten am besten über Primary-Index-Felder verknüpft werden.
- Kein DLookup in Abfrage; eher Tabelle in Abfrage aufnehmen oder Unterabfrage.
- Anzahl der Felder beschränken, wenn möglich.
- Listen- und Kombinationsfelder sollten nicht auf eingebundene Tabelle zeigen.
- Eigenschaft Datensatzherkunft für Formulare und Felder besser auf eine Abfrage zeigen lassen.
Drucken:
- Berichtseigenschaft Schneller Laserdruck
- im Abschnitt [Microsoft Access] der msacc20.ini den Eintrag 'UseDefaultPrSetup' einfügen.
Module:
- immer erst kompilieren, bevor gespeichert wird.
- vollständige Bezeichner nicht häufig verwenden, eher an Objektvariablen übergeben.
- Transaktionen !
Wenn nicht in einer Mehrbenutzerumgebung gearbeitet wird, können innerhalb von MS-Access in ANSICHT / OPTIONEN die Zeitintervalle im Menüpunkt 'Mehrbenutzerumgebung / ODBC' auf die zulässigen Höchstwerte gesetzt werden.
Unbedingt das Hilfe-Item "Optimieren / Leistung" durchlesen !
Geschwindigkeit und Programmierstil:
TRANSAKTION:
Wenn Datenmengen durchgenudelt werden müssen und dabei Schreib-/Lesezugriffe erfolgen, kann die Performance durch den Einsatz von Transaktionen (transaction) erheblich beschleunigt werden:
Dim WS As WorkSpace
Set WS = DBEngine.Workspaces(0)
WS.BeginTrans
Do While Not RSZ.EOF
...
Loop
' ************* Rücknahme der Transaktion anbieten **************
x = SysCmd(SYSCMD_SETSTATUS, "Wollen Sie ... bestätigen ?")
If MsgBox("Text", 292, "Titel") = 6 Then
WS.CommitTrans
Else
WS.Rollback
end if
x = SysCmd(SYSCMD_CLEARSTATUS)
Allerdings kam es einmal vor, daß in einer Routine, in der in einer transaktions-überwachten Schleife ein Recordset redefiniert wurde, der Fehler "Kann keine weiteren Tabellen öffnen" auftrat. Erst nach Entfernen der Transaktions-Methoden konnte das bewältigt werden.
Ebenso mußte festgestellt werden, daß ein Recordset nicht durchlaufen wurde, wenn nicht ein explizites RS.MoveFirst angewandt wurde und, was viel schwerwiegender ist, daß es über das SEL-Stiftungs-Novell-Netz zu wiederholbaren
Abstürzen bei einer bestimmten Tabelle, an die per Transaktion Datensätze angefügt wurden, kam.
Vergleich von Access mit Excel
Quelle: microsoft
Datum: 08.2005
Die Entscheidung, welche Aufgaben man besser mit Excel oder Access bearbeitet, ist selbst für fortgeschrittene Benutzer schwer zu überschauen. Als Datenbank-Programmierer habe ich meistens kein Problem, nach 'Sicht der Akten' zu entscheiden, welcher Weg der bessere ist.
Ausgerechnet aus dem 'feindlichen' Microsoft-Lager stammt ein einigermaßen allgemein verständlicher Artikel zu diesem Thema, geschrieben von Emma Nelson (Office-Hilfeteam):
Verwalten von Daten mit Access oder Excel
Verzögerung
Quelle: dmt
Datum: 03.2004
PAUSE:
Sub Pause(Sekunden As Integer)
Dim sngStart As Single
sngStart = Timer ' Start-Zeit ermitteln.
Do
DoEvents
Loop Until Timer >= sngStart + Sekunden ' Übergabe-Sekunden-Schleife
End Sub
sorgt dafür, daß Access-Basic für die übergebene Anzahl Sekunden in dieser Routine verweilt.
* * * *
WAIT:
Eine andere, eher simple Möglichkeit, Minipausen einzubauen, um Systemhänger in z.B. anderen Anwendungen zu überbrücken, bestand bei SEL im Mehrfach-Aufruf von DoEvents. Hat bei RemoteShell-Anweisungen in Windows-TNVT-Unix-Terminal-Fenstern gut geholfen.
Sub wait ()
Dim j as Integer
For j = 1 To 200
DoEvents
Next j
End Sub
* * * *
XSENDKEYS:
Ebenfalls in diesem Zusammenhang steht xSendKeys, das einen SendKeys-String buchstabenweise übermittelt. Dann klappts auch in Shell-Fenstern.
Sub xSendKeys (sK As String)
' Wenn eine Anwendung sich beim Empfangen von Access-SendKeys-Zeichenketten
' verschluckt, können diese dann eben auch buchstabenweise übergeben werden.
Dim l As Integer, C As String
l = Len(sK)
For i% = 1 To l
C = Mid$(sK, i%, 1)
SendKeys C, True
Next i%
End Sub