Drag Drop, Copy Paste Custom binary Daten

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
HobbyProgrammer
Beiträge: 173
Registriert: Di 29. Okt 2019, 12:51
Wohnort: Deutschland , Baden-Württemberg

Drag Drop, Copy Paste Custom binary Daten

Beitrag von HobbyProgrammer »

Hallo Forengemeinde,

in meinem Projekt 'CP/M Image-File Explorer' habe ich nun das Hineinkopieren von Dateien mittels Paste und Drop-Files am laufen.

Code: Alles auswählen

procedure TMainWindow.actionPasteExecute(Sender: TObject);
var
    Page: TImagePage;
    {$ifdef WINDOWS}
    ClipboardFileList: HDROP;
    FileBuffer: PChar;
    BufferSize: integer;
    {$else}
    ClipboardFileList: TStringArray;
    FileBuffer: string;
    {$endif}
    IndexI: integer;
    FilesToPaste: TStringArray;
begin

    {$ifdef WINDOWS}
    if (Clipboard.HasFormat(CF_HDROP) and OpenClipboard(0)) then begin

        try
            ClipboardFileList := GetClipboardData(CF_HDROP);

            if ClipboardFileList <> 0 then begin

                for IndexI := 0 to (DragQueryFile(ClipboardFileList, $FFFFFFFF, nil, 0) - 1) do begin
                    BufferSize := DragQueryFile(ClipboardFileList, IndexI, nil, 0);
                    FileBuffer := StrAlloc(BufferSize + 1);

                    try

                        if (DragQueryFile(ClipboardFileList, IndexI, FileBuffer, BufferSize + 1) > 0) then begin
                            SetLength(FilesToPaste, IndexI + 1);
                            FilesToPaste[IndexI] := FileBuffer;
                        end;

                    finally
                        StrDispose(FileBuffer);
                    end;

                end;

            end;

        finally
            CloseClipboard;
        end;

    end;
    {$else}
    if Clipboard.HasFormat(CF_Text) then begin
        ClipboardFileList := Clipboard.AsText.Trim.Split(Chr($0A));

        for IndexI := 0 to (Length(ClipboardFileList) - 1) do begin
            FileBuffer := ParseURI(ClipboardFileList[IndexI]).Path + ParseURI(ClipboardFileList[IndexI]).Document;

            if (IsRegular(FileBuffer)) then begin
                SetLength(FilesToPaste, IndexI + 1);
                FilesToPaste[IndexI] := FileBuffer;
            end;

        end;

    end;
    {$endif}

    if (Length(FilesToPaste) > 0) then begin
        Page := PageControl.ActivePage as TImagePage;

        if (Assigned(Page)) then begin
            Page.PasteFiles(FilesToPaste);
        end;

    end;

end;


procedure TMainWindow.FormDropFiles(Sender: TObject; const FileNames: array of string);
var
    MousePoint: TPoint;
    Page: TImagePage;
    IndexI: integer;
    FilesToPaste: TStringArray;
    FileBuffer: string;
begin
    Page := PageControl.ActivePage as TImagePage;

    if (Assigned(Page)) then begin
        MousePoint := Page.ScreenToControl(Mouse.CursorPos);

        if Page.ClientRect.Contains(MousePoint) then begin

            {$ifdef WINDOWS}
            for IndexI := Low(FileNames) to High(FileNames) do begin
                FileBuffer := FileNames[IndexI];

                if not DirectoryExists(FileBuffer) then begin
                    SetLength(FilesToPaste, IndexI + 1);
                    FilesToPaste[IndexI] := FileBuffer;
                end;

            end;
            {$else}
            for IndexI := Low(FileNames) to High(FileNames) do begin
                FileBuffer := FileNames[IndexI];

                if (IsRegular(FileBuffer)) then begin
                    SetLength(FilesToPaste, IndexI + 1);
                    FilesToPaste[IndexI] := FileBuffer;
                end;

            end;
            {$endif}
            Page.PasteFiles(FilesToPaste);
        end;

    end;
