Announcement

Collapse
No announcement yet.

"Speichern unter"-Dialog abfangen

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • "Speichern unter"-Dialog abfangen

    Hallo,<br>
    Ich möchte ein Tool schreiben, welches beim Aufruf des "Speichern unter"-Dialogs von Windows ein eigenes Formular aufgehen läßt anstelle des "Speichern unter"-Dialogs. Der "Speichern unter"-Dialog soll dann allerdings von meinem Formular aus aufrufbar sein.<br>
    Um das ganze ein wenig zu erläutern...<br>
    Es geht hier grundsätzlich um Immobilienverwaltung; wenn bspw. ein Rundschreiben verfaßt wird an alle Mieter des Objekts 001, dann soll dieses Rundschreiben gespeichert werden im Ordner h:\Document\Rundschreiben\001, der Anwender selbst soll lediglich einen Dateinamen eingeben und über eine Combobox auswählen, um welches Objekt es sich handelt. Das Verzeichnis wird dann von meinem Tool gewählt und nicht mehr vom Anwender.<br>
    Mein Tool müßte also... <br>
    1. ...benachrichtigt werden, wenn aus irgendeiner Anwendung heraus der "Speichern unter"-Dialog aufgerufen wird (dürfte eine simple Windowsmessage sein, ich weiß nur nicht, welche)<br>
    2. ...das Erscheinen des "Speichern unter"-Dialogs unterbinden<br>
    3. ...wissen, welche Dateitypen der "Speichern unter"-Dialog angeboten hätte und<br>
    4. ...der Anwendung mitteilen, daß die aktuelle Datei unter Pfad xyz zu speichern ist - ich frage in meinen Anwendungen immer die Property FileName des "Speichern unter"-Dialogs ab, diese Property müßte man also nachträglich setzen und außerdem den Rückgabewert der Funktion TSaveDialog.execute manipulieren.<br>
    <br>
    Die obligatorischen zwei Fragen:<br>
    1. Geht das überhaupt? und<br>
    2. Wenn ja, wie?<br>
    <br>
    Danke<br>
    Patrick

  • #2
    Hallo,

    &gt;..dürfte eine simple Windowsmessage sein, ich weiß nur nicht, welche..

    nein - jede Anwendung ruft direkt die Win32-API-Funktion <b>GetSaveFileName</b> auf, die ihrerseiten den Standard-Dialog aus <i>comdlg32.dll</i> anzeigt. Im Fall von Delphi kapselt die VCL-Komponente diese API-Funktion ein, wobei je nach Konfiguration der alte bzw. neu Weg genutzt wird.

    &gt;..außerdem den Rückgabewert der Funktion TSaveDialog.execute ..

    Soll nur die eigene (im Sourcecode vorliegende) Anwendung auf diesem Weg kontrolliert werden oder soll das global für das komplette System gelten

    Comment


    • #3
      Hallo,

      >>..dürfte eine simple Windowsmessage sein, ich weiß nur nicht, welche..

      > nein ...

      Es geht doch, Andreas. Dazu muß "nur" die Adresse für den Funktionsaufruf im Adressbereich der Zielanwendung umgebogen werden. :-)<br>
      Für das Umbiegen einer WinAPI-Funktion in der eigenen Anwendung hab ich das schon mal gemacht.

      Relativ einfach ist dies Möglich mit der PeImportHooks.HookImport-Methode aus der Jedi (http://sourceforge.net/projects/jcl) möglich (VCS snapshots laden, da offizieles Release hier noch 'nen Buck hat). Hab damit schon mal die GetModuleHandle-Funktion aus der Win-API für eine geladene DLL auf eine eigene Funktion umgebogen.

      Eine systemweite Lösung ist natürlich eine ziemliches Arbeit, da hier ein permanent laufende Anwendung (Systemdienst)? geschrieben werden muß, welche beim Start jeder Anwendung diese entsprechend "Behandelt". Und ob da nicht irgendwann ein Virenscanner deine Anwendung als "Virus" betrachten

      Comment


      • #4
        Hallo Bernhard,

        genau das (Stichwort "Injekt-DLL") wollte ich vermeiden, damit wird schon jetzt genug Unsinn angestellt :-)

        Eine einfache Win32-API-Funktion wie zum Beispiel <b>MessageBox</b> geht ja ganz einfach:
        <pre>
        <b>uses</b>
        JclPeImage;

        <b>type</b>
        THookMessageBox = <b>function</b>(hWnd: HWND; lpText, lpCaption: PChar;
        uType: UINT): Integer; <b>stdcall</b>;

        <b>var</b>
        OrgMessageBox : THookMessageBox = <b>nil</b>;

        <font color="#003399"><i>{------------------------------------------------------------}</i></font>
        <font color="#003399"><i>{ Neue Fassung der Win32-API-Funktion MessageBox }</i></font>
        <font color="#003399"><i>{------------------------------------------------------------}</i></font>

        <b>function</b> NewMessageBox(hWnd: HWND; lpText, lpCaption: PChar;
        uType: UINT): Integer; <b>stdcall</b>;
        <b>begin</b>
        MessageBeep(0);
        Result := MessageDlg(lpText, mtInformation, [mbYes], 0);
        MessageBeep(0);
        <b>end</b>;

        <b>procedure</b> TForm2.ButtonHookClick(Sender: TObject);
        <b>begin</b>
        <b>if</b> PeImportHooks.HookImport(Pointer(HInstance), user32, <font color="#9933CC">'MessageBoxA'</font>,
        @NewMessageBox, @OrgMessageBox) <b>then</b>
        StatusBar1.SimpleText := <font color="#9933CC">'API-Funktion MessageBox wurde ausgetauscht.'</font>;
        <b>end</b>;

        <b>procedure</b> TForm2.ButtonMessageBoxClick(Sender: TObject);
        <b>begin</b>
        MessageBox(Handle, <font color="#9933CC">'Text aus dem Client'</font>, <font color="#9933CC">'Test'</font>, 0);
        <b>end</b>;

        <b>procedure</b> TForm2.ButtonUnHookClick(Sender: TObject);
        <b>begin</b>
        <b>if</b> PeImportHooks.UnhookByNewAddress(@NewMessageBox) <b>then</b>
        <b>begin</b>
        @OrgMessageBox := <b>nil</b>;
        StatusBar1.SimpleText := <font color="#9933CC">''</font>;
        <b>end</b>;
        <b>end</b>;
        </pre>
        Aber im Fall von GetSaveFileName haben wir es mit einer komplexen Struktur zu tun, die korrekt gefüllt/behandelt werden muss und die es auch noch in mehreren Ausführungen (je Windows-Version und gesetztem Flag) gibt. Wenn der Austausch auch für "wildfremde" Anwendungen gelten soll, muss das Verhalten der originalen Funktion in Bezug auf die Struktur zu 100% simuliert werden. Der Aufwand ist entsprechend hoch.

        Einfacher und sicherer ist hingegen das Überwachen des Dateisystem (FindFirstChangeNotification), um sich vom Betriebssystem die neu angelegte/geänderte Datei "melden" zu lassen. Das Programm kann dann die Datei an die richtige Stelle kopieren und das "falsche" Original löschen

        Comment


        • #5
          Hallo Andreas,

          das stimmt. Es ist mit sicherheit für den SaveDialog sehr schwierig. Und wahrscheinlich würde eine Implementierung (für allgemeingültige Lösung) über den Daumen gepeilt ca. 4-8 Wochen benötigen um die meißten Fallstricke zu beseitigen.

          Die Idee mit der Dateisystemüberwachung ist nicht schlecht. Dürfte auch in wenigen Tagen zu lösen sein und zusätzlich evtl. mit einem Dialog verknüpft der entsprechend erscheint um auf die Aktionen hinzuweisen dürfte das evtl. auch verständlicher sein

          Comment


          • #6
            Zeit spielt keine so große Rolle, es muß nicht in den nächsten Tagen fertig sein...<br>
            <br>
            Die Dateisystemüberwachung mag einfacher zu lösen sein, aber da sträube ich mich irgendwie gegen. Angenommen, der Anwender schreibt einen Text und speichert ihn unter h:\Rundschreiben.doc, dann würde mein Tool das bemerken und einen zweiten Dialog aufgehen lassen, wo der Anwender noch einmal wählen muß, mit was für einem Datensatz aus der Immobilienverwaltungssoftware diese Datei denn verknüpft werden soll. Dann würde mein Tool die Datei an die entsprechende Stelle kopieren und versuchen, das Original zu löschen - das schlägt aber fehl, weil das Original ja noch in Bearbeitung ist.<br>
            Abgesehen davon, daß dadurch das Dateisystem so langsam zugemüllt wird, würde es mich als Anwender auch ziemlich nerven, immer zwei Dialoge zu bekommen.<br>
            Wenn ich das mit dem SaveDialog nicht hinbekommen sollte, lasse ich es eher ganz bleiben (war eigentlich auch nur so nebenbei gedacht, das ist kein sooo wichtiges Projekt).<br>
            Was die Sache noch erschweren dürfte, ist, daß ich den SaveDialog gar nicht überschreiben möchte, ich möchte anstelle des SaveDialogs einen anderen Dialog aufgehen lassen, von dem aus der Anwender dann ggbf. (bspw. bei privatem Schriftverkehr) noch den SaveDialog aufrufen kann...<br>
            Wenn das nicht gehen sollte, dann geht's halt nicht...<br>
            <br>
            Trotzdem Danke<br>
            Patric

            Comment


            • #7
              Hallo Patrick,

              dann ist mein erster Vorschlag richtig. Aber hat mit sehr hohen aufwand Verbunden.

              Und ob er bis in die letzte Konsequenz durchzuführen ist ...

              Comment

              Working...
              X