Donnerstag, 3. Januar 2008

Beliebige Dateien über assoziierte Anwendung öffnen / Opening any file with its associated application

Um externe Anwendungen zu starten stellt Visual FoxPro den Befehl RUN zur Verfügung.

Wenn wir jedoch nicht wissen, wie die Anwendung genau heisst oder wo sie liegt, dann führt meist kein Weg an ShellExecute vorbei.

Dieses von shell32.dll bereitgestellte Interface ermöglicht uns ein recht flexibles Handling mit Dateien und den damit assoziierten Anwendungen.

Bevor wir mit ShellExecute arbeiten können, ist die Deklaration der Schnittstelle notwendig.

Bereitgestellt werden insgesamt sechs Parameter.

hwndParent  Fensterhandle (benötigt bei Fehlermeldungen)
cVerb       Funktionsbezeichner (open,print,printto,edit,explore,find)
cFilename   Dateiname oder URL
cParameters Zu übergebende Parameter
cDirectory  Arbeitsverzeichnis
nCmdShow    Anzeigevariante

Parameter #6 können wir wahlweise als numerischen Wert oder als deklarierte Konstante übergeben. Im u.a. Beispielcode findet sich die entsprechende Deklaration direkt zu Anfang. Definieren wir die Funktion ShellExecute als Integer, so liefert sie einen numerischen Rückgabewerte. Liegt dieser über 32 dann wurde die Operation erfolgreich ausgeführt. Andernfalls sollten wir anhand der folgenden Liste eine entsprechende Info ausgeben:

Konstante               Beschreibung                                  Wert
SE_ERR_FNF              Die Datei wurde nocht gefunden                   2
SE_ERR_PNF              Der Pfad wurde nicht gefunden                    3
SE_ERR_ACCESSDENIED     Das OS verweigerte den Zugriff auf die Datei     5
SE_ERR_OOM              Nicht genügend Arbeitsspeicher                   8
ERROR_BAD_FORMAT        Die .exe Datei hat ein ungültiges Format        11
                        (keine Win32 .exe oder Fehler in Datei)
SE_ERR_SHARE            Zugriffsverletzung bei Mehrfachnutzung          26
SE_ERR_ASSOCINCOMPLETE  Das Suffix ist unvollständig oder ungültig      27
SE_ERR_DDETIMEOUT       DDE Transaction wegen Timeout abgebrochen       28
SE_ERR_DDEFAIL          Die DDE Transaction schlug fehl                 29
SE_ERR_NOASSOC          Keine assoziierte Applikation für das Suffix    31
                        (Erscheint auch bei nicht druckbaren Dateien)
SE_ERR_DLLNOTFOUND      Die spezifizierte DLL wurde nicht gefunden      32

Der folgende Beispielcode zeigt vier verschiedene Möglichkeiten für den Umgang mit ShellExecute auf. Um den u.a. Code auszuprobieren genügt es, in VFP ein neues PRG anzulegen und den markierten Code über die Zwischenablage einzufügen.

#DEFINE SW_HIDE             0
#DEFINE SW_SHOWNORMAL       1
#DEFINE SW_NORMAL           1
#DEFINE SW_SHOWMINIMIZED    2
#DEFINE SW_SHOWMAXIMIZED    3
#DEFINE SW_MAXIMIZE         3
#DEFINE SW_SHOWNOACTIVATE   4
#DEFINE SW_SHOW             5
#DEFINE SW_MINIMIZE         6
#DEFINE SW_SHOWMINNOACTIVE  7
#DEFINE SW_SHOWNA           8
#DEFINE SW_RESTORE          9
#DEFINE SW_SHOWDEFAULT      10
#DEFINE SW_FORCEMINIMIZE    11

* // Deklaration der benötigten Arbeitsvariablen
LOCAL    llExistsErrorCrs as Boolean, llDeclareStatus as Boolean, ;
        lcTyp as String, lcFile as String, lcPrinter as String, ;
        lcMailto as String, lcSubject as String, lcBody as String, ;
        liHwndMain as Integer, liReturn as Integer
       
* // Variablen initialisieren
liHwndMain            = _SCREEN.HWnd
llExistsErrorCrs    = CreateErrorCursor()
llDeclareStatus        = DeclareShellExec()
STORE [] TO lcTyp, lcFile, lcPrinter, lcMailto, lcSubject, lcBody
STORE 0  TO liReturn

