Exceptions with spell checking

General TRichView support forum. Please post your questions here
Post Reply
vit
Posts: 115
Joined: Tue Feb 03, 2009 3:11 pm

Exceptions with spell checking

Post by vit »

Hi!
There is a descendant of TRichViewEdit (TCustomTextInplaceEditor) that use spell checking. Method ClearLiveSpellingResults is calling from destructor. And I get various exception with this.

This is a stack of one of exceptions:

Code: Select all

Classes                 TThread.CheckThreadError
Classes                 TThread.CheckThreadError
Classes                 TThread.SetPriority
RVThread                TRVWordEnumThread.Finish
RichView                TCustomRichView.ClearLiveSpellingResults
CustomTextInplaceEditor	TCustomTextInplaceEditor.Destroy
exception class : EThread
exception message : Thread Error: The handle is invalid (6).


And this is another case:

Code: Select all

Classes                 TThread.Resume
RVThread                TRVWordEnumThread.Finish
RichView                TCustomRichView.ClearLiveSpellingResults
CustomTextInplaceEditor	TCustomTextInplaceEditor.Destroy

exception class : EAccessViolation
exception message : Access violation at address 41077CBA in module ...

Can anybody assume what is a reason of this exceptions?
Thank you!
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Why do you need to call this method from your destructor? It's already called by TCustomRichView.
vit
Posts: 115
Joined: Tue Feb 03, 2009 3:11 pm

Post by vit »

Sergey Tkachenko wrote:Why do you need to call this method from your destructor? It's already called by TCustomRichView.
Yes, you are right, it is not necessary. But early we have another similar troubles with spelling check threads. So it was attempt to fix its. Do you think if I remove this calling exception will disappear?

A big trouble in that that I can't repeat this exceptions (they come from our users).

We have a form with many (0-tens) instances of TRichViewEdit (actually their descendants TCustomTextInplaceEditor). And in all of them is using spelling check. May be a problem in count of instances?
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Each TRichViewEdit has its own spelling thread, they do not interact.

There is a change I am considering to make in TRichView code.

In RVThread.pas: delete the line

Code: Select all

FreeOnTerminate := True;
In RichView.pas, in procedure TCustomRichView.ClearLiveSpellingResults, add

Code: Select all

    FWordEnumThread.Free;
after

Code: Select all

    FWordEnumThread.Finish;
Try these changes and inform me if they fixed the problem.
vit
Posts: 115
Joined: Tue Feb 03, 2009 3:11 pm

Post by vit »

Ok! Thank you for advise!
vit
Posts: 115
Joined: Tue Feb 03, 2009 3:11 pm

Post by vit »

Well, for march we have tested version of our systems with modifications wich you have proposed. And now I can say that we not have such errors more.
But we still have errors that seems to related with spell checking. Its only two.

1. When user delete row from table:

Code: Select all

exception class   : EAccessViolation
exception message : Access violation at address 00000000. Read of address 00000000.
main thread ($298):
00000000 +000 ???
System                    TObject.Free
CRVData                   TCustomRVData.EnumItems
RichView                  TCustomRichView.DoClearLiveSpellingResults
RichView                  TCustomRichView.ClearLiveSpellingResults
MedStRichTextParamContent TRichTextParamContent.ClearLiveSpellChecking
MedStRichTextParamContent TRichTextParamContent.DelRow
TRichTextParamContent - its just TWinControl with TCustomRichView inside (working as inplace editor)

There is related code:

Code: Select all

procedure TRichTextParamContent.DelRow;
var
  Table: TRVTableItemInfo;
  ModifyData: Integer;
  ItemNo: Integer;
  Editor: TCustomRichViewEdit;
begin
  Table := GetCurrentTable(Editor); // function GetCurrentTable receive out parameter - Editor
  if Table <> nil then
  begin
    ItemNo := Editor.GetItemNo(Table);
    ClearLiveSpellChecking;
    FInplaceEditor.BeginItemModify(ItemNo, ModifyData);
    try
      Table.DeleteSelectedRows;
      Editor.Change;
    finally
      Editor.EndItemModify(ItemNo, ModifyData);
    end;
  end;
end;

procedure TRichTextParamContent.ClearLiveSpellChecking;
begin
  if FInplaceEditor <> nil then
  begin
    FInplaceEditor.ClearLiveSpellingResults;
    FInitSpellChecked := False;
  end;
end;

2. in TRVWordEnumThread

Code: Select all

exception class   : EAccessViolation
exception message : Access violation at address 410042CE in module '*.exe'. Read of address EE20EEEF.
thread $fb8 (TRVWordEnumThread):
System                             @AsClass
RVStyle                            TFontInfos.GetInvalidItem
RVStyle                            TFontInfos.GetItem
CRVData                            TCustomRVData.GetStyleCodePage
MedStSpellChecking                 TSpellChecker.GetUnicode
MedStSpellChecking                 TSpellChecker.IsMisspelled
MedStCustomTextParamContentClasses TCustomTextInplaceEditor._OnSpellCheck
RVThread                           TRVWordEnumThread.Execute
madExcept                          HookedTThreadExecute
Classes                            ThreadProc
System                             ThreadWrapper
madExcept                          CallThreadProcSafe
madExcept                          ThreadExceptFrame
>> created by main thread ($ad0) at:
RVThread                           TRVWordEnumThread.Create
There is related code:

