Autor |
Beitrag |
GuaAck
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: 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
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, 1, 10000); clipboard.open; clipboard.Clear; 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; hs := clipboard.Getashandle(Clipboardindex); ps := globallock(hs); Filename := copy(ps^, 1, 10000); clipboard.close; GlobalUnlock(hs); END; EN | D
|
|
jaenicke
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: 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
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 03.10.10 21:50
Richtig, das hatte ich zuerst anders verstanden.
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 
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: 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:
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; 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; clipboard.Clear; clipboard.Setashandle(MeinClipboardformat, hs); clipboard.close; 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; hs := clipboard.Getashandle(Clipboardindex); ps := globallock(hs); 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; GlobalUnlock(hs); END; END |
Moderiert von Martok: Delphi-Tag eingefügt
|
|
|