infobase: EDV - MS-Access


API

32-Bit Aufrufe aus Access 2.0   Datum: 02.2006   nach oben

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   nach oben

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   nach oben

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   nach oben

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   nach oben

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   nach oben

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   nach oben

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   nach oben

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

nach oben
zur Startseite dieses Webangebotes zur infobase-Hauptseite