Autor Beitrag
galagher
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mo 04.05.20 07:12 
Hallo!

Weiss jemand, wie ich per Code in ein TRichMemo eine Grafik einfügen kann, ohne den Weg über ClipBoard zu nehmen?
Alternativ: Wie realisiere ich eine "eigene" Zwischenablage, die ich dazu verwenden kann? Der Hintergrund dabei ist, dass ich dabei den Inhalt der systemweiten Zwischenablage nicht überschreiben will.

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 04.05.20 08:54 
Du musst soweit ich weiß ein TRichMemoInlinePicture erstellen, dem Konstruktor dein Bild mitgeben und das dann mit InDelInline in das TRichMemo einfügen.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 04.05.20 09:13 
In der Wiki steht auch noch RichMemo: InsertImageFromFile (sowie InsertImageFromFileNoResize).

Für diesen Beitrag haben gedankt: galagher
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mo 04.05.20 09:14 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Du musst soweit ich weiß ein TRichMemoInlinePicture erstellen, dem Konstruktor dein Bild mitgeben und das dann mit InDelInline in das TRichMemo einfügen.
Sagt mir jetzt erstmal gar nichts, aber ich seh's mir an! :mrgreen:

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mo 04.05.20 16:43 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
In der Wiki steht auch noch RichMemo: InsertImageFromFile (sowie InsertImageFromFileNoResize).
Das fügt Grafiken als eingebettetes Objekte ein, ich möchte aber lediglich eine Grafik so einfügen, wie man sie auch per ClipBoard einfügen kann.
Ich sehe mir jetzt erstmal den Vorschlag von user profile iconjaenicke an:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Du musst soweit ich weiß ein TRichMemoInlinePicture erstellen, dem Konstruktor dein Bild mitgeben und das dann mit InDelInline in das TRichMemo einfügen.

Am einfachsten wäre es aber per ClipBoard. Kann man denn davon nicht eine eigene Instanz erstellen? - Ja, kann man, aber dabei wird trotzdem der Inhalt der "echten" Zwischenablage ersetzt. Wie kann ich das verhindern?

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 04.05.20 17:36 
user profile icongalagher hat folgendes geschrieben Zum zitierten Posting springen:
Am einfachsten wäre es aber per ClipBoard.
Nein, der korrekte Weg ist genauso einfach.

user profile icongalagher hat folgendes geschrieben Zum zitierten Posting springen:
Kann man denn davon nicht eine eigene Instanz erstellen? - Ja, kann man, aber dabei wird trotzdem der Inhalt der "echten" Zwischenablage ersetzt. Wie kann ich das verhindern?
Gar nicht, die Zwischenablagenfunktionalität macht ja Windows und nicht die Ansteuerung in der eigenen Anwendung.

Das ist quasi als ob du dir ein eigenes Lenkrad im 3D-Drucker kopierst und dann fragst wie du damit nun ein Auto lenken kannst ohne das echte Auto zu lenken. ;-)
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mo 04.05.20 18:31 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Nein, der korrekte Weg ist genauso einfach.
Ist er nicht! In RichMemo.pas gibt es zwar die erfoderlichen Prozeduren, die sind aber leer.

Also habe ich das Ganze zuerst mal in Form1 erstellt und dort funktioniert es auch. Dann habe ich alles in RichMemo.pas kopiert, den Code natürlich angepasst, aber ich bekomme dort, sobald ich an imageList Width und Height zuweise, die Fehlermeldung:
Zitat:
Projekt project1 hat Exception-Klasse »External: SIGSEGV« ausgelöst.


Wozu brauche ich denn da überhaupt eine ImageList?

Ich blicke da nicht durch, und das Sample-Projekt bringt mich auch nicht weiter (von dort habe ich ja die Vorgehensweise mit der ImageList)...

//Edit: Wenn ich die ImageList weglasse, wird ein "leerer Bereich" eingefügt, aber kein sichtbares Bitmap.

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mo 04.05.20 19:38 
Es funktioniert dank: forum.lazarus.freepa...ex.php?topic=33563.0
Ein einziges Beispiel ist Goldes Wert!

Ich habe den Code angepasst, sodass nun keine Datei mehr geöffnet werden muss, sondern Picture übergeben wird. Nach dem Einfügen gebe ich piclist frei (aber natürlich nicht dessen Elemente).

