infobase: EDV - MS-Access
API
32-Bit Aufrufe aus Access 2.0
Datum: 02.2006
Ja, das hat für Verwirrung gesorgt und lange gedauert, bis Licht ins Dunkel kam.
Alle Beispiele setzen selbstverständlich eine 32-Bit-Windows-dll-Umgebung voraus, womit die Türe zu Windows 3.x und OS/2 zugeschlagen worden sein dürfte.
Der Modul-Deklarationsbereich API_Call32:
Option Compare Database 'Verwenden der Datenbank-Sortierreihenfolge beim Vergleich von Zeichenfolgen.
Option Explicit
' **** In 16-Bit-Anwendungen ist es nicht möglich, Aufrufe an 32-Bit-dlls zu richten. ****
' Aufrufe gegen z.B. "kernel32" mißlingen daher in Access-2.0 IMMER: Datei nicht gefunden !
' Die unter Windows NT im system32-Verzeichnis enthaltene "kernel32.dll" wird grundsätzlich
' nicht gefunden, der 16-Bit-"kernel" wird wohl vom ominösen 16-Bit-Subsystem geliefert.
' Aufrufe gegen "kernel" mißlingen wegen des verschiedenen Funktionsumfanges der kernel-
' Dateien unter Win9x und Windows NT zuweilen auch:
' So wird eine API-Funktion "GetFileAttributes" unter Win9x im "kernel" gefunden,
' Windows NT meldet aber "Sub oder Function nicht definiert".
' **** und hier kommt die Lösung, die es erlaubt, aus 16-Bit-VB-Anwendungen heraus ****
' **** beliebige Aufrufe an 32-Bit-dlls zu richten: ****
' Mein mehr als herzlicher Dank geht an:
' Peter Golde (Author und Verfasser der Ur-Version) und
' Rob Lichtefeld (Verfasser der verwendeten Version)
' **** Die call32-Funktionalitäten werden von 2 Deklarationszeilen bereitgestellt: ****
Declare Function Declare32 Lib "call32.dll" (ByVal Func As String, ByVal Library As String, ByVal Args As String) As Long
Declare Sub FreeCall32IDs Lib "call32.dll" ()
' **** Alle 32-Bit-Aufrufe erfolgen immer gegen die Lib "call32.dll" mit dem Alias "Call32". ****
Declare Function GetFileAttributesA Lib "call32.dll" Alias "Call32" (ByVal lpFileName As String, ByVal lngdAdditionalAufrufId As Long) As Long
' **** Die Aufrufe werden in Prozeduren gefasst, da sie von zusätzlichem Code begleitet werden müssen. ****
' Das Ganze läuft immer nach folgendem Schema ab:
' Ein Aufruf gegen declare32 holt mit Nennung von API-Prozedur-, Bibliotheksname und Parametertypen-
' Ankündigung ("i" 32 bit integer oder handle, "p" pointer type, "w" als 16- oder 32-bit HWND)
' eine Aufruf-Id als Long ab.
' CODE: lngAufrufId = Declare32("GetFileAttributesA", "kernel32", "p")
' Danach die eigentlich erwünschte Prozedur mit Nennung der Aufruf-Id als zusätzlichen Parameter:
' CODE: lngReturnValue = GetFileAttributesA(sDateiname, lngAufrufId)
' Als letztes erfolgt eine Speicher-aufräumende Anweisung
' CODE: FreeCall32IDs
* * * *
Aufrufe von Funktionen und Sub-Prozeduren:
Voraussetzungen: Es wird vorausgesetzt, daß das aktuelle Arbeitsverzeichnis dem Anwendungsverzeichnis entspricht (falls man die call32.dll nicht in den Windows-Verzeichnissen verteilt).
Daher muß beim Anwendungsstart sichergestellt werden, daß dies der Fall ist:
Dim i As Integer
i = ForceDir(Database_Dir())
* * * *
FILE_EXISTS: Existenz von Dateien (lange Pfadnamen und lange Dateinamen):
Function Exists_File32 (sFile As String) As Integer
On Error GoTo err_Exists_File32
' **** Beherrscht dank call32 langen Pfad- wie auch Dateinamen. ****
Dim iRet As Integer
If GetFileAttributesA_Call32(sFile) > 0 Then
iRet = True
End If
Exists_File32 = iRet
Exit Function
err_Exists_File32:
Fehler "Exists_File32"
Exit Function
End Function
Das stützt sich leicht mißbrauchend auf die 32-Bit-API-Funktion GetFileAttributes:
Function GetFileAttributesA_Call32 (sFile As String) As Long
On Error GoTo err_GetFileAttributesA_Call32
Dim lngAufrufId As Long
lngAufrufId = Declare32("GetFileAttributesA", "kernel32", "p")
' **** Alle erforderlichen sowie die call32-Aufruf-Id als zusätzlichen Parameter ****
GetFileAttributesA_Call32 = GetFileAttributesA(sFile, lngAufrufId)
exit_GetFileAttributesA_Call32:
FreeCall32IDs ' DLL-Aufruf-Speicher aufräumen
Exit Function
err_GetFileAttributesA_Call32:
Fehler "GetFileAttributesA_Call32"
If Err = 53 Then ' evtl. entspricht das aktuelle Arbeitsverzeichnis
Beep ' nicht dem Anwendungs-Verzeichnis, z.B. bei manuellem Start.
MsgBox "Bitte starten Sie die Anwendung auf die dafür vorgesehene Weise.", 64, "GetFileAttributesA_Call32"
Exit Function
End If
Resume exit_GetFileAttributesA_Call32
End Function
allgemein
Quelle: dmt
Datum: 11.2007
API-FUNKTIONEN oder auch 'das ganz große Elend':
Um dem Ärger unzulänglicher Dokumentationen zu entgehen, ist es unbedingt erforderlich Zugriff auf die Datei win32api.txt zu haben !
Das Programmieren mit API-Funktionen empfinde ich allzu oft als obskur bis untragbar.
Teils denke ich, es fehlt mir einfach an Erfahrung, dann bin ich mir wieder sicher: die Typen haben einfach einen an der Waffel. Sicher bin ich schlampig, wenn ich String-Parameter ohne das geforderte abschließende chr$(0)-Zeichen an solche API-Funktionen übergebe - aber da hat es auch noch nie Ärger gegeben. Wenn eine durchgängig mit Integer-Werten arbeitende API-Funktion GetPrivateProfileInt() verspricht, mir zur Sicherheit einen zuvor übergebenen Defaultwert zurückzugeben (selbstverständlich ein Integerwert), dann gucke ich ziemlich dumm aus der Wäsche, wenn auf einmal irrsinnige Long-Werte zurückgegeben werden, wenn z.B. ein ungültiger Section- oder key-Name angegeben wurde.
So was ist einfach Scheiße, wozu dokumentiert ihr Deppen das eigentlich, wenn die Funktionen dann doch machen, was sie wollen ???
Fazit:
Auf vorhandene Funktionen zurückzugreifen, ist eigentlich empfehlenswert.
Das Rad muß beileibe nicht immer wieder neu erfunden werden.
Die Windows-API-Funktionen aber stellen sich mir als echter Kriegsschauplatz dar, mit allem, was an ächtenswertem Zeug dazugehört: 16Bit- und 32Bit-Unverträglichkeiten, DLL-Hölle (so hat es Bill Gates angeblich einmal selbst bezeichnet!), Versionskonflikte zwischen den Betriebssystem-Umgebungen, den Anwendungen und den bezogenen dll-Dateien.
Deswegen: Wenn es sich nicht vermeiden läßt, dann können solche API-Aufrufe brav in Visual-Basic-Funktionen gekapselt werden, in denen dann auch vernünftig Fehler behandelt werden können. Der Umgang mit solchen Basic-Prozeduren ist dann wieder ein Heimspiel.
Vieles von dem, was hier steht, ist teilweise Zeichen meiner Hilflosigkeit und Verzweiflung.
Manches andere, das gerade zu hirnrissig aussieht, hat sich über viele Jahre in verschiedensten Windows-Umgebungen über Kontinente hinweg bravstens bewährt.
carpe diem & fuck the API
* * * *
So gibt z.B. die Funktion GetWindowsDirectory einen 144 Bytes langen String zurück, der hintenraus mit asc(0)-Zeichen gefüllt ist und dessen letztes gültiges Zeichen nicht immer (k)ein Backslash ist: 'C:\' oder auch 'C:\WINDOWS'.
Das wieder so hinzukriegen, daß ein solcher String ver- und auch auswertbar ist, war mal wieder so richtig zum Kotzen:
Alte, umständliche DMT-Lösung:
Private Function CustomizePath (s As String) As String
Dim l As Integer, npos As Integer, i As Integer, c As String
l = Len(s) ' Länge des Parameters
For i = 1 To l ' Die übergebenen
If Asc(Mid$(s, i)) > 0 Then ' Strings werden
c = c + Mid$(s, i, 1) ' Zeichen für Zeichen
Else ' bis zum ersten asc(0)
Exit For ' zusammengebaut und
End If ' nur in dieser Form
Next i ' weiterverwendet
If Right$(c, 1) <> "\" Then ' Letzt. Zeichen '\'?
c = c & "\" ' anhängen
End If ' oder nicht.
CustomizePath = c ' Funktionszuweisung
End Function
Besser:
Dieses Problem kann aber auf sehr einfache Weise durch eine customizte API-Aufruf-Funktion gelöst werden, in der der 144 Byte lange String nur noch exclusive bis zum ersten chr(0) eingelesen wird.
Vorausgesetzt wird die Deklaration:
Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Function API_GetWindowsDirectory () As String
Dim nSize As Integer, x As Integer
Dim lpBuffer As String * 144
nSize = 144
x = GetWindowsDirectory(lpBuffer, nSize)
If x = 0 Then
MsgBox "Funktion fehlgeschlagen !", 16, "API_GetWindowsDirectory"
ElseIf x > nSize Then 'verursacht Schutzverletzung !!
MsgBox "Buffer zu klein !", 16, "API_GetWindowsDirectory"
Else
API_GetWindowsDirectory = Left$(lpBuffer, InStr(lpBuffer, Chr$(0))-1) ' ok
End If
End Function
Ich habe aber auch in irgendeiner mda-Library Code entdeckt, in der der Parameter nSize nach dem Funktionsaufruf (ist wohl neu gesetzt worden) dazu benutzt wurde, die Längenangabe einer Left$-Anweisung zu steuern.
Die Sache mit den API-Strings fester Länge, die dann immer mit ASCII-0-Zeichen aufgefüllt werden, kann auch mit einer Funktion gelöst werden:
Function API_Trim (sBuffer As String) As String
' entferne aus einem per API ermitteltem String die
' verschissenen, rechts angehängten asc(0)-Zeichen.
API_Trim = Left$(sBuffer, InStr(sBuffer, Chr$(0)) - 1)
End Function
Hier wird aber der Fall nicht bedacht, daß der String gar keine chr$(0) enthält.
Bei Microsoft sieht das so aus:
Function GetStringFromSz(sz As String) As String
' **** Bereinige einen chr(0)-terminierten String, der z.B. mit fester Länge ****
' **** deklariert wurde, weswegen ein einfaches Trim$ ausgehebelt würde. ****
Dim i As Integer
i = InStr(sz, Chr$(0))
If i Then
GetStringFromSz = Left$(sz, i - 1)
Else
GetStringFromSz = sz
End If
End Function
Wenn solche Strings nicht mit festen Längen definiert wurden, kann auch einfacher und chr$(0)-tolerant mit RTrim$(Zeichenkette) gearbeitet werden.
Betriebssystem
Quelle: dmt
Datum: 05.2004
Selbst das so "gnädige" Access 2.0 gerät in der Umgebung verschiedener Windows-Versionen (grundsätzlich läuft es problemlos) in die Bredouille.
Beispiel:
Eine Schaltfläche soll ein Datensatz-bezogenes pdf-Dokument öffnen, indem es die entsprechende Anwendung startet.
Die Shell-Befehle müssen aber nach der Windows-Familie unterschieden werden.
Unter Win 9.x ist ein "start ..." angesagt, während ein NT "cmd.exe /C ..." sehen möchte.
Lösung:
Trotz der 16-Bittigkeit von Access 2.0 kann das zuverlässig erledigt werden:
Eine Funktion API_Is_WindowsNT_Running() versucht erst einen Aufruf von GetVersionExA(osinfo) gegen kernel32, ein abfangbarer Fehler versucht es dann noch einmal mit GetVersionEx. Das sollte mit win 95, Win 98, NT 3.51, NT 4 und auch mit Windows XP klappen.
ACHTUNG: Hier ist leider ein Fehler enthalten, denn Aufrufe gegen kernel32 mißlingen aus einer 16-Bit-Anwendung grundsätzlich. Die vorliegende Funktion API_Is_WindowsNT_Running sollte nur solange hier bestehen bleiben, bis an einer XP-Maschine ein echter 32-Bit-Aufruf mit Hilfe von s.a. call32 getestet wurde.
Alleine die Tatsache, daß unter NT die Aufrufe vertauscht werden mußten, deutet auf ein Mißverständnis der Zusammenhänge auf meiner Seite hin !
' **** Datentypen ****
Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBuildNumber As Long
dwPlatformId As Long
szCSDVersion As String * 128
End Type
Declare Function GetVersionExA Lib "kernel32" (lpVersionInformation As OSVERSIONINFO) As Integer
Declare Function GetVersionEx Lib "kernel" (lpVersionInformation As OSVERSIONINFO) As Integer
Beim Betrieb mittels Access 2.0 unter NT 4.0 mußte ich allerdings die Aufrufe von GetVersionEx und GetVersionExA vertauschen.
Function API_Is_WindowsNT_Running () As Integer
On Error GoTo err_API_Is_WindowsNT_Running
Dim osinfo As OSVERSIONINFO, retvalue As Integer
osinfo.dwOSVersionInfoSize = 148
osinfo.szCSDVersion = Space$(128)
retvalue = GetVersionExA(osinfo) ' kernel32
Go_API_Is_WindowsNT_Running:
Select Case osinfo.dwPlatformId
Case 1:
If osinfo.dwMinorVersion = 0 Then
retvalue = False ' "Windows 95"
ElseIf osinfo.dwMinorVersion = 10 Then
retvalue = False ' "Windows 98"
End If
Case 2:
If osinfo.dwMajorVersion = 3 Then
retvalue = True ' "Windows NT 3.51"
ElseIf osinfo.dwMajorVersion = 4 Then
retvalue = True ' "Windows NT 4.0"
End If
Case Else: retvalue = 88
End Select
API_Is_WindowsNT_Running = retvalue
Exit Function
err_API_Is_WindowsNT_Running:
If Err = 53 Then
retvalue = GetVersionEx(osinfo) ' kernel, aber hier scheint XP ein 1 zu melden
GoSub Go_API_Is_WindowsNT_Running
Else
Fehler "API_Is_WindowsNT_Running"
Exit Function
End If
End Function
und hier die User-Routine:
Function Show_DokuDatei (sFile As String)
On Error GoTo err_Show_DokuDatei
Dim v As Variant, sOrgDir As String
If API_Is_WindowsNT_Running() Then
' ACHTUNG: NT 4 meldet -1=True, XP hingegen 1, deswegen das schlampige "If ...() Then"
v = Shell("cmd.exe /C " & sFile, 7) ' NT
Else
' Das ist wirklich ärgerlich, aber unter Win9x wird im übergeordneten Pfad die
' start.exe angezogen und nicht die in %windir%\command, also machen wir einen Umweg:
sOrgDir = CurDir
ChDir Database_Dir()
v = Shell("start " & sFile, 3) ' Win 9x
ChDir sOrgDir
End If
Exit Function
err_Show_DokuDatei:
Fehler "Show_DokuDatei"
Exit Function
End Function
Desktopverzeichnis
Quelle: dmt
Datum: 03.2004
Wie lautet das DESKTOP-Verzeichnis ?
Aufgrund der immer umfangreicher und schwieriger zu durchdringenden VB-Dokumentation hat es sich bewährt, API-Code-Beispiele im Internet zu suchen.
Das geht wesentlich schneller und funktioniert oft auch direkt in Access-Basic.
' Deklarationen zum Auslesen von Registry-Werten
Private Declare Function RegCloseKey& Lib "ADVAPI32.DLL" (ByVal hKey&)
Private Declare Function RegOpenKeyExA& Lib "ADVAPI32.DLL" (ByVal hKey&, ByVal lpSubKey$, ByVal ulOptions&, ByVal samDesired&, phkResult&)
Private Declare Function RegQueryValueExA& Lib "ADVAPI32.DLL" (ByVal hKey&, ByVal lpValueName$, ByVal lpReserved&, lpType&, lpData As Any, lpcbData&)
Function GetDesktopDir() As String
Const ERROR_SUCCESS = 0&
Const HKEY_CURRENT_USER = &H80000001
Const SYNCHRONIZE = &H100000
Const READ_CONTROL = &H20000
Const STANDARD_RIGHTS_READ = READ_CONTROL
Const KEY_QUERY_VALUE = &H1
Const KEY_ENUMERATE_SUB_KEYS = &H8
Const KEY_NOTIFY = &H10
Const KEY_READ = ((STANDARD_RIGHTS_READ Or KEY_QUERY_VALUE Or KEY_ENUMERATE_SUB_KEYS Or KEY_NOTIFY) And (Not SYNCHRONIZE))
Const REG_SZ = 1
Const nLG As Long = 256
Dim sValue As String * nLG
Dim s As String
Dim hKey As Long
Dim nType As Long
Dim nCR As Long
If (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", 0, KEY_READ, hKey) = ERROR_SUCCESS) Then
If (RegQueryValueExA(hKey, "Desktop", 0, nType, ByVal sValue, nLG) = ERROR_SUCCESS) Then
If (nType = REG_SZ) Then
s = GetStringFromSz(sValue)
End If
End If
nCR = RegCloseKey(hKey)
End If
If s = "" Then
Beep
MsgBox "Das Desktop-Verzeichnis konnte leider nicht ausgelesen werden !", vbInformation, "GetDesktopDir"
Else
GetDesktopDir = s
End If
End Function
Fenster, Größe, Dimensionen
Quelle: dmt
Datum: 03.2004
FENSTERGRÖßE und -POSITION ERMITTELN / Fensterdimensionen:
Yeah, in einem eigenen Tools-Modul als Private Sub hervorragend geeignet zum Ermitteln der ECHTEN Fensterkoordinaten auch von Child-Fenstern, und das auch noch unabhängig von eingeblendeten Symbolleisten, Datensatzmarkierern,
eingestellten Rahmenarten usw.
Als Voraussetzungen müssen definiert sein:
Type RECT ' Datenstruktur für die
Left As Integer ' Eckpunkte eines Fensters
Top As Integer ' -> GetWindowRect
Right As Integer
Bottom As Integer
End Type
und
Declare Sub GetWindowRect Lib "User" (ByVal hWnd As Integer, lpRect As RECT)
Im Direktfenster kann dann ein bequemes GetWindowDimensions "sau" absetzen, die Daten werden samt Nennung der momentanen Ansicht per Debug.Print ausgegeben.
Private Sub GetWindowDimensions (s As String)
On Error GoTo err_GetWindowDimensions
Dim tR As RECT
GetWindowRect Forms(s).hWnd, tR
Debug.Print
Select Case Forms(s).CurrentView
Case 1: Debug.Print "Formularansicht"
Case 2: Debug.Print "Datenblattansicht"
Case 0: Debug.Print "Entwurfansicht"
End Select
Debug.Print
Debug.Print "Pos. abs. in Pixeln"
Debug.Print "Links : " & tR.Left
Debug.Print "Oben : " & tR.Top
Debug.Print "Breite: " & tR.Right - tR.Left
Debug.Print "Höhe : " & tR.Bottom - tR.Top
Debug.Print
Debug.Print "Pos. rel. in Twips"
Debug.Print "MS-Access (Vollbild)"
Debug.Print "Maß Oben korrigiert"
Debug.Print "Links : " & tR.Left * 15
Debug.Print "Oben : " & (tR.Top - 38) * 15 ' Korrektur der Access-Titel- und Menüleiste
Debug.Print "Breite: " & (tR.Right - tR.Left) * 15
Debug.Print "Höhe : " & (tR.Bottom - tR.Top) * 15
Exit Sub
err_GetWindowDimensions:
Fehler "GetWindowDimensions"
Exit Sub
End Sub
Hilfesystem einer Anwendung
Quelle: dmt
Datum: 03.2004
So kommen wir denn nun auch zum Anstoßen der MS-ACCESS-HILFE vom Runtime-Modul aus:
Ebenfalls alles Dreck. Von MS-Access aus kein Problem, funktioniert kontextsensitiv, weil da sensibelste Dinge hineinkompiliert wurden. Aus msarn200.exe heraus geht nix!
Die Suche nach Hilfeaufrufe per API-Funktionen geriet wie üblich zum Desaster, aber auch hier hat sich Hartnäckigkeit gepaart mit der Lizenz zum Abkacken wieder mal ausbezahlt, wenn auch nicht bezahlt gemacht.
Als Voraussetzung eine API-Funktion:
Declare Function WinHelp Lib "User" (ByVal hWnd As Integer, ByVal lpHelpFile As String, ByVal wCommand As Integer, dwData As Any) As Integer
und dann das:
Function API_WinHelp (s As String)
On Error GoTo err_API_WinHelp
Dim l As Long, sFile As String
sFile = Database_Dir() & "\msacc20.hlp" ' Helpfile
Const HELP_QUIT = &H2 ' Terminate help
Const HELP_CONTENTS = &H3 ' Display Help for a particular topic
Const HELP_PARTIALKEY = &H105 ' Display topic found in keyword list
l = GetActiveWindow()
Select Case s
Case "Contents": l = WinHelp(l, sFile, HELP_CONTENTS, Null)
Case "Search": l = WinHelp(l, sFile, HELP_PARTIALKEY, 0)
Case "Quit": l = WinHelp(l, sFile, HELP_QUIT, Null)
Case Else: Beep
MsgBox "Ungültiger Parameter '" & s & "'", 16, "API_WinHelp"
Exit Function
End Select
If l = 0 Then
Beep
MsgBox "Mißlingen einer WinHelp-API-Funktion mit Parameter '" & s & "'", 16, "API_WinHelp"
End If
Exit Function
err_API_WinHelp:
Fehler "API_WinHelp"
Exit Function
End Function
Nur Ärger, aber immerhin kann man jetzt wenigstens die Hilfeoptionen des ?-Menüs imitieren, soll heißen Inhalt, Suchen und Ende. Der Suchedialog kann sogar unabhängig vom Hilfefenster geöffnet werden. ALLE eingehenderen Manipulationen
anhand der beschissenen API-Dokumentation müssen als Griff ins Klo bezeichnet werden.
Daß die Steuerung einerseits über eine Basic-Funktion und andererseits über Access-Makros erfolgt, sieht uneinheitlich aus, hat aber bei der Menü-Programmierung und spätestens bei einer ?-Symbolleisten-Schaltfläche leichte Vorteile und man erspart sich dummes Funktions-Rückgabe-Gechecke. Obendrein kommt nach dem WinHelp-Makro-Waterloo der Dokumentation fast ein leicht gehässiges Triumphgefühl auf, wenn es im Code heißt:
DoCmd RunMacro "Hilfe.Beenden"
Die Anwendung, die die Hilfe angefordert hat, sollte spätestens bei ihrer Beendigung auch diesen Quit-Befehl absetzen, da sonst irgendwelche Tracking-Resourcen offen bleiben.
Nach offizieller Lesart können auch standardisierte Hilfeeinträge in den zur Anwendung gehörenden Ini-Dateien gemacht werden. Von 74 ini-Dateien gaben immerhin doch 3 Stück was zu dem Thema her:
Bei Excel und Winword (beide 16-Bit) heißt es:
[Help]
XLREADME.HLP=C:\WINDOWS\EXCEL5\XLINFO.HLP
[Help]
WINWORD.HLP=C:\WINDOWS\WINWORD6\WINWORD.HLP
WRDBASIC.HLP=C:\WINDOWS\WINWORD6\WRDBASIC.HLP
Oracle macht das dann wieder anders:
MSHELP=G:\ORAWIN\mshelp
Aber woher weiß ich, wie der Name der xyz-Datei lauten muß, damit die Anwendung darauf anspringt ?
Obendrein gibt es auch noch eine winhelp.ini, in der nur so Einträge drinstehen.
Ich glaube, DIE wissen selber nicht, was das Ganze eigentlich soll.
Klar, daß auch eine direkte, explizite Zuweisung einer Hilfedatei in der entsprechenden Formulareigenschaft zu KEINEM Ergebnis führt (Pfade hin oder her).
hWnd
Quelle: dmt
Datum: 04.2006
HWND oder willst Du HANDLE oder einen HANDLER ?
Tausendmal probiert und immer wieder auf die Schnauze gefallen:
Der hWnd eines Access-Fensters kann mit Form.hWnd simpel ermittelt werden. Oft muß aber der Handle der Access-Anwendung herhalten und da gab's dann schon übelste Sachen mit absturzfreudigen Temp_Modal-Fenstern und so Sachen.
Alles Dreck:
Geh'n tut's mit GetActiveWindow(),
Declare Function GetActiveWindow Lib "User" () As Integer
aber bitte schön innerhalb der Anwendung und nicht vom Visual-Basic-Direktfenster aus.
Menüeinträge
Quelle: dmt
Datum: 03.2004
MENÜEINTRÄGE per API-Funktionen prüfen:
Fast hätte es geklappt; geplant war das Ermitteln des Zustandes der Formular-Menü Datei-Einstellung 'Seitenansicht', um eine Druckanforderung entweder erst anzuzeigen oder danach an den Drucken-Dialog weiterzureichen.
Leider mußte festgestellt werden, daß beim Bedienen dieser Druckanforderung per Symbol-leiste veraltete Menüwerte ermittelt wurden, während hingegen beim Aufklappen des Menüs natürlich die richtigen Einstellungen angezeigt und auch
ermittelt werden.
Deswegen die Doku sowie die Contraprogrammierung der Contraprogrammierung hier nur der Vollständigkeit halber:
An API-Deklarationen benötigt werden:
Declare Function GetActiveWindow Lib "User" () As Integer
Declare Function GetMenu Lib "User" (ByVal hWnd As Integer) As Integer
Declare Function GetSubMenu Lib "User" (ByVal hMenu As Integer, ByVal nPos As Integer) As Integer
Declare Function GetMenuState Lib "User" (ByVal hMenu As Integer, ByVal wId As Integer, ByVal wFlags As Integer) As Integer
Abgecheckt wird das durch folgende Funktion:
Function Check_Seitenansicht ()
On Error GoTo err_Check_Seitenansicht
Dim iHandle As Integer
Const MF_BYPOSITION = &H400
Const MF_CHECKED = &H8
Const GECHECKED = 88
iHandle = GetActiveWindow() ' Handle auf Anwendung
iHandle = GetMenu(iHandle) ' Handle auf Anwendungsmenu
iHandle = GetSubMenu(iHandle, 1) ' Handle auf erste Menüoption
' **** wenn's denn tut, ist 88 scheinbar der IsChecked-Wert ****
If GetMenuState(iHandle, 1, MF_BYPOSITION) & MF_CHECKED = GECHECKED Then
Check_Seitenansicht = True
End If
Exit Function
err_Check_Seitenansicht:
Fehler "Check_Seitenansicht"
Exit Function
End Function
Da das aber typischerweise in die Pulldown-heruntergelassenen Hosen ging, hier
nun die breitenbüchersche Arschloch-Contra-Programmierung:
Function Check_Seitenansicht (sForm As String)
On Error GoTo err_Check_Seitenansicht
' **** Im Rahmen einer Contraprogrammierung wird hier ****
' **** der positive Funktionswert erst nach Auftreten ****
' **** eines speziellen Fehlers zugewiesen, da das ****
' **** beinahe erfolgreiche API-Programming durch in- ****
' **** differente Symbolleisten/Menüleisten nicht ak- ****
' **** tualisiert-Scheisse wieder abgehakt wurde. ****
Forms(sForm).Repaint
Exit Function
err_Check_Seitenansicht:
If Err = 2478 Then
Check_Seitenansicht = True
Else
Fehler "Check_Seitenansicht"
End If
Exit Function
End Function