end;

Code: Alles auswählen

procedure TImagePage.PasteFiles(const AFiles: TStringArray);
var
    IndexI: integer;
    FileToPaste: string;
    UserNumber: integer;
    PreserveTimeStamps: boolean;
    ConvertTextFiles: boolean;
    TextfileEndings: string;
    IsTextFile: boolean;
begin

    with TXMLSettings.Create(SettingsFile) do begin

        try
            OpenKey('Settings');
            PreserveTimeStamps := GetValue('KeepTimestamps', True);
            UserNumber := GetValue('DefaultUserNumber', 0);
            ConvertTextFiles := GetValue('ConvertTextFiles', False);
            TextfileEndings := GetValue('TextFileEndings', 'txt pip pas');
            CloseKey;
        finally
            Free;
        end;

    end;

    for IndexI := 0 to (Length(AFiles) - 1) do begin
        FileToPaste := AFiles[IndexI];
        IsTextFile := (ConvertTextFiles and TextFileEndings.Contains(RightStr(FileToPaste,
            (Length(FileToPaste) - Pos('.', FileToPaste)))));

        if (FileExists(FileToPaste)) then begin
            FCpmTools.WriteFileToImage(FileToPaste, UserNumber, IsTextFile, PreserveTimeStamps);
        end;

    end;

    RefreshDirectory;

end;

Code: Alles auswählen

procedure TCpmTools.WriteFileToImage(AFileName: string; AUserNumber: integer; AIsTextFile: boolean;
    APreserveTimeStamps: boolean);
var
    UnixFile: file of byte;
    CpmFile: TCpmFile;
    CpmName: string[15];
    Inode: TCpmInode;
    Buffer: array of byte = nil;
    UnixFileSize: longword;
    WriteError: boolean;
    IndexJ: longword;
    DataByte: byte;
    Times: TUTimeBuf;
    {$ifdef UNIX}
    StatBuf: stat;
    {$else}
    FileAttr: TWIN32FILEATTRIBUTEDATA;
    SystemTime, LocalTime: TSystemTime;
    {$endif}