Warum richmemo.pas das nicht schon OnBoard hat (genauso wie so maches andere), weiss der Kuckuck... Aber ich arbeite dran!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mi 06.05.20 17:51 
Die Grafik wird nicht mitgespeichert. Da macht sich also jemand die Arbeit, eine gut funktionierende Funktion zum Einfügen von Grafiken zu schreiben. Aber natürlich kommt der niemals auf die Idee, dass man das Ganze dann auch speichern können will! :mrgreen: :evil: Nein, wie denn auch? Das ist ja abwegig! Wer will schon Text UND Grafiken als Datei speichern? :autsch:

Nein, im Ernst: Das ärgert mich. Eine halbe Sache, an sich gut, aber doch letzlich so, wie sie ist, unbrauchbar. Leider kann ich das nicht fertig schreiben, weil ich keine Idee habe, wie man die Daten der Grafik in den RTF-Text hinein bekommt.
Wenn man sich die rtf-Datei ansieht, findet sich darin der String {\pict{\*\picprop}\wmetafile0 , es fehlen aber die Daten der Grafik. Wie erhalte ich diese als Text? Ich habe zwar eine Funktion, die das zumindest mit Bitmaps erledigt, aber es funktioniert nicht, wenn man die da einfach dran hängt.

Ich habe das vorläufig so gelöst, dass ich den Text oder das Bitmap der Zwischenablage sichere, dann die Grafik über ClipBoard einfüge und danach den ursprünglichen Inhalt der Zwischenablage wiederherstelle. Das klappt, ist aber natürlich unelegant...

Weiss jemand wie ich beliebigen Inhalt der Zwischenablage sichern und wieder herstellen kann? :eyecrazy:

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mi 06.05.20 19:44 
user profile icongalagher hat folgendes geschrieben Zum zitierten Posting springen:
Weiss jemand wie ich beliebigen Inhalt der Zwischenablage sichern und wieder herstellen kann? :eyecrazy:

ich habe das jetzt erstmal so gelöst:
ausblenden 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:
procedure TCustomRichMemo.InsertGraphic(const aPicture: TPicture);
var
  Stream: TMemoryStream;
  i, n: Integer;
  aArray: array of TClipBoardFormat;
begin
  Stream := TMemoryStream.Create;
  SetLength(aArray, ClipBoard.FormatCount);

  n := ClipBoard.FormatCount;

  {ClipBoard sichern}
  for i := 0 to ClipBoard.FormatCount-1 do
  begin
    aArray[i] := ClipBoard.Formats[i];
    ClipBoard.GetFormat(ClipBoard.Formats[i], Stream);
  end;

  ClipBoard.Assign(aPicture.Bitmap);
  PasteFromClipboard;

  ClipBoard.Clear;
  
  {ClipBoard wiederherstellen}
  for i := 0 to n-1 do
    ClipBoard.AddFormat(aArray[i], Stream);
end;

Scheint zu funktionieren, aber geht das auch besser?

//Edit: Funktioniert aber nicht immer, teilweise enthält ClipBoard danach irgendwelche Zeichen. Was stimmt da denn nicht?

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 06.05.20 22:39 
Du packst alles in einen Stream? Wie soll das denn funktionieren? Woher soll denn beim Laden erkannt werden wo welches Format endet usw.?
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 07.05.20 06:47 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Du packst alles in einen Stream? Wie soll das denn funktionieren?
Nun, AddFormat oder auch SetFormat verlangt eben einen Stream. Ich dachte, das Array erledigt das, aber da wird nun einmal ein Stream verlangt. Und das Array enthält die korrekten Daten ja (denke ich...).
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Woher soll denn beim Laden erkannt werden wo welches Format endet usw.?
Ja, stimmt. Das ist dann wohl auch der Grund, warum die Zwischenablage manchmal nur "Unsinn" enthält, einfach nur irgendwelche Zeichen. Das passiert genau dann, wenn zB. rtf-formatierter Text in der Zwischenblage ist. Dann ist dort ja nicht nur Text, sondern eben auch der rtf-Code.

Wie kann ich das also verbessern? Muss ja prinzipiell funktionieren: 1. Sichere ClipBoard, 2. schreibe da was rein, 3. stelle ClipBoard wieder her. Im Grunde nichts Aufregendes. Aber wie?

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 07.05.20 10:50 
user profile icongalagher hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Du packst alles in einen Stream? Wie soll das denn funktionieren?
Nun, AddFormat oder auch SetFormat verlangt eben einen Stream.
Die Betonung liegt auf einem Stream. Da packst du ja quasi einfach nur Daten hintereinander rein.

user profile icongalagher hat folgendes geschrieben Zum zitierten Posting springen:
Wie kann ich das also verbessern? Muss ja prinzipiell funktionieren: 1. Sichere ClipBoard, 2. schreibe da was rein, 3. stelle ClipBoard wieder her. Im Grunde nichts Aufregendes. Aber wie?
Einfach einen Stream pro Typ verwenden. ;-)
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 07.05.20 15:38 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Einfach einen Stream pro Typ verwenden. ;-)
Woher weiss ich vorher, wie viele Typen es aktuell gibt bzw. wie genau erstelle ich einen Stream pro Typ?

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 07.05.20 16:23 
Du benutzt doch schon die Anzahl ClipBoard.FormatCount? Und davon erstellst du dynamisch entsprechend viele Streams und packst jedes Format in den zugehörigen Stream (und beim Wiederherstellen entsprechend) - so wie du es ja bisher für das array of TClipBoardFormat auch schon gemacht hast.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 07.05.20 16:36 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Du benutzt doch schon die Anzahl ClipBoard.FormatCount? Und davon erstellst du dynamisch entsprechend viele Streams und packst jedes Format in den zugehörigen Stream (und beim Wiederherstellen entsprechend) - so wie du es ja bisher für das array of TClipBoardFormat auch schon gemacht hast.
Ich steh wohl auf der Leitung. Die können doch nicht alle den selben Namen haben? Und wie packe ich die einzelnen Formate da hinein?
Das Prinzip ist mir schon klar, aber die Umsetzung nicht...

