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 25.03.19 07:33 
Hallo!

Folgender Code fügt an der Caret-Position in einem TJvRichEdit beliebigen, rtf-formatierten Text ein. Müsste auch für TRichEdit geeignet sein, ich habe es dzt. für TJvRichEdit. Egal. Es geht um folgendes:

Der Code funktioniert mit 32Bit-Kompiliereung einwandfrei, aber nicht bei 64Bit, da wird die eingebaute Fehlermeldung ausgegeben, weil rtfStream.dwError <> $0000.

Wie muss ich das umbauen, dass es auch bei 64Bit-Kompilierung funktioniert?

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:
59:
60:
61:
62:
{rtf-Daten an ein JvRichEdit an der Caretposition einfügen, ohne den bisherigen}
{Inhalt zu überschreiben. Wenn srcJvRichEdit und dstJvRichEdit identisch sind,}
{wird an das Quell-JvRichEdit an- bzw. eingefügt.}
{http://delphidabbler.com/tips/57}
procedure InsertRtfJvRichEdit(const srcJvRichEdit, dstJvRichEdit: TJvRichEdit);
var
  rtfStream: TEditStream;
  sourceStream : TMemoryStream;

  function EditStreamReader(
    dwCookie: DWORD;
    pBuff: Pointer;
    cb: LongInt;
    pcb: PLongInt): DWORD; stdcall;
  begin
    result := $0000;
    try
      pcb^ := TStream(dwCookie).Read(pBuff^, cb) ;
    except
      result := $FFFF;
    end;
  end{EditStreamReader}

begin  {InsertRtfJvRichEdit}
  dstJvRichEdit.Lines.BeginUpdate;
  sourceStream := TMemoryStream.Create;
  try
    srcJvRichEdit.Lines.SaveToStream(sourceStream) ;

    sourceStream.Position := 0;

    (*
    {Ausreichende Länge sicherstellen!}
    dstJvRichEdit.MaxLength :=
      dstJvRichEdit.MaxLength + sourceStream.Size + Length(dstJvRichEdit.Text);
    *)

    {Besser:}
    {Ausreichende Länge sicherstellen!}
    dstJvRichEdit.MaxLength := 0;

    rtfStream.dwCookie := DWORD(sourceStream) ;
    rtfStream.dwError := $0000;
    rtfStream.pfnCallback := @EditStreamReader;

    dstJvRichEdit.Perform(
      EM_STREAMIN,
      SFF_SELECTION or SF_RTF or SFF_PLAINRTF, LPARAM(@rtfStream));

    if rtfStream.dwError <> $0000 then
    begin
      Application.MessageBox(
             'Fehler beim Einfügen der Daten.',
             'Fehler',
             mb_OK or mb_ICONSTOP or mb_DEFBUTTON1);
    end;

    (* raise Exception.Create('Fehler beim Einfügen der Daten.') ; *)
  finally
    sourceStream.Free;
    dstJvRichEdit.Lines.EndUpdate;
  end;
end;


Dies hier ist die Schwachstelle:
ausblenden Delphi-Quelltext
1:
2:
3:
dstJvRichEdit.Perform(
  EM_STREAMIN,
  SFF_SELECTION or SF_RTF or SFF_PLAINRTF, LPARAM(@rtfStream));

Und hier ist es konkret SF_RTF, was den Fehler verursacht. Lasse ich das weg, passiert gar nichts.

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 25.03.19 09:23 
- Nachträglich durch die Entwickler-Ecke gelöscht -

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 25.03.19 09:47 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
der Wert SF_RTF hat darauf keine Auswirkung.
Wenn ich den aber weglasse, kommt der Fehler nicht, allerdings funktioniert dann der Code natürlich auch nicht!

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Die Callback-Methode EditStreamReader() wird wohl $FFFF liefern. Überprüfe das mal.
Ich denke schon, dass das so ist, denn es kommt ja zu dem Fehler und es erscheint dann genau die vordefinierte Fehlermeldung.

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Der Doku nach sollte die Variable pBuff vom Typ PByte anstelle von Pointer sein, so nebenbei.
Ok, werde ich korrigieren.

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Die ganzen Zeiger-Typen werden wahrscheinlich eine andere Größe in einer Win64-Anwendung annehmen, daher gelingt der Stream nicht.
Ich schaue mir das alles heute noch an!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 25.03.19 09:55 
- Nachträglich durch die Entwickler-Ecke gelöscht -
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 25.03.19 10:27 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Könntest du ein Beispiel hinzufügen, wie so ein Aufruf bei dir aussieht?
Gerne, kann ich aber ebenfalls erst heute Abend machen!

_________________
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 25.03.19 18:36 
Ok, hier ist nun, was ich mache:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
var
  s: String;
  tmpJvRichEdit: TJvRichEdit;
begin
  tmpJvRichEdit := TJvRichEdit.Create(Self);
  tmpJvRichEdit.Hide;
  tmpJvRichEdit.Parent := Form1;

  s := //Irgendein rtf-Code

  //SetRichText arbeitet mit LoadFromStram, wodurch der bereits vorhandene Text
  //gelöscht werden würde, deshalb verwenden ich ein temporäres JvRichEdit
  SetRichText(s, tmpJvRichEdit);

  //Nun füge ich den Inhalt von tmpJvRichEdit in JvRichEdit ein
  InsertRtfJvRichEdit(tmpJvRichEdit, JvRichEdit);

  //...
end;


Das ist alles! SetRichText arbeitet einwandfrei, daran liegt es also schon mal nicht.

//Edit:
Ich habe das nun korrigiert: pBuff: PByte;
Aber auch das bringt keinen Erfolg.

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 25.03.19 19:10 
- Nachträglich durch die Entwickler-Ecke gelöscht -

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 25.03.19 19:25 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
pcb^ := TStream(dwCookie).Read(pBuff^, cb) ;					

Hier bekommst du eine Zugriffsverletzung.
Hab' ich vorhin herausgefunden, ja. Das geht ins except.

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Auf Anhieb weiss ich nicht, wie man die Zeile umschreiben könnte.
Werde googlen...

_________________
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 25.03.19 19:28 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Als Win64 Plattform muss die Callback-Methode wohl außerhalb der InsertRtfJvRichEdit() Methode definiert werden, dann funktioniert es auch.

Ich habe deinen Nachtrag erst jetzt gelesen - das ist es! Ausserhalb! Darauf muss man erst kommen! :dance2:

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 25.03.19 19:38 
- Nachträglich durch die Entwickler-Ecke gelöscht -
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 25.03.19 20:58 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Naja, wenn der Compiler ständig in der Zeile meckert, egal wie TStream initialisiert wird, und es sich um eine Zugriffsverletzung handelt, kam mir nur noch das in den Sinn.

Zuerst dachte ich ja, dass es daran liegt:
ausblenden Delphi-Quelltext
1:
2:
3:
dstJvRichEdit.Perform(
  EM_STREAMIN,
  SFF_SELECTION or SF_RTF or SFF_PLAINRTF, LPARAM(@rtfStream));

Dann, dass es lediglich an SF_RTF liegt, denn ohne dieses kam die Zugriffsverletzung nicht, da passierte einfach gar nichts.

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Meide verschachtelte Methoden so gut es geht. Es scheint bei Win64 Anwendung da ein Problem zu geben.

Nun, "normale", einfachere Methoden bereiten da kein Problem. Ich bin der Meinung, wenn eine Methode nur von einer einzigen anderen Methode gebraucht und genutzt wird, "lege" ich sie in die aufrufende Methode "hinein", das ist sauber und aufgeräumt.

Ich kann jetzt wieder - mit mühsam zusammengeschriebenem rtf-Code - sogar Tabellen einfügen!

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