Autor Beitrag
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: So 03.10.10 21:06 
Hallo,

ich möchte mein Programm zweimal starten (fenster 1 und fenster 2) und dann zwischen den beiden Fenstern Daten über die Zwischenablage austauschen.

Es funktioniert bestens, wenn ich innerhalb eines Fensters etwas (im Beispiel der Filename) kopiere und an anderer Stelle einfüge.

Aber nach "Kopieren" in Fenster 1 ist in Fenster 2 das "hasFormat" erfolgreich, aber dann kommt eine Access violation. Wenn ich den Empfänger in der IDE von Delphi starte, dann gibt es das zwar nicht, aber Filename enthält unsinnige Daten. Sieht für mich so aus, also ob der mit dem Handle verbundene Soeicher zwischenzeitlich wieder freigegeben wurde.

(Filename ist nur ein Beispiel, das geht einfacher per getText und funktioniert auch, z. B. mit WORD, es soll eigentlich eine kompliziertere Struktur kopiert werden, aber weil es nicht geht, nehme ich zunächst einfach einen String.)

Hat jemand einen Tipp?

Gruß Guenther

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
PROCEDURE TForm1.Kopieren1Click(Sender: TObject);
VAR
  hs: THandle;
  ps: ^STRING;
  anzbytes: integer;
BEGIN
  anzbytes := sizeof(mein_string);
  hs := globalalloc(GMEM_FIXED OR GMEM_ZEROINIT OR GMEM_SHARE, anzbytes);
  ps := globallock(hs);
  ps^ := copy(mein_string, 110000);
  clipboard.open; { Open the clipboard will prevent overwriting of so far copied items }
  clipboard.Clear; { Clear the clipboard first }
  clipboard.Setashandle(Clipboardindex, hs);
  clipboard.close;
  GlobalUnlock(hs);
END;

PROCEDURE TForm1.Einfuegen1Click(Sender: TObject);
VAR
  hs: THandle;
  ps: ^STRING;
  Filename: STRING;

BEGIN
  IF clipboard.hasformat(MeinClipboardformat) THEN
    BEGIN
      clipboard.open; { First open the clipboard again }
      hs := clipboard.Getashandle(Clipboardindex); { Catch the handle to the stored items }
      ps := globallock(hs); { and lock it }
      Filename := copy(ps^, 110000);
      clipboard.close; { Close it }
      GlobalUnlock(hs);
    END;
EN
D
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.10.10 21:25 
Unabhängig von dem Problem:
Einen Datenaustausch zwischen zwei eigenen Programmen über die Zwischenablage zu machen ist... naja, ungünstig...

Mach es lieber richtig, dann funktioniert es auch und du ärgerst den Benutzer nicht indem du seine Zwischenablagendaten überschreibst. Stell dir vor das würde jedes Programm machen...

Der Möglichkeiten gibt es viele:
WM_COPYDATA
MMF + Messages zur Benachrichtigung
Pipes
...

// EDIT:
Es sei denn das soll so sein wie kopieren und einfügen. Denn ich sehe gerade, dass das offenbar entsprechende Befehle vom Benutzer sind, das las sich im Text anders.

Das sieht so aus als wolltest du mehrere Daten kopieren und weitere hinzufügen? Da wäre es sinnvoller das wie in Excel zu machen: Beim Einfügen die Daten aus der anderen Instanz anfordern. Dann musst du nicht alle Daten zuerst in den Arbeitsspeicher kopieren.
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: So 03.10.10 21:38 
Danke Jaenicke,

es soll wirklich wie Kopieren und Einfügen gehen und beide Fenster sind im Vordergund und werden vom Bentzer per Maus usw. bedient. M. E. typische Anwendung der Zwischenablage.

Gruß Guenther
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 03.10.10 21:50 
Richtig, das hatte ich zuerst anders verstanden. :oops:
Beim zweiten Durchlesen dachte ich mir das schon fast.

Trotzdem musst du nicht alle Daten direkt in die Zwischenablage kopieren. Siehe wie gesagt Excel. Es reicht, wenn du in der Zwischenablage z.B. eine Textrepräsentation hinterlegst. Wenn dein Programm die Daten abholt, kann es das bei deinem Programm direkt tun. Das ist dann auch schneller.

Warum es schief geht:
Du forderst nur 4 Bytes an und versuchst darein den ganzen String zu kopieren.
Zweitens kann Copy beim Auslesen nicht wissen, dass da keine 10000 Bytes zur Verfügung stehen. Es versucht also wirklich so viel zu kopieren, greift also auf den Speicher hinter dem Speicherbereich zu. Daher die Schutzverletzung.

Ja, bei Copy auf Strings geht es, weil Copy dort nachprüft wie groß der String ist. Das geht bei einem Pointer aber nicht. (Ob der vor dem String stehende Zähler in diesem Fall wirklich in dem Datenbereich liegt, weiß ich nicht ganz genau, vermute aber nein, wie auch?)
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Di 05.10.10 23:25 
Danke Jaenicke,

das mit sizeof(string) war ein kapitaler Fehler, habe ich korrigiert. Ich habe auch bei Copy vorsichthalber immer nur die Länge kopiert.

Aber es geht nur innerhalb einer Anwednung, aber nicht wenn die Anwendung doppelt gestartet sit von einem Fenster zum Anderen. Es gibt "Access violation"

Wahrscheinlcihes Problem: Ich habe beim Kopieren und beim Einfügen unterschiedliche Werte für das Handle und den Pointer. Handle und Pointer sind jeweils gleich, wie es nach der Beschreibung sein muss.

Gruß Guenther
Hier der aktuelle Code:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
PROCEDURE TForm1.Kopieren1Click(Sender: TObject);
VAR
  hs: THandle;
  ps: ^STRING;
  laenge: integer;
  anzbytes: integer;
BEGIN
  laenge := length(s.Filename[s.i_Dia_aus_Platz[Popup_display_platz]]);
  anzbytes := 10 + laenge; { Laenge + 6 Bytes Reserve }
  hs := globalalloc(GMEM_FIXED OR GMEM_ZEROINIT OR GMEM_SHARE, anzbytes);
  ps := globallock(hs);
  ps^ := copy(s.Filename[s.i_Dia_aus_Platz[Popup_display_platz]], 1, laenge);
  clipboard.open; { Open the clipboard will prevent overwriting of so far copied items }
  clipboard.Clear; { Clear the clipboard first }
  clipboard.Setashandle(MeinClipboardformat, hs); { Copy to clipboard }
  clipboard.close; { finally close the clipboard }
  GlobalUnlock(hs);
  Messagedlg('Kopie: Handle: $' + inttohex(hs, 8) + ' ps^: $' + inttohex(cardinal(ps), 8), mtinformation, [mbok], 0);
END;

PROCEDURE TForm1.Einfuegen1Click(Sender: TObject);
VAR
  hs: THandle;
  ps: ^STRING;
  Filename: STRING;

BEGIN
  IF clipboard.hasformat(MeinClipboardformat) THEN
    BEGIN

      clipboard.open; { First open the clipboard again }
      hs := clipboard.Getashandle(Clipboardindex); { Catch the handle to the stored items }
      ps := globallock(hs); { and lock it }
      Messagedlg('Einfügen: Handle: ' + inttohex(hs, 8) + ' ps^: ' + inttohex(cardinal(ps), 8), mtinformation,
        [mbok], 0);
      laenge := length(ps^);
      Filename := copy(ps^, 1, laenge);
      clipboard.close; { Close it }
      GlobalUnlock(hs);
    END;
END


Moderiert von user profile iconMartok: Delphi-Tag eingefügt