//Edit:
Ok, die einzelnen Formate schreibe ich mit GetFormat hinein. Gut. aber wie erstelle ich n Streams? n ist eine Zahl, die ich vorher nicht kenne.
//Edit: Doch, n kenne ich. n = ClipBoard.FormatCount.
Bleibt die Frage: Wie erstelle ich die einzelnen Streams, die ja nicht alle einfach Stream heissen können?

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 07.05.20 17:00 
Genau so wie du es für aArray auch gemacht hast:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
var
  // ...
  aStreams: array of TMemoryStream;
begin
  n := ClipBoard.FormatCount;

  SetLength(aStreams, n);

  // todo: Schleife, um alle n aStreams[i] per TMemoryStream.Create zu erzeugen
  // ...

  for i := 0 to n-1 do
  begin
    aArray[i] := ClipBoard.Formats[i];
    ClipBoard.GetFormat(aArray[i], aStreams[i]);
  end;
  
   // ...
end


PS: aArray solltest du besser aFormats nennen!

Für diesen Beitrag haben gedankt: galagher
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Do 07.05.20 17:24 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:

ausblenden Delphi-Quelltext
1:
2:
3:
var
  // ...
  aStreams: array of TMemoryStream;
Das ist es, was mir nicht klar war! Jetzt scheint es mir ja ganz einleuchtend, das so zu machen, aber an ein Array von Streams dachte ich nicht!

Hier die ganze Prozedur:
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:
{Grafik in den Text von TRichMemo einfügen}
procedure TCustomRichMemo.InsertGraphic(const aPicture: TPicture);
var
  i, n: Integer;
  aFormats: array of TClipBoardFormat;
  aStreams: array of TMemoryStream;
begin
  try
    n := ClipBoard.FormatCount;
    SetLength(aFormats, n);
    SetLength(aStreams, n);

    for i := 0 to n-1 do
      aStreams[i] := TMemoryStream.Create;

    for i := 0 to n-1 do
    begin
      aFormats[i] := ClipBoard.Formats[i];
      ClipBoard.GetFormat(aFormats[i], aStreams[i]);
    end;

    ClipBoard.Assign(aPicture.Bitmap);
    PasteFromClipboard;

    for i := Low(aFormats) to High(aFormats) do
      ClipBoard.SetFormat(aFormats[i], aStreams[i]);

  finally
    for i := High(aStreams) downto Low(aStreams) do
      aStreams[i].Free;
  end;
end;

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mo 11.05.20 23:56 
Nach merfachem Testen kommt es öfter dann zu dem SIGSEGV-Fehler, wenn ich RTF-Daten in der Zwischenablage habe. Wenn ich jedoch ein Sleep(450) einfüge, tritt dieser Fehler nicht auf. :eyecrazy: Mittlerweile habe ich den Code so modifiziert, dass er die RTF-Formatierung in der Zwischenablage erkennt und einfügt. Aber es funktioniert immer nur zusammen mit Sleep!