Code: Select all

function TSpellChecker.IsMisspelled(const AWord: string; StyleNo: Integer;
  const Editor: TCustomRichView): Boolean;
var
  UniStr: string;
begin
  Result := False;
  if not FEnabled then Exit;

  FLock.Enter; //TCriticalSection for protecting access to FRVHunSpell
  try
    UniStr := GetUnicode(AWord, StyleNo, Editor);
    Result := not FRVHunSpell.Spell(UniStr); //TRVHunSpell
  finally
    FLock.Leave;
  end;
end;

function TSpellChecker.GetUnicode(const ANSI: string;
  const StyleNo: Integer; const Editor: TCustomRichView): TRVUnicodeString;
begin
  Result := RVU_RawUnicodeToWideString(RVU_AnsiToUnicode(
    Editor.RVData.GetStyleCodePage(StyleNo), ANSI));
end;
I will very grateful if you help us with this!
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

1) Where is FInplaceEditor variable assigned?
By the way, it is not necessary (and may be even harmful) to clear live spelling results in the inplace editor; live spelling procedure must handle table operations without any additional code.

2) I am not sure why the second error occurs, but I can see TFontInfos.GetInvalidItem in the stack.
This function is called when accessing incorrect text style (StyleNo<0 or StyleNo>=TextStyles.Count).
Since I can see AsClass function in the stack, it looks like the following code in TFontInfos.GetInvalidItem is executed:

Code: Select all

    FInvalidItem := (FOwner as TRVStyle).GetTextStyleClass.Create(nil);
This code is executed when the invalid item is accessed for the first time.
It's quite strange, because if the document has references incorrect styles, they should be already accessed before live spelling, when formatting document.
So, please recheck that:
a) in TSpellChecker.IsMisspelled, StyleNo is really the index of Editor.Style.TextStyle (may be incorrect Editor is passed as the parameter)
b) there is no procedure that can change styles after the document is formatted
vit
Posts: 115
Joined: Tue Feb 03, 2009 3:11 pm

Post by vit »

1) Firstly, I must clarify. TRichTextParamContent is a TWinControl. And its have "inplace editor" - instance of TRichViewEdit (FInplaceEditor field). FInplaceEditor is creating in SetParent of TRichTextParamContent instance. So inplace editor in TRichTextParamContent it is not the same inplace editor in TRichViewEdit.

So that I do not call ClearLiveSpellingResults of inplace editor of TRichViewEdit, but call its for TRichViewEdit.

Well, I am not sure that is needed to call this method in this context, I was follow your advise from this post:
http://www.trichview.com/forums/viewtop ... highlight=
you wrote:
However, if you have your own operations that are not started from Clear and use non-editing methods, you should be careful (call ClearLiveSpellingResults before them).
Is I don't understand you and I should not call ClearLiveSpellingResults in this case?

2)
a) in TSpellChecker.IsMisspelled, StyleNo is really the index of Editor.Style.TextStyle (may be incorrect Editor is passed as the parameter)
Unfortunately, this is one of errors, wich we can't repeat. So I will insert assertions to check TSpellChecker.IsMisspelled params and we will know some time later.
b) there is no procedure that can change styles after the document is formatted
All style changes processed through ApplyStyleConversion/ApplyParaStyleConversion.
Example:

Code: Select all

procedure TRTInplaceEditor.SetFontSize(const ASize: Integer); //TRTInplaceEditor - Descendant of TRichViewEdit, this is inplace editor of TRichTextParamContent
begin
  FFontSize := ASize;
  ClearLiveSpellingResults; //It is not necessary also?
  ApplyStyleConversion(fcSetFontSize);
end;
and

Code: Select all

procedure TRTInplaceEditor.TextStyleConversion(Sender: TCustomRichViewEdit;
  StyleNo, UserData: Integer; AppliedToText: Boolean;
  var NewStyleNo: Integer);
var
  fi: TFontInfo;
begin
  ClearLiveSpellingResults;
  fi := TFontInfo.Create(nil);
  try
    fi.Assign(Style.TextStyles[StyleNo]);

    case UserData of
      fcSetFontSize: fi.Size := FFontSize;
      fcSetFontName: fi.FontName := FFontName;
      fcSetFontColor: fi.Color := FFontColor;
      fcSetFontStyles: fi.Style := FFontStyles;
    end;

    NewStyleNo := Style.TextStyles.FindSuchStyle(StyleNo, fi,
      RVAllFontInfoProperties);
    if NewStyleNo = -1 then
    begin
      Style.TextStyles.Add;
      NewStyleNo := Style.TextStyles.Count - 1;
      Style.TextStyles[NewStyleNo].Assign(fi);
      Style.TextStyles[NewStyleNo].Standard := False;
      Style.TextStyles[NewStyleNo].Charset := RUSSIAN_CHARSET;
    end;
  finally
    fi.Free;
  end;