* // Wenn sowohl die Cursorerstellung als auch die Deklaration
* // von ShellExec funktioniert hat, dann kann es jetzt losgehen
IF llDeclareStatus AND llExistsErrorCrs

    * // Beispiel 1 ---------------------
    * // Öffnet das Standard-Mailprogramm
    IF MESSAGEBOX([EMail-Erstellung testen?],4+32+0,[Abfrage]) = 6
        lcMailto    = [mailto:mustermann@musterdomaene.de]
        lcSubject    = [?Subject=EMail Test]
        lcBody        = [&Body=Hallo Welt]
        liReturn    = ShellExecute(liHwndMain,[open],lcMailto + lcSubject + lcBody,[],[],SW_SHOWNORMAL)
        IF liReturn <= 32
            ShowErrorMessage(liReturn)
        ENDIF
    ENDIF
   
    * // Beispiel 2 ---------------------
    * // Öffnet das assoziierte Programm zum ausgewählten Dateityp
    IF MESSAGEBOX([Starten einer assoziierten Applikation testen?],4+32+0,[Abfrage]) = 6
        lcTyp        = [Dokument:doc;Text:txt;Tabelle:xls;Grafik:jpg,bmp,tif,gif,png]
        lcFile        = GETFILE(lcTyp,[Auswählen],[Öffnen],1,[Datei auswählen])
        IF FILE(lcFile)
            liReturn = ShellExecute(liHwndMain,[open],lcFile,[],[],SW_SHOWNORMAL)
            IF liReturn <= 32
                ShowErrorMessage(liReturn)
            ENDIF
        ENDIF
    ENDIF
   
    * // Beispiel 3 ---------------------
    * // Druckt die ausgewählte Datei über das assoziierte Programm zum ausgewählten Dateityp
    IF MESSAGEBOX([Druckausgabe testen?],4+32+0,[Abfrage]) = 6
        lcTyp        = [Dokument:doc;Text:txt;Tabelle:xls;Grafik:jpg,bmp,tif,gif,png]
        lcFile        = GETFILE(lcTyp,[Auswählen],[Öffnen],1,[Datei auswählen])
        lcPrinter    = GETPRINTER()
        IF FILE(lcFile)
            liReturn = ShellExecute(liHwndMain,[printto],lcFile,["] + lcPrinter + ["],[],SW_HIDE)
            IF liReturn <= 32
                ShowErrorMessage(liReturn)
            ENDIF
        ENDIF
    ENDIF
   
    * // Beispiel 4 ---------------------
    * // Öffnet den Standard-HTML-Editor um die ausgewählte Datei zu bearbeiten
    IF MESSAGEBOX([Öffnen des HTML-Editors testen?],4+32+0,[Abfrage]) = 6
        lcTyp        = [HTML:htm,html;ASP:asp;PHP:php;PYTHON:py;STYLESHEET:css]
        lcFile        = GETFILE(lcTyp,[Auswählen],[Öffnen],1,[Datei auswählen])
        IF FILE(lcFile)
            liReturn = ShellExecute(liHwndMain,[edit],lcFile,[],[],SW_SHOWNORMAL)
            IF liReturn <= 32
                ShowErrorMessage(liReturn)
            ENDIF
        ENDIF
    ENDIF
   
ENDIF

* // Freigeben der Ressourcen
llDeclareStatus    = ClearShellExec()

USE IN SELECT([crsError])

RELEASE llExistsErrorCrs, llDeclareStatus, ;
        lcTyp, lcFile, lcPrinter, ;
        lcMailto, lcSubject, lcBody, ;
        liHwndMain, liReturn

* //----------------------------//
FUNCTION CreateErrorCursor
    LOCAL llReturn
    * // Error-Cursor erzeugen und befüllen
    TRY
        CREATE CURSOR crsError (iValue I, cInfo c(50))
        INSERT INTO crsError (iValue, cInfo) VALUES ( 2,[Die Datei wurde nocht gefunden])
        INSERT INTO crsError (iValue, cInfo) VALUES ( 3,[Der Pfad wurde nicht gefunden])
        INSERT INTO crsError (iValue, cInfo) VALUES ( 5,[Das OS verweigerte den Zugriff auf die Datei])
        INSERT INTO crsError (iValue, cInfo) VALUES ( 8,[Nicht genügend Arbeitsspeicher])
        INSERT INTO crsError (iValue, cInfo) VALUES (11,[Die .exe Datei hat ein ungültiges Format])
        INSERT INTO crsError (iValue, cInfo) VALUES (26,[Zugriffsverletzung bei Mehrfachnutzung])
        INSERT INTO crsError (iValue, cInfo) VALUES (27,[Das Suffix ist unvollständig oder ungültig])
        INSERT INTO crsError (iValue, cInfo) VALUES (28,[DDE Transaction wegen Timeout abgebrochen])
        INSERT INTO crsError (iValue, cInfo) VALUES (29,[Die DDE Transaction schlug fehl])
        INSERT INTO crsError (iValue, cInfo) VALUES (31,[Keine assoziierte Applikation für das Suffix])
        INSERT INTO crsError (iValue, cInfo) VALUES (32,[Die spezifizierte DLL wurde nicht gefunden])
        llReturn = .T.
    CATCH
        llReturn = .F.
    ENDTRY
    RETURN llReturn
ENDFUNC

* //----------------------------//
FUNCTION ShowErrorMessage
LPARAMETERS vValue as Integer, vExistsErrorCrs as Boolean
    * // Routine zur Ausgabe der SellExecute-Fehlernummer
    SELECT crsError
    GO TOP
    LOCATE FOR iValue = m.vValue
    IF FOUND()
        TEXT TO cString NOSHOW ADDITIVE TEXTMERGE PRETEXT 2
            Fehler #<<crsError.iValue>>
            <<crsError.cInfo>>
        ENDTEXT
        MESSAGEBOX(cString,0+48,0)
    ENDIF
ENDFUNC

* //----------------------------//
FUNCTION DeclareShellExec
    * // Deklaration der API-Funktion 'ShellExecute'
    DECLARE Integer ShellExecute ;
        IN shell32.dll ;
        Integer hwndParent, ;
        String cVerb, ;
        String cFilename, ;
        String cParameters, ;
        String cDirectory, ;
        Integer nCmdShow
    RETURN .T.
ENDFUNC

* //----------------------------//
FUNCTION ClearShellExec
    * // Freigeben der zuvor genutzten API-Funktion
    CLEAR DLLS [ShellExecute]
    RETURN .F.
ENDFUNC

Keine Kommentare:

Kommentar veröffentlichen