begin

    try
        AssignFile(UnixFile, AFileName);
        Reset(UnixFile, 1);
        UnixFileSize := FileSize(UnixFile);
    except

        on e: Exception do begin
            MessageDlg(Format('can not open %s' + LineEnding + '%s', [ExtractFileName(AFileName), e.Message]),
                mtError, [mbOK], 0);
            exit;
        end;

    end;

    CpmName := Format('%.2d%s', [AUserNumber, ExtractFileName(AFileName)]);

    // check if file already exists
    if (FCpmFileSystem.IsFileExisting(CpmName)) then  begin
        if (MessageDlg(Format('file %s already exists.' + LineEnding + 'replace existing file?',
            [ExtractFileName(AFileName)]), mtError, [mbYes, mbNo], 0) = mrYes) then begin

            if not (FCpmFileSystem.Delete(PChar(Format('%.2d%s', [AUserNumber, ExtractFileName(AFileName)])))) then begin
                MessageDlg(Format('can not replace %s' + LineEnding + '%s',
                    [ExtractFileName(AFileName), FCpmFileSystem.GetErrorMsg]),
                    mtError, [mbOK], 0);
                exit;
            end;

        end
        else begin
            exit;
        end;

    end;

    if not (FCpmFileSystem.Create(FCpmFileSystem.GetDirectoryRoot, CpmName, UnixFileSize, Inode, &666)) then begin
        MessageDlg(Format('can not create %s' + LineEnding + '%s', [ExtractFileName(AFileName), FCpmFileSystem.GetErrorMsg]),
            mtError, [mbOK], 0);
        exit;
    end;

    WriteError := False;
    FCpmFileSystem.Open(Inode, CpmFile, O_WRONLY);

    if (AIsTextFile) then begin

        try
            SetLength(Buffer, 4096);
        except

            on e: Exception do begin
                MessageDlg(Format('can not create buffer space' + LineEnding + '%s', [e.Message]),
                    mtError, [mbOK], 0);
                exit;
            end;

        end;

        repeat
            IndexJ := 0;

            while ((IndexJ < (Length(Buffer) div 2)) and not EOF(UnixFile)) do begin
                Read(UnixFile, DataByte);

                if (DataByte = $0A) then begin
                    Buffer[IndexJ] := $0D;
                    Inc(IndexJ);
                end;

                Buffer[IndexJ] := DataByte;
                Inc(IndexJ);
            end;

            if (EOF(UnixFile)) then begin
                Buffer[IndexJ] := &032;
                Inc(IndexJ);
            end;

            if (FCpmFileSystem.Write(CpmFile, @Buffer[0], IndexJ) <> IndexJ) then begin
                MessageDlg(Format('can not write %s' + LineEnding + '%s',
                    [Format('%.d:%s', [AUserNumber, ExtractFileName(AFileName)]), FCpmFileSystem.GetErrorMsg]),
                    mtError, [mbOK], 0);
                WriteError := True;
                Break;
            end;

        until (EOF(UnixFile));

    end
    else begin

        try
            SetLength(Buffer, UnixFileSize);
        except

            on e: Exception do begin
                MessageDlg(Format('can not create buffer space' + LineEnding + '%s', [e.Message]),
                    mtError, [mbOK], 0);
                exit;
            end;

        end;

        try
            BlockRead(UnixFile, Buffer[0], UnixFileSize);
        except

            on e: Exception do begin
                MessageDlg(Format('can not read %s from disk' + LineEnding + '%s', [ExtractFileName(AFileName), e.Message]),
                    mtError, [mbOK], 0);
                exit;
            end;

        end;

        if (FCpmFileSystem.Write(CpmFile, @Buffer[0], UnixFileSize) <> UnixFileSize) then begin
            MessageDlg(Format('can not write %s' + LineEnding + '%s',
                [Format('%.d:%s', [AUserNumber, ExtractFileName(AFileName)]), FCpmFileSystem.GetErrorMsg]),
                mtError, [mbOK], 0);
            WriteError := True;
        end;

    end;

    if (not FCpmFileSystem.Close(CpmFile) and not WriteError) then begin
        MessageDlg(Format('can not close %s' + LineEnding + '%s',
            [Format('%.d:%s', [AUserNumber, ExtractFileName(AFileName)]), FCpmFileSystem.GetErrorMsg]), mtError, [mbOK], 0);
    end;

    if (APreserveTimeStamps and not WriteError) then begin
        {$ifdef UNIX}
        FpStat(AFileName, StatBuf);
        Times.AcTime := FileDateToDateTime(StatBuf.st_atime);
        Times.ModTime := FileDateToDateTime(StatBuf.st_mtime);
        {$else}
        GetFileAttributesEx(PChar(AFileName), GetFileExInfoStandard, @FileAttr);
        FileTimeToSystemTime(FileAttr.ftLastAccessTime, SystemTime);
        SystemTimeToTzSpecificLocalTime(nil, SystemTime, LocalTime);
        Times.AcTime := SystemTimeToDateTime(LocalTime);
        FileTimeToSystemTime(FileAttr.ftLastWriteTime, SystemTime);
        SystemTimeToTzSpecificLocalTime(nil, SystemTime, LocalTime);
        Times.ModTime := SystemTimeToDateTime(LocalTime);
        {$endif}
        FCpmFileSystem.UpdateTime(Inode, Times);
    end;

    try
        CloseFile(UnixFile);
    except

        on e: Exception do begin
            MessageDlg(Format('can not close %s' + LineEnding + '%s', [ExtractFileName(AFileName), e.Message]),
                mtError, [mbOK], 0);
        end;

    end;

    if not FCpmFileSystem.Sync then begin
        MessageDlg(Format('paste error write back directory' + LineEnding + '%s', [FCpmFileSystem.GetErrorMsg]),
            mtError, [mbOK], 0);
    end;
