Announcement

Collapse
No announcement yet.

Ereignis aus Excel

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

  • Ereignis aus Excel

    Ich hätte folgendes Problem zu lösen:Aus meinem Delphi Programm wird Excel
    gestartet.In Excel hat der Anwender die Möglichkeit mit Speichern / Speichern unter die Excel Datei zu speichern.Das muss ich abfangen. Wie kann mann das Ereignis abfangen ?? oder alternativ: kann mann die beiden Menueeintraege ausblenden ??

  • #2
    Hallo,

    wenn der Zugriff über die VCL-Wrapperkomponenten von Delphi (TExcelApplication und TExcelWorkbook) erfolgt, kann man folgendes machen. In der Ereignisbehandlungsmethode für <b>OnBeforeSave</b> wird Excel mitgeteilt, dass das Speichern nicht zulässig ist:
    <pre>
    procedure TForm1.ExcelWorkbook1BeforeSave(Sender: TObject;
    SaveAsUI: WordBool; var Cancel: OleVariant);
    begin
    Cancel := True; // oder Cancel := -1;
    end;
    </pre>
    Aufgrund eines uralten Delphi-Bugs funktionert das jedoch erst mit Delphi 7. Wenn mit Delphi 5 oder 6 gearbeitet wird, darf man die Borland-Wrapperkomponenten auf der Registerseite <i>Servers</i> <b>nicht</b> verwenden, sondern muss eigene über das FreeWare-Tool <i>EventSinkImp.exe</i> anlegen (denn dort werden die Komponenten fehlerfrei generiert)

    Comment


    • #3
      Programm läuft folgendermaßen ab:
      - Excel Datei wird auf der DB auf dem Server ausgewählt
      - Excel Datei wird auf Client in Ordner geladen
      - Aufruf "Excel anzeigen":
      var
      vExcel: OleVariant;
      vExcel := CreateOleObject ('Excel.Application');

      vExcel.Workbooks.Open ('Excel Datei aus Ordner');

      - Excel wird angezeigt
      - Benutzer kann Daten im Excel ändern
      Problem: Abfangen des Speicherns - denn Dokument soll nur auf DB auf Server gespeichert werden

      Ich arbeite mit Delphi 5 Enterprise u. benutze die Komponenten der Registerseite Server nicht!
      Delphi 7 kann ich leider auch nicht bekommen und Freeware - Komponenten dürfen bei uns nicht eingesetzt werden.

      Für eine Lösung meines Problems wäre ich sehr dankba

      Comment


      • #4
        Hallo,

        &gt;Für eine Lösung meines Problems wäre ich sehr dankbar

        ein Umstieg auf Visual Basic 6 kommt wohl nicht in Frage - dort wäre das mit der Zeichenkette "With Events" erledigt :-)

        Mit Delphi bleibt nur die harte Tour übrig, man muss die <b>ConnectionPoint</b>-Schnittstelle in der eigenen Anwendung in eigener Regie implementieren. In meinem Buch <i>ADO und Delphi</i> habe ich das zur "Abschreckung" einmal in einem Beispielprojekt gemacht:

        1. Eigenes COM-Objekt von <b>TInterfacedObject</B> ableiten und dort das <b>ConnectionEventsVt</b>-Interface implementieren.

        2. Nachdem ich das Interface ConnectionEventsVt von Hand der Class-Deklaration hinzugefügt habe, kopiere ich alle Interface-Methoden dieses Interfaces aus der Unit ADOInt in die Zwischenablage und füge diese Deklarationen in die eigene Formular-Deklaration ein. Außerdem benötigte ich noch zwei private Objektfelder für die Verwaltung der ConnectionPoint-Schnittstelle:
        <pre>
        type
        TFormMain = class(TForm, ConnectionEventsVt)
        ButtonConnect: TButton;
        Label1: TLabel;
        EditUserName: TEdit;
        EditPasswd: TEdit;
        Label2: TLabel;
        StatusBar1: TStatusBar;
        MemoLog: TMemo;
        Label3: TLabel;
        procedure ButtonConnectClick(Sender: TObject);
        private
        { Private-Deklarationen }
        FConnEventsID : Integer;
        FICP : IConnectionPoint;
        public
        { ConnectionEventsVt-Deklarationen }
        procedure InfoMessage(const pError: Error;
        var adStatus: EventStatusEnum;
        const pConnection: _Connection); safecall;
        procedure BeginTransComplete(TransactionLevel: Integer;
        const pError: Error;
        var adStatus: EventStatusEnum;
        const pConnection: _Connection); safecall;
        procedure CommitTransComplete(const pError: Error;
        var adStatus: EventStatusEnum;
        const pConnection: _Connection); safecall;
        procedure RollbackTransComplete(const pError: Error;
        var adStatus: EventStatusEnum;
        const pConnection: _Connection); safecall;
        procedure WillExecute(var Source: WideString;
        var CursorType: CursorTypeEnum;
        var LockType: LockTypeEnum; var Options: Integer;
        var adStatus: EventStatusEnum; const pCommand: _Command;
        const pRecordset: _Recordset;
        const pConnection: _Connection); safecall;
        procedure ExecuteComplete(RecordsAffected: Integer;
        const pError: Error;
        var adStatus: EventStatusEnum; const pCommand: _Command;
        const pRecordset: _Recordset;
        const pConnection: _Connection); safecall;
        procedure WillConnect(var ConnectionString: WideString;
        var UserID: WideString;
        var Password: WideString; var Options: Integer;
        var adStatus: EventStatusEnum;
        const pConnection: _Connection); safecall;
        procedure ConnectComplete(const pError: Error;
        var adStatus: EventStatusEnum;
        const pConnection: _Connection); safecall;
        procedure Disconnect(var adStatus: EventStatusEnum;
        const pConnection: _Connection); safecall;
        end;
        </pre>

        3. Wenn das erledigt ist, sorge ich über die Tastenkombination STRG+SHIFT+C dafür, dass Delphi die Methodenrümpfe für die Interfacemethoden von ConnectionEventsVt anlegt. Dort trage ich jeweils die Aufrufe für das Mitprotokollieren der Events über die TMemo-Instanz ein. Was jetzt noch fehlt, ist der Verbindungsaufbau zwischen den beiden ConnectionEventsVt-Schnittstellen des Connection-Objekts und meines Formulars. Dazu muss ich das umsetzen, was COM für ein ConnectionPoint-Interface vorschreibt. Nachdem ich die Instanz des Connection-Objekts über den Aufruf der CoConnection-Methode Create erzeugt habe, fordere ich diese Instanz des Connection-Objekts auf, mir einen Interface-Zeiger auf das IConnectionPointContainer-Interface zurückzuliefern. Dieser Container ist das Verwaltungsobjekt für ConnectionPoints, so dass sich jeder Interessent dort anmelden muss. Wenn ein gültiger Interface-Zeiger auf den Container vorliegt, kann ich dort nach dem speziellen Interface-Zeiger für die ConnectionEvents fragen. Liefert die Methode FindConnectionPoint einen gültigen Interface-Zeiger zurück, melde ich das COM-Objekt in meinem Formular über die Methode Advise als Kunde dieses ConnectionPoint-Interfaces an. Am Ende sorgt der Aufruf von Unadvise dafür, dass das Connection-Objekt seine Verbindung zu meinem Formular-Objekt wieder freigibt.
        <pre>
        procedure TFormMain.ButtonConnectClick(Sender: TObject);
        var
        aCon : _Connection;
        aICPC : IConnectionPointContainer;
        begin
        aCon := CoConnection.Create;
        aCon.CursorLocation := adUseClient;
        // Connection Point aktivieren
        OleCheck(aCon.QueryInterface(IConnectionPointConta iner, aICPC));
        OleCheck(aICPC.FindConnectionPoint(DIID_Connection Events,FICP));
        // Treffer ?
        if(FICP <> nil) then
        OleCheck(FICP.Advise(Self, FConnEventsID))
        else
        MemoLog.Lines.Add('ConnectionEvents wurden nicht gefunden');
        aCon.Open(cCS, EditUserName.Text, EditPasswd.Text,
        adConnectUnspecified);
        aCon.Close;
        // eventuell aktiven Connection Point deaktivieren
        if(FICP <> nil) then FICP.Unadvise(FConnEventsID);
        FICP := nil;
        aCon := nil;
        end;
        </pre>
        4. Immer dann, wenn das Connection-Objekt eine über die Methode Execute abgeschickte Anweisung ausgeführt hat, löst es das Event ExecuteComplete aus. Mein Beispielprojekt wertet dieses Event aus, wobei zuerst im Parameter adStatus nachgesehen wird, ob alles gut gegangen ist. Finde ich nicht den Wert adStatusOk vor, ist die Ausführung fehlgeschlagen, so dass der Parameter pError einen Interface-Zeiger auf das zuständige Error-Objekt enthält.
        <pre>
        procedure TFormMain.ExecuteComplete(RecordsAffected: Integer;
        const pError: Error; var adStatus: EventStatusEnum;
        const pCommand: _Command; const pRecordset: _Recordset;
        const pConnection: _Connection);
        begin
        MemoLog.Lines.Add(' -> Connection-Event ExecuteComplete');
        if adStatus <> adStatusOK then begin
        if adStatus = adStatusErrorsOccurred then
        MemoLog.Lines.Add('adStatus: adStatusErrorsOccurred');
        MemoLog.Lines.Add('Error.Description: '+pError.Description);
        end;
        end;
        </pre>

        P.S: Sie sehen - der Aufwand ist gewaltig. Ich würde an Ihrer Stelle die notwendigen Units doch mit dem FreeWare-Tool EventSinkImp.exe <b>automatisch</b> zusammenbauen lassen. Danach wird das Tool nicht mehr benötigt - es ist nur ein Sourcecode-Generator

        Comment


        • #5
          Danke für ihre Antwort , ich werde es wohl auf die harte Tour probieren

          Comment

          Working...
          X