Draufgekommen bin ich, als ich den Code mit Haltepunkten versehen habe: Eine Pause genügt, und es klappt, und auch Sleep bewirkt dies. Ausserdem tritt der Fehler nur dann auf, wenn die RTF-Daten "frisch" aus der Zwischenablage kommen. Wenn sie mit der Prozedur wieder dorthin zurück geschrieben wurden, funktioniert alles auch ohen Sleep.

Habt ihr eine Erklärung für dieses Phänomen?
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:
{Grafik in den Text von TRichMemo einfügen}
procedure TCustomRichMemo.InsertGraphic(const aPicture: TPicture);
var
  i, n: Integer;
  aFormats: array of TClipBoardFormat;
  aStreams: array of TMemoryStream;
begin
  try
    n := ClipBoard.FormatCount;
    SetLength(aFormats, n);
    SetLength(aStreams, n);

Sleep(450//<- Dies behebt den SIGSEGV-Fehler, Wert kann auch höher sein, 400 klappt nicht

    for i := 0 to n-1 do
      aStreams[i] := TMemoryStream.Create;

    for i := 0 to n-1 do
    begin
      aFormats[i] := ClipBoard.Formats[i];
      ClipBoard.GetFormat(aFormats[i], aStreams[i]);
    end;

    ClipBoard.Assign(aPicture.Bitmap);
    PasteFromClipboard;

    for i := Low(aFormats) to High(aFormats) do
      ClipBoard.SetFormat(aFormats[i], aStreams[i]);

  finally
    for i := High(aStreams) downto Low(aStreams) do
      aStreams[i].Free;
  end;
end;

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2510
Erhaltene Danke: 44

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: So 17.05.20 18:59 
Weiss denn keiner weiter? Der Fehler tritt jetzt, obwohl ich die unten stehende Prozedur seit Tagen nicht verändert habe, nur noch sehr selten auf, und wenn, dann immer dann, wenn die RTF-Daten schon vor dem Programmstart in der Zwischenablage waren. Da hilf auch das try-except nichts, es knallt beim Abfragen des Formats der Zwischenablage: if Windows.IsClipboardFormatAvailable(CF_RICHTEXT). Mit if ClipBoard.HasFormat(CF_RICHTEXT) ebenso.

Weiters: Muss CF_RICHTEXT als Word oder als UINT (= LongWord) dekalriert werden? In Lazarus' VirtualTree.pas sind ClipBoard-Formate als Word's deklariert, irgendwo im Internet habe ich aber UINT aufgeschnappt. Teste nun mit Word...

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:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
implementation
//...
var
//...
  CF_RICHTEXT: Word;//UINT;

procedure TCustomRichMemo.InsertGraphic(const aPicture: TPicture);
var
  i, n: Integer;
  aFormats: array of TClipBoardFormat;
  aStreams: array of TMemoryStream;
  cpFormat: TClipBoardFormat;
begin
  try
    try
      n := ClipBoard.FormatCount;
      SetLength(aFormats, n);
      SetLength(aStreams, n);

      for i := 0 to n-1 do
        aStreams[i] := TMemoryStream.Create;

      for i := 0 to n-1 do
      begin
        aFormats[i] := ClipBoard.Formats[i];
        ClipBoard.GetFormat(aFormats[i], aStreams[i]);
      end;

      if Windows.IsClipboardFormatAvailable(CF_RICHTEXT) then
        cpFormat := CF_RICHTEXT;

      ClipBoard.Assign(aPicture.Bitmap);
      PasteFromClipboard;

      if cpFormat = CF_RICHTEXT then
        for i := Low(aFormats) to High(aFormats) do
        begin
          if aFormats[i] = cpFormat then
            Clipboard.SetFormat(cpFormat, aStreams[i])
        end
      else
        for i := Low(aFormats) to High(aFormats) do
          ClipBoard.SetFormat(aFormats[i], aStreams[i]);  {Andere Formate: Text, Grafiken usw.}

    finally
      for i := High(aStreams) downto Low(aStreams) do
        aStreams[i].Free;
    end;

  except
    ;  {Dzt. nichts}
  end;
end;

//...

initialization
  CF_RICHTEXT := RegisterClipboardFormat(RichEdit.CF_RTF);

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!