end;
Nun möchte ich aber auch einzelne oder mehrere Dateien aus so einem Image wieder herauskopieren. Das Lesen einer Datei aus dem Image resultiert in einen dynamischen Array of bytes mit der Größe der jeweiligen Datei.

Gibt es eine Möglichkeit dieses Array als z.B. Custom-Data über das Clipboard direkt mit Paste (CTRL-V) bzw. Drop z.B. im Windows Explorer oder Linux Dolphin dann zu speichern. Das ganze soll, wie auch schon das Hineinkopieren von Dateien, Cross-Platform (Linux , Windows) funktionieren.

Freue mich auf Tips von euch.

Grüße
HobbyProgrammer
Host: Core i7-12700H, NVIDIA RTX3050 6GB, 32GB Ram, 1TB NVME SSD mit KUbuntu 22.04LTS 64bit , VM KUbuntu 22.04 LTS 64bit mit Lazarus 3.0.0 und Cross-Platform Compiler für Linux 32/64bit und Windows 32/64bit. Wine für erste Tests der Windows Binarys.

Soner
Beiträge: 624
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von Soner »

Für Copy/Paste suche in der Unit Clipbrd nach, wenn du diese Unit einbindest, dann hast du Zugriff auf die Variable Clipboard vom Type TClipBoard, damit kannst du Sachen Copy/Paste machen. Die Jungs haben das ganz gut gemacht. Wenn du Beispiel für CustomData suchst, dann schaue TsWorkSheetGrid nach, dort werden Excel-Tabellendaten in die Zwischenablage kopiert. Ich denke das muss CustomData sein. Die Komponente findest du bei fpSpreadSheet-Package auf Sourceforge oder bei Onlinepackagemanager.

Für Drag&Drop auf Windows gibt es auch eine Komponente, das findest du auch auf Onlinepackagemanager oder hier.

Ich denke Copy/Paste mit TClipBoard müsste Crossplatform sein.

Ich wünsche dir viel Glück.


HobbyProgrammer
Beiträge: 173
Registriert: Di 29. Okt 2019, 12:51
Wohnort: Deutschland , Baden-Württemberg

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von HobbyProgrammer »

Hallo,

bin leider erst jetzt dazu gekommen mich mal weiters damit zu beschäftigen.

@Soner
TClipboard verwende ich ja schon um Dateien von ausserhalb in ein image zu kopieren. Das klappt auch sehr gut. Die Schwierigkeit besteht darin, eine Datei aus einem Image so nach TClipboard zu bringen, das diese extern (z.B. Linux Dolphin, Windows Explorer) dann mittels Paste (Ctrl-V) in ein Verzeichnis kopiert werden können.

@Theo
Das von Dir genannte Package schaut interessant aus. Unter Linux kompiliert es ohne Probleme. Allerdings erzeugt das Package in einem Testprojekt beim Beenden ein Speicherleck. Hab jetzt aber noch nicht geschaut woran das liegt.
Unter Windows bekomme ich in der Datei 'DragDropWin32' einen Compilerfehler in der Zeile:

Code: Alles auswählen

TDataObject = class(TInterfacedObject, IDataObject)
Fehler:

Code: Alles auswählen

dragdropwin32.pas(84,17) Error: No matching implementation for interface method "SetData(const tagFORMATETC;var TagSTGMEDIUM;LongBool):LongInt; StdCall;" found
Host: Core i7-12700H, NVIDIA RTX3050 6GB, 32GB Ram, 1TB NVME SSD mit KUbuntu 22.04LTS 64bit , VM KUbuntu 22.04 LTS 64bit mit Lazarus 3.0.0 und Cross-Platform Compiler für Linux 32/64bit und Windows 32/64bit. Wine für erste Tests der Windows Binarys.

Benutzeravatar
theo
Beiträge: 10500
Registriert: Mo 11. Sep 2006, 19:01

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von theo »

