Forum Delphi.cz

Delphi => Obecné => Téma založeno: rmaster 06-08-2019, 09:42:08

Název: Podivné chování RxRichEdit
Přispěvatel: rmaster 06-08-2019, 09:42:08
Zdravím,
řeším už několik dnů problém a bohužel nevím, jak dál. Používám léta RxRichEdit z RXLIB (poslední verze 275_u_1_0_19) kvůli tomu, že podporuje vkládání obrázků.
Uvedu jednoduchý testovací příklad:
Kód: Delphi [Vybrat]
  1. procedure TForm1.Button8Click(Sender: TObject);
  2. begin
  3.   Showmessage(R1.Lines[0]);
  4.   Showmessage(R1.Text);
  5. end;
  6.  
  7. procedure TForm1.FormCreate(Sender: TObject);
  8. begin
  9.   R1:=TRxRichEdit.Create(self);
  10.   R1.Visible:=False;
  11.   R1.Parent:=Self;
  12.   R1.Text:='POKUS';
  13. end;
  14.  

Tento kód funguje bez problémů a v obou případech Showmessage vypíše 'POKUS'.
Pokud do projektu vložím třeba GestureManager, nebo AdvStringGrid, nebo ActionMainMenuBar, tak R1.Lines[0] začne vrace vždy prázdný string. Chová se to stejně při libovolném množství řádků.
Pokud obsah R1 uložím do souboru (nebo streamu), tak tam data jsou.
Nenasměrujte mě prosím, kde by mohl být problém a proč přestane RxRichEdit fungovat?
Moc vám děkuji.
Název: Re:Podivné chování RxRichEdit
Přispěvatel: JaroB 06-08-2019, 11:29:30
Jak se zachová normální richedit?
Název: Re:Podivné chování RxRichEdit
Přispěvatel: rmaster 06-08-2019, 12:13:20
RichEdit funguje bez problémů. Sice né s obrázky, ale jinak je OK.
Našel jsem, že by to mohlo dělat asi toto v RxRichEdit.pas:
Kód: Delphi [Vybrat]
  1. function TRichEditStrings.Get(Index: Integer): string;
  2. var
  3.   Text: array[0..4095] of Char;
  4.   L: Integer;
  5. begin
  6.   Word((@Text)^) := SizeOf(Text);
  7.   L := SendMessage(RichEdit.Handle, EM_GETLINE, Index, Longint(@Text));
  8.   if (Text[L - 2] = #13) and (Text[L - 1] = #10) then Dec(L, 2)
  9.   else if (RichEditVersion >= 2) and (Text[L - 1] = #13) then Dec(L);
  10.   SetString(Result, Text, L);
  11. end;
  12.  
Netuším, proč to normálně jde a když přidám na form komponenty, tak ne.
Název: Re:Podivné chování RxRichEdit
Přispěvatel: vandrovnik 06-08-2019, 13:39:30
Kód: Delphi [Vybrat]
  1. function TRichEditStrings.Get(Index: Integer): string;
  2. var
  3.   Text: array[0..4095] of Char;
  4.   L: Integer;
  5. begin
  6.   Word((@Text)^) := SizeOf(Text);
  7.   L := SendMessage(RichEdit.Handle, EM_GETLINE, Index, Longint(@Text));
  8.   if (Text[L - 2] = #13) and (Text[L - 1] = #10) then Dec(L, 2)
  9.   else if (RichEditVersion >= 2) and (Text[L - 1] = #13) then Dec(L);
  10.   SetString(Result, Text, L);
  11. end;
  12.  

Mě by tam dráždilo už jen to  Longint(@Text), protože to zavání tím, že v 64bitové aplikaci to nebude fungovat. Pevně alokovaná velikost bufferu taky vypadá podezřele, jestli tedy neexistuje nějaká dohoda, že delší text tam nikdy být nesmí. Mimochodem, co když L:=SendMessage dosadí do L hodnotu 0 nebo 1? Tak na dalším řádku Text[L-2] se leze bůh ví kam.
Název: Re:Podivné chování RxRichEdit
Přispěvatel: JaroB 06-08-2019, 14:09:29
4KB je vnitřně nastavený limit bufferu pro jeden řádek a toto omezení tuším platilo pro verzi richeditu 1, pro vyšší verze asi lze použít jakoukoliv velikost.

kvůli statickému bufferu by tam možná mohlo být na začátku ověření na velikost

Kód: Delphi [Vybrat]
  1. if SendMessage(RichEdit.Handle, EM_LINELENGTH, Index, 0) > SizeOf(Text) then Exit;
Název: Re:Podivné chování RxRichEdit
Přispěvatel: JaroB 06-08-2019, 14:54:11
Zkus toto (pro unicode)

Kód: Delphi [Vybrat]
  1. function TRichEditStrings.Get(Index: Integer): string;
  2. var
  3.   Text: array of Char;
  4.   L: Integer;
  5.   W: Word;
  6. begin
  7.   SetLength(Text, SizeOf(Char) * 2048);
  8.   L := SendMessage(RichEdit.Handle, EM_LINELENGTH, Index, 0);
  9.   if L > Length(Text) then SetLength(Text, SizeOf(Char) * L);
  10.   W := Length(Text);
  11.   Text[0] := Char(W);
  12.   L := SendMessage(RichEdit.Handle, EM_GETLINE, Index, Longint(@Text[0]));
  13.   Result := Trim(string(Text));
  14. end;
  15.  
Název: Re:Podivné chování RxRichEdit
Přispěvatel: JaroB 06-08-2019, 14:56:05
Ten Trim() je tam navíc, to je asi chybka
Název: Re:Podivné chování RxRichEdit
Přispěvatel: vandrovnik 06-08-2019, 15:04:05
Místo Longint(@Text[0]) bych fakt psal NativeInt(@Text[0]).
Název: Re:Podivné chování RxRichEdit
Přispěvatel: rmaster 06-08-2019, 15:13:45
Zkusil jsem to takto a zdá se, že to funguje:
Kód: Delphi [Vybrat]
  1. function TRichEditStrings.Get(Index: Integer): string;
  2. var
  3.   LineIndex, LineLength, I: Integer;
  4. begin
  5.   Result := '';
  6.   LineIndex := SendMessageW(RichEdit.Handle, EM_LINEINDEX, Index, 0);
  7.   if LineIndex >= 0 then
  8.     begin
  9.       LineLength := SendMessageW(RichEdit.Handle, EM_LINELENGTH, LineIndex, 0);
  10.       if LineLength > 0 then
  11.         begin
  12.           SetLength(Result, LineLength);
  13.           Result[1] := Widechar(LineLength);
  14.           I:= SendMessageW(RichEdit.Handle, EM_GETLINE, Index, LPARAM(PWideChar(Result)));
  15.           if I < LineLength then SetLength(Result, I);
  16.         end;
  17.     end;
  18. end;
  19.  
Prosím, vidíte tam na první pohled nějaký problém? Co případně opravit?
Díky.
Název: Re:Podivné chování RxRichEdit
Přispěvatel: JaroB 06-08-2019, 15:13:49
Hmm, takže lepší kód, který bude pracovat jak v Delphi 32 tak 64

Kód: Delphi [Vybrat]
  1. function TRichEditStrings.Get(Index: Integer): string;
  2. var
  3.   Text: array of Char;
  4.   L: Integer;
  5.   W: Word;
  6. begin
  7.   SetLength(Text, SizeOf(Char) * 4096);
  8.   L := SendMessage(RichEdit.Handle, EM_LINELENGTH, Index, 0);
  9.   if L > Length(Text) then SetLength(Text, SizeOf(Char) * L);
  10.   W := Length(Text);
  11.   Text[0] := Char(W);
  12.   L := SendMessage(RichEdit.Handle, EM_GETLINE, Index, LongInt(@Text[0]));
  13.   if ((L - 2) >= 0) and (Text[L - 2] = #13) and (Text[L - 1] = #10) then Dec(L, 2)
  14.   else if (RichEditVersion >= 2) and ((L - 1) >= 0) and (Text[L - 1] = #13) then Dec(L);
  15.   SetString(Result, PChar(@Text[0]), L);
  16. end;