end;
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Deleting table rows and ApplyStyleConversion are editing operations. Like all editing operations, they handle live spelling correctly, so do not call ClearLiveSpellingResults before them.

I am afraid I do not know what's wrong with styles in your application.
I can suggest to access Editor.Style.TextStyles.InvalidItem before starting live spelling. Probably it will remove this exception, but it will just hide the problem.
vit
Posts: 115
Joined: Tue Feb 03, 2009 3:11 pm

Post by vit »

Can be problem in that I using OnCaretMove event for update styles control toolbar?

P.S. I know in manual says:
Warning: This event may occur when document is not completely formatted! Do not use any methods relying on formatting inside this event, including methods working with selection (for example, do not use SelectionExists here). If you need to update user interface reflecting selection, use OnSelect.
P.P.S. However all style changes performs through ApplyStyleConversion/ApplyParaStyleConversion
vit
Posts: 115
Joined: Tue Feb 03, 2009 3:11 pm

Post by vit »

Sergey, you was right!
This function is called when accessing incorrect text style (StyleNo<0 or StyleNo>=TextStyles.Count).
Assertions have shown violation! I was just passed wrong styleNo in some caller of this methods.

So I hope this exception will disapear now.

Thank you!
vit
Posts: 115
Joined: Tue Feb 03, 2009 3:11 pm

Post by vit »

Hi again!
We have exceptions with spell checking again!

Exceptions occure when I reopen window with TRichViewEdits.

This is FastMM4 report

Code: Select all

--------------------------------2010/6/28 10:35:49--------------------------------
FastMM has detected an error during a GetMem operation. FastMM detected that a block has been modified after being freed. 

Modified byte offsets (and lengths): 14(1)

The previous block size was: 108

This block was previously allocated by thread 0x790, and the stack trace (return addresses) at the time was:
402AEF [System][@GetMem]
4043C3 [System][TObject.NewInstance]
40478A [System][@ClassCreate]
D0A742 [RVThread.pas][RVThread][TRVWordEnumThread.Create][96]
D3F720 [RichView.pas][RichView][TCustomRichView.StartLiveSpelling][3520]
E21F29 [TRichTextParamContent.StartLiveSpellChecking][986]
E21163 [TRichTextParamContent.IESwitchOn][532]
E1781E [TCustomParamContent.SwitchIE][516]
E17BE5 [TIESwitcher.SwitchAll][616]
E179F1 [TIESwitcher.OnTimer][560]
4A1E02 [ExtCtrls.pas][ExtCtrls][TTimer.Timer][1620]
4A1C70 [ExtCtrls.pas][ExtCtrls][TTimer.WndProc][1578]
47DF66 [Classes][StdWndProc]
7E368734 [Unknown function at GetDC]
7E368816 [Unknown function at GetDC]
7E3689CD [Unknown function at GetWindowLongW]
9A09C1 [AppEvnts.pas][AppEvnts][TCustomApplicationEvents.DoMessage][212]

The block was previously used for an object of class: TRVWordEnumThread

The allocation number was: 2049456

The block was previously freed by thread 0xABC, and the stack trace (return addresses) at the time was:
402B0F [System][@FreeMem]
4043E1 [System][TObject.FreeInstance]
4047D5 [System][@ClassDestroy]
D0A7B1 [RVThread.pas][RVThread][TRVWordEnumThread.Destroy][106]
404427 [System][TObject.Free]
47C43D [Classes][ThreadProc]
4052D6 [System][ThreadWrapper]
455AB7 [madExcept][CallThreadProcSafe]
455B24 [madExcept][ThreadExceptFrame]
7C80B713 [Unknown function at GetModuleFileNameA]

The current thread ID is 0x790, and the stack trace (return addresses) leading to this error is:
40C921 [FastMM4.pas][FastMM4][DebugGetMem][6725]
402AEF [System][@GetMem]
4043C3 [System][TObject.NewInstance]
40478A [System][@ClassCreate]
D0A742 [RVThread.pas][RVThread][TRVWordEnumThread.Create][96]
4C02FE [Controls.pas][Controls][TWinControl.Repaint][7613]
E23ED4 [TRichTextParamContent.PerformResizeRequest][1860]
D3F720 [RichView.pas][RichView][TCustomRichView.StartLiveSpelling][3520]
E21F29 [TRichTextParamContent.StartLiveSpellChecking][986]
E2123E [TRichTextParamContent.SetContent][557]
After I close window first time TRVWordEnumThread is destroyed. But when I open it again this error occured.

Remark: becouse our forms may contain very many controls, we make it visible according window scroll position with using timer.

Can you help me with this?
vit
Posts: 115
Joined: Tue Feb 03, 2009 3:11 pm

Post by vit »

I think you should ignore my last post. This report generated by FastMM right before EOutOfMemory exception is throwed. It's seems like there is no available memory to create new thread.
Post Reply