HobbyProgrammer hat geschrieben:
Fr 12. Apr 2024, 16:20
@Theo
Das von Dir genannte Package schaut interessant aus. Unter Linux kompiliert es ohne Probleme. Allerdings erzeugt das Package in einem Testprojekt beim Beenden ein Speicherleck. Hab jetzt aber noch nicht geschaut woran das liegt.
Unter Windows bekomme ich in der Datei 'DragDropWin32' einen Compilerfehler in der Zeile:

Code: Alles auswählen

TDataObject = class(TInterfacedObject, IDataObject)
Fehler:

Code: Alles auswählen

dragdropwin32.pas(84,17) Error: No matching implementation for interface method "SetData(const tagFORMATETC;var TagSTGMEDIUM;LongBool):LongInt; StdCall;" found
K.A., bin nicht auf Win. Google führt aber hierhin: https://forum.lazarus.freepascal.org/in ... ic=53057.0

HobbyProgrammer
Beiträge: 173
Registriert: Di 29. Okt 2019, 12:51
Wohnort: Deutschland , Baden-Württemberg

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von HobbyProgrammer »

So einen ähnlichen Forenbeitrag habe ich auch schon gefunden. Muß ich mal sehen wie ich das evtl. lösen kann. Ich habe eben (immernoch) die Hoffung diese Art von Drag and Drop, auf Linux und Windows hinzubekommen. Da mein Programm von Linux- als auch von Windows-Usern benutzt wird.
Host: Core i7-12700H, NVIDIA RTX3050 6GB, 32GB Ram, 1TB NVME SSD mit KUbuntu 22.04LTS 64bit , VM KUbuntu 22.04 LTS 64bit mit Lazarus 3.0.0 und Cross-Platform Compiler für Linux 32/64bit und Windows 32/64bit. Wine für erste Tests der Windows Binarys.

Stevie
Beiträge: 44
Registriert: Di 27. Feb 2024, 22:40

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von Stevie »

Lässt sich denn der Compile-Fehler mit WPs Fix aus dem internationalen Forum fixen? Das hört sich doch ganz einfach an, oder?
...
This means that you must replace the "const" before the TStgMedium parameter by "var" for FPC 3.2+
...
Edit: Theo war schneller...

HobbyProgrammer
Beiträge: 173
Registriert: Di 29. Okt 2019, 12:51
Wohnort: Deutschland , Baden-Württemberg

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von HobbyProgrammer »

So wirklich weiter bin ich immer noch nicht.
Das Drap & Drop Package gibt auch nur StringLists weiter in welchen die Files als Pfad+Filename weitergereicht werden.

Ich versuche jetzt zuerst mal STRG-C und STRG-V zu implementieren. Aber auch das gestaltet sich schwieriger als gedacht. Ich habe es zwar hinbekommen die Binärdaten eines CP/M-Files aus einem Image in das Clipboard zu schreiben. Wenn ich dann aber z.B. in Dolphin STRG-V drücke muß ich noch den Namen angeben unter welchem die Daten dann gespeichert werden.
Es gibt noch ein Event 'Clipboard.OnRequest' welches ausgelöst wird wenn ich STRG-V drücke, aber da ist es mir bis jetzt auch nicht gelungen das Verzeichnis abzufragen ich welchem STRG-V gedrückt wurde um evtl. die Daten dann in Code auf Platte schreiben zu können... :?
Host: Core i7-12700H, NVIDIA RTX3050 6GB, 32GB Ram, 1TB NVME SSD mit KUbuntu 22.04LTS 64bit , VM KUbuntu 22.04 LTS 64bit mit Lazarus 3.0.0 und Cross-Platform Compiler für Linux 32/64bit und Windows 32/64bit. Wine für erste Tests der Windows Binarys.

Mathias
Beiträge: 6210
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von Mathias »

Das Drap & Drop Package gibt auch nur StringLists weiter in welchen die Files als Pfad+Filename weitergereicht werden.
Wen du die Dateiliste hast sollte es eigentlich kein Problem sein. Datein öffnen und und die Daten in deine Anwendung kopieren.

Zum Clipboard hast du verstanden, wie ein OS ein Clipboard abarbeitet ?
Wen ja, man kann X-beliebig Daten hin und her schieben. Vor allem auch User definierte.

Es gibt die sogenannten Targets, welche jede App mit Chlipboard Funktion zur Verfügung stellt. Und da kann man auch eigene Formate definieren.
ZB. hat auch ein Word oder Excel interne Formate, welche nur sie untereinander kennen.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

HobbyProgrammer
Beiträge: 173
Registriert: Di 29. Okt 2019, 12:51
Wohnort: Deutschland , Baden-Württemberg

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von HobbyProgrammer »

Wie ich Dateien in mein Programm bekomme funktioniert ja schon. Siehe meinen Startpost für dieses Thema.

Was ich jetzt suche ist die Funktion Daten aus meinen Programm, welche in dynamischen Arrays vom Typ TBytes vorliegen, wieder mit dem richtigen Namen in die 'reale Welt' (z.B. Linux Dolphin oder Windows Explorer) zu transferieren.
Host: Core i7-12700H, NVIDIA RTX3050 6GB, 32GB Ram, 1TB NVME SSD mit KUbuntu 22.04LTS 64bit , VM KUbuntu 22.04 LTS 64bit mit Lazarus 3.0.0 und Cross-Platform Compiler für Linux 32/64bit und Windows 32/64bit. Wine für erste Tests der Windows Binarys.

Mathias
Beiträge: 6210
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von Mathias »

Wie werden die Dateien in deinem Programm dargestellt ?
Machst du dies mit einer ListBox oder was ähnlichem ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

HobbyProgrammer
Beiträge: 173
Registriert: Di 29. Okt 2019, 12:51
Wohnort: Deutschland , Baden-Württemberg

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von HobbyProgrammer »

Das Inhaltsverzeichnis eines Images wird in einem TListView dargestellt. Dort können dann ein oder mehrere Dateien ausgewählt werden.

Das Projekt ist hier zu finden:
https://github.com/ProgrammingHobby/Cife

Die Lesemethoden laufen alle schon und eine aus einem Image gelesene Datei steht dann wie schon angedeutet in einen dynamischen Array of TBytes zur verfügung.
Host: Core i7-12700H, NVIDIA RTX3050 6GB, 32GB Ram, 1TB NVME SSD mit KUbuntu 22.04LTS 64bit , VM KUbuntu 22.04 LTS 64bit mit Lazarus 3.0.0 und Cross-Platform Compiler für Linux 32/64bit und Windows 32/64bit. Wine für erste Tests der Windows Binarys.

Mathias
Beiträge: 6210
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von Mathias »

Ich habe mal hier rein geguckt. Aber leider scheinen alle Beispiele für den Datenempfang zu sein.

https://wiki.freepascal.org/Drag_and_Drop/de

So nebenbei kenne ich keine Anwendung, ausser Datei-Manager, welche Dateinamen ausgeben.
Auch bei einem normales Copy/Paste wird das gleiche Problem sein.

Der Inhalt einer Datei-Bewegung ist immer nur der/die Datei-Namen.
Wen ich also etwas markiere und kopiere oder mit Drag verschiebe, hat es zB. folgenden Inhalt:

Code: Alles auswählen

/home/tux/PDF
/home/tux/Lazarus_fpcupdeluxe_trunk
/home/tux/Lazarus_fpcupdeluxe_trunk_2
Und anhand von dem weis der Datei Manager welche Dateien er kopieren soll. Und diese liegen schön brav im Dateisystem.

Was mir jetzt gerade in den Sinn kommt. ZB. kann Winzip auch Dateien ausgeben.

Folgendes reagiert, wen ich von Dateimanager empfange.
Aber versuche ich es aus einem Zip-Programm, reagiert es nicht.
Somit machen die ganz einen anderen Weg, und dieser Weg wäre für dich interessant. Dein Programm müsste das gleiche machen, wie eine Zip-GUI.

Code: Alles auswählen

procedure TForm1.FormCreate(Sender: TObject);
begin
  AllowDropFiles:=True;
end;

procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of string  );
var
  i: Integer;
begin
  WriteLn('FormDropFiles');
  for i:=0 to Length(FileNames)-1 do WriteLn(FileNames[i]);
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

HobbyProgrammer
Beiträge: 173
Registriert: Di 29. Okt 2019, 12:51
Wohnort: Deutschland , Baden-Württemberg

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von HobbyProgrammer »

Wenn ich mit Copy/Paste oder Drag/Drop Dateien von aussen in ein Image hineinkopiere bekomme ich File-Urls welche ich auswerte, die jeweilen Dateien als binäres Abbild aus dem Filesystem lese und in dem Imagefilesystem speichere.

Mein Ansatz ist nun, das ich Dateien aus dem Imagefilesystem lese, diese temporär (z.B. /tmp oder C:\Temp), daraus eine File-Url erzeuge und diese dann dem Clipboard bzw. Drag/Drop System übergebe.
Werde das die nächsten Tage versuchen.
Host: Core i7-12700H, NVIDIA RTX3050 6GB, 32GB Ram, 1TB NVME SSD mit KUbuntu 22.04LTS 64bit , VM KUbuntu 22.04 LTS 64bit mit Lazarus 3.0.0 und Cross-Platform Compiler für Linux 32/64bit und Windows 32/64bit. Wine für erste Tests der Windows Binarys.

HobbyProgrammer
Beiträge: 173
Registriert: Di 29. Okt 2019, 12:51
Wohnort: Deutschland , Baden-Württemberg

Re: Drag Drop, Copy Paste Custom binary Daten

Beitrag von HobbyProgrammer »

Ich habe es nun geschafft, das die Windows Version meines Programmes Dateien aus einem Image mittels Copy (STRG-C) herauskopieren und mittels Paste (STRG-V) z.B. in einem Ordner im Windows Explorer wieder Einfügen lassen.
Die Dateien werden dazu in einem Temporären Ordner zwischengespeichert und dann an Clipboard übergeben.

Code: Alles auswählen

procedure TImagePage.CopyFiles(ADoCut: boolean);
var
    SelectedFile, TmpFile, CpmFile: string;
    FileExt, TextfileEndings: string;
    PreserveTimeStamps, ConvertTextFiles, IsTextFile: boolean;
    IndexI: integer;
    ClipbrdList: TStringList;
begin
    { #todo : 'ADoCut' auswerten. }
    { #todo : Selektionen nach erfolgter Operation löschen }
    with TXMLSettings.Create(SettingsFile) do begin

        try
            OpenKey('Settings');
            PreserveTimeStamps := GetValue('KeepTimestamps', True);
            ConvertTextFiles := GetValue('ConvertTextFiles', False);
            TextfileEndings := GetValue('TextFileEndings', 'txt pip pas');
            CloseKey;
        finally
            Free;
        end;

    end;

    try
        ClipbrdList := TStringList.Create;
        ClipbrdList.Clear;

        for IndexI := 0 to FDirectoryList.Items.Count - 1 do begin

            if (FDirectoryList.Items[IndexI].Selected) then begin
                SelectedFile := DelSpace(FDirectoryList.Items[IndexI].Caption);
                TmpFile := RightStr(SelectedFile, Length(SelectedFile) - Pos(':', SelectedFile));
                CpmFile := Format('%.2d%s', [StrToInt(LeftStr(SelectedFile, Pos(':', SelectedFile) - 1)), TmpFile]);
                FileExt := RightStr(TmpFile, (Length(TmpFile) - Pos('.', TmpFile)));
                IsTextFile := (ConvertTextFiles and TextFileEndings.Contains(FileExt));
                ReadCpmFile(CpmFile, TmpFile, IsTextFile, PreserveTimeStamps);
                ClipbrdList.Add(FTempFolder + TmpFile);
            end;

        end;

        CopyFilesToClipboard(ClipbrdList);

    finally
        FreeAndNil(ClipbrdList);
    end;

end;

Code: Alles auswählen

procedure TImagePage.ReadCpmFile(ACpmFileName: string; ATmpFileName: string; AIsTextFile: boolean; APreserveTimeStamps: boolean);
var
    FileLength, Count: size_t;
    FileData: TBytes;
    FileTime: TUTimeBuf;
    TmpFile: file of byte;
begin
    { #todo : 'APreserveTimeStamps' auswerten !!! }
    FCpmTools.ReadFileFromImage(ACpmFileName, FileData, FileLength, AIsTextFile, FileTime);

    if (FileLength > 0) then begin

        try
            AssignFile(TmpFile, FTempFolder + ATmpFileName);
            Rewrite(TmpFile);

            try
                BlockWrite(TmpFile, FileData[0], FileLength, int64(Count));
            except

                on e: Exception do begin

                    if (Count <> FileLength) then begin
                        MessageDlg(Format('Error writing %s to Temp Folder' + LineEnding + '%s',
                            [ExtractFileName(ATmpFileName), e.Message]), mtError, [mbOK], 0);
                    end;

                end;
            end;

        finally
            CloseFile(TmpFile);
        end;

    end;

end; 

Code: Alles auswählen

procedure TImagePage.CopyFilesToClipboard(AFileList: TStringList);
var
    {$ifdef UNIX}
    IndexI: integer;
    {$endif}

    {$ifdef WINDOWS}
    ClipbrdData: PDropFiles;
    ClipbrdHandle: THandle;
    IndexI, FileListLength: integer;
    {$endif}

    FileList: string;
begin  
    FileList := '';

    {$ifdef UNIX}
    for IndexI := 0 to AFileList.Count - 1 do begin
        FileList := FileList + 'file://' + AFileList[IndexI] + #$0A;
    end;

    Clipboard.Open;
    Clipboard.Clear;
    Clipboard.AddFormat(CF_Text, FileList[1], Length(FileList));
    Clipboard.Close;
    {$endif}


    {$ifdef WINDOWS}
    for IndexI := 0 to AFileList.Count - 1 do begin
        FileList := FileList + AFileList[IndexI] + #0;
    end;

    FileList := FileList + #0;
    FileListLength := Length(FileList);
    ClipbrdHandle := GlobalAlloc(GMEM_SHARE or GMEM_MOVEABLE or GMEM_ZEROINIT, SizeOf(TDropFiles) + FileListLength);

    if (ClipbrdHandle <> 0) then begin
        ClipbrdData := GlobalLock(ClipbrdHandle);
        ClipbrdData^.pFiles := SizeOf(TDropFiles);
        Move(FileList[1], (PChar(ClipbrdData) + SizeOf(TDropFiles))^, FileListLength);
        GlobalUnlock(ClipbrdHandle);
        OpenClipboard(self.Handle);
        EmptyClipboard;
        SetClipboardData(CF_HDROP, ClipbrdHandle);
        CloseClipboard;
    end;
    {$endif}

end;
Für Linux bin ich noch am Versuchen.
Wenn ich mit einem Clipboard Manager die File URIs anschaue welche ins Clipboard geschrieben werden wenn ich z.B. in Dolphin Dateien mit STRG-C kopiere und dann die URIs so nachbaue, das diese aus meinem Programm auch so herauskommen, dann erkennt Clipboard dennoch nicht das es sich um Dateien handelt.
Ich kann zwar in Dolphin den Inhalt der Zwischenablage speichern, dann muß ich aber einen Dateinamen angeben, und in der Datei stehen dann die File URIs in Textform. :?
Host: Core i7-12700H, NVIDIA RTX3050 6GB, 32GB Ram, 1TB NVME SSD mit KUbuntu 22.04LTS 64bit , VM KUbuntu 22.04 LTS 64bit mit Lazarus 3.0.0 und Cross-Platform Compiler für Linux 32/64bit und Windows 32/64bit. Wine für erste Tests der Windows Binarys.

Antworten