home *** CD-ROM | disk | FTP | other *** search
/ Multimedia & CD-ROM 4 / mmcd04-julaug1995-cd.iso / applicat / educate / spmate12 / spellwnd.pa$ / spellwnd.pas
Pascal/Delphi Source File  |  1993-07-23  |  22KB  |  742 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Turbo Pascal for Windows                        }
  5. {       Standard windows unit for ObjectWindows         }
  6. {                                                       }
  7. {       Copyright (c) 1991 Borland International        }
  8. {                                                       }
  9. {=======================================================}
  10. {       Modifications to allows Spell Checker           }
  11. {       SpelMate DLL to be accesses.                    }
  12. {       Copyright (c) 1993 Aciran Software systems      }
  13. {*******************************************************}
  14.  
  15. unit SpellWnds;
  16.  
  17. {$R SpellWNDS.RES}
  18.  
  19. interface
  20.  
  21. uses WinTypes, WinProcs, WinDos, Objects, OWindows, ODialogs,
  22.   OMemory, OStdDlgs, Strings,Win31;
  23.  
  24. const
  25.   cm_spell   = 101;
  26.   MaxWordLen = 20;
  27.  
  28.  
  29. {create function prototypes}
  30. type
  31.   TSpelmateInit = function :integer;
  32.   TSpellCheck = function (AWord:Pchar):BOOL;
  33.   TSuggestWord = function(AWord:PChar):PChar;
  34.   TDisplayAtTop = procedure;
  35.  
  36.  
  37. {create a new edit type so we can get a handle direct to its text buffer
  38.  for faster scanning}
  39. type
  40.    PNewEdit = ^TNewEdit;
  41.    TNewEdit = object(TEdit)
  42.    function GetHandle:word;
  43. end;
  44.  
  45.  
  46. type
  47.  
  48.   { TSearchRec }
  49.   TSearchRec = record
  50.     SearchText: array[0..80] of Char;
  51.     CaseSensitive: Bool;
  52.     ReplaceText: array[0..80] of Char;
  53.     ReplaceAll: Bool;
  54.     PromptOnReplace: Bool;
  55.     IsReplace: Boolean;
  56.   end;
  57.  
  58.   { TEditWindow  }
  59.   PEditWindow = ^TEditWindow;
  60.   TEditWindow = object(TWindow)
  61.     Editor: PNewEdit;
  62.     SearchRec: TSearchRec;
  63.     constructor Init(AParent: PWindowsObject; ATitle: PChar);
  64.     constructor Load(var S: TStream);
  65.     procedure Store(var S: TStream);
  66.     procedure WMSize(var Msg: TMessage);
  67.       virtual wm_First + wm_Size;
  68.     procedure WMSetFocus(var Msg: TMessage);
  69.       virtual wm_First + wm_SetFocus;
  70.     procedure CMEditFind(var Msg: TMessage);
  71.       virtual cm_First + cm_EditFind;
  72.     procedure CMEditFindNext(var Msg: TMessage);
  73.       virtual cm_First + cm_EditFindNext;
  74.     procedure CMEditReplace(var Msg: TMessage);
  75.       virtual cm_First + cm_EditReplace;
  76.     procedure CMSpell(var Msg: TMessage); {Spell check option added}
  77.       virtual cm_First + cm_Spell;
  78.   private
  79.     procedure DoSearch;
  80.   end;
  81.  
  82.   { TFileWindow }
  83.   PFileWindow = ^TFileWindow;
  84.   TFileWindow = object(TEditWindow)
  85.     FileName: PChar;
  86.     IsNewFile: Boolean;
  87.     constructor Init(AParent: PWindowsObject; ATitle, AFileName: PChar);
  88.     destructor Done; virtual;
  89.     constructor Load(var S: TStream);
  90.     procedure Store(var S: TStream);
  91.     function CanClear: Boolean; virtual;
  92.     function CanClose: Boolean; virtual;
  93.     procedure NewFile;
  94.     procedure Open;
  95.     procedure Read;
  96.     procedure SetFileName(AFileName: PChar);
  97.     procedure ReplaceWith(AFileName: PChar);
  98.     function Save: Boolean;
  99.     function SaveAs: Boolean;
  100.     procedure SetupWindow; virtual;
  101.     procedure Write;
  102.     procedure CMFileNew(var Msg: TMessage);
  103.       virtual cm_First + cm_FileNew;
  104.     procedure CMFileOpen(var Msg: TMessage);
  105.       virtual cm_First + cm_FileOpen;
  106.     procedure CMFileSave(var Msg: TMessage);
  107.       virtual cm_First + cm_FileSave;
  108.     procedure CMFileSaveAs(var Msg: TMessage);
  109.       virtual cm_First + cm_FileSaveAs;
  110.   end;
  111.  
  112. const
  113.   REditWindow: TStreamRec = (
  114.     ObjType: 80;
  115.     VmtLink: Ofs(TypeOf(TEditWindow)^);
  116.     Load:    @TEditWindow.Load;
  117.     Store:   @TEditWindow.Store);
  118.  
  119. const
  120.   RFileWindow: TStreamRec = (
  121.     ObjType: 81;
  122.     VmtLink: Ofs(TypeOf(TFileWindow)^);
  123.     Load:    @TFileWindow.Load;
  124.     Store:   @TFileWindow.Store);
  125.  
  126. procedure RegisterStdWnds;
  127.  
  128. implementation
  129.  
  130. {make instances of the functions from our prototypes}
  131. var
  132. SpelmateInit : TSpelmateInit;
  133. SpellCheck : TSpellCheck;
  134. SuggestWord : TSuggestWord;
  135. DisplayAtTop : TDisplayAtTop;
  136.  
  137. { TSearchDialog }
  138.  
  139. const
  140.   sd_Search          = MakeIntResource($7F10);
  141.   sd_Replace         = MakeIntResource($7F11);
  142.   sd_BCSearch        = MakeIntResource($7F12);
  143.   sd_BCReplace       = MakeIntResource($7F13);
  144.   id_SearchText      = 100;
  145.   id_CaseSensitive   = 101;
  146.   id_ReplaceText     = 102;
  147.   id_ReplaceAll      = 103;
  148.   id_PromptOnReplace = 104;
  149.  
  150. type
  151.   PSearchDialog = ^TSearchDialog;
  152.   TSearchDialog = object(TDialog)
  153.     constructor Init(AParent: PWindowsObject; Template: PChar;
  154.       var SearchRec: TSearchRec);
  155.   end;
  156.  
  157. constructor TSearchDialog.Init(AParent: PWindowsObject; Template: PChar;
  158.   var SearchRec: TSearchRec);
  159. var
  160.   C: PWindowsObject;
  161. begin
  162.   TDialog.Init(AParent, Template);
  163.   C := New(PEdit, InitResource(@Self, id_SearchText,
  164.     SizeOf(SearchRec.SearchText)));
  165.   C := New(PCheckBox, InitResource(@Self, id_CaseSensitive));
  166.   if (Template = sd_Replace) or (Template = sd_BCReplace) then
  167.   begin
  168.     C := New(PEdit, InitResource(@Self, id_ReplaceText,
  169.       SizeOf(SearchRec.ReplaceText)));
  170.     C := New(PCheckBox, InitResource(@Self, id_ReplaceAll));
  171.     C := New(PCheckBox, InitResource(@Self, id_PromptOnReplace));
  172.   end;
  173.   TransferBuffer := @SearchRec;
  174. end;
  175.  
  176. function TNewEdit.GetHandle;
  177. begin
  178.   GetHandle := SendMessage(HWindow,EM_GETHANDLE,0,LongInt(0));
  179. end;
  180.  
  181. { TEditWindow }
  182.  
  183. { Constructor for a TEditWindow.  Initializes its data fields using passed
  184.   parameters and default values.  Constructs its child edit control. }
  185. constructor TEditWindow.Init(AParent: PWindowsObject; ATitle: PChar);
  186. begin
  187.   TWindow.Init(AParent, ATitle);
  188.   {NOTE: we use our new edit type here}
  189.   Editor := New(PNewEdit, Init(@Self, 200, nil, 0, 0, 0, 0, 0, True));
  190.   with Editor^.Attr do
  191.     Style := Style or es_NoHideSel;
  192.   FillChar(SearchRec, SizeOf(SearchRec), #0);
  193. end;
  194.  
  195. { Load a TEditWindow from the given stream }
  196. constructor TEditWindow.Load(var S: TStream);
  197. begin
  198.   TWindow.Load(S);
  199.   GetChildPtr(S, Editor);
  200. end;
  201.  
  202. { Store a TEditWindow to the given stream }
  203. procedure TEditWindow.Store(var S: TStream);
  204. begin
  205.   TWindow.Store(S);
  206.   PutChildPtr(S, Editor);
  207. end;
  208.  
  209. { Responds to an incoming wm_Size message by resizing the child edit
  210.   control according to the size of the TEditWindow's client area. }
  211. procedure TEditWindow.WMSize(var Msg: TMessage);
  212. begin
  213.   TWindow.WMSize(Msg);
  214.   SetWindowPos(Editor^.HWindow, 0, -1, -1, Msg.LParamLo+2, Msg.LParamHi+2,
  215.     swp_NoZOrder);
  216. end;
  217.  
  218. { Responds to an incoming wm_SetFocus message by setting the focus to the
  219.   child edit control. }
  220. procedure TEditWindow.WMSetFocus(var Msg: TMessage);
  221. begin
  222.   SetFocus(Editor^.HWindow);
  223. end;
  224.  
  225. procedure TEditWindow.DoSearch;
  226. var
  227.   S: array[0..80] of Char;
  228.   P: Pointer;
  229.   Rslt: Integer;
  230. begin
  231.   Rslt := 0;
  232.   with SearchRec do
  233.     repeat
  234.       Rslt := Editor^.Search(-1, SearchText, CaseSensitive);
  235.       if Rslt = -1 then
  236.       begin
  237.         if not IsReplace or not ReplaceAll then
  238.         begin
  239.           P := @SearchText;
  240.           WVSPrintF(S, '"%0.60s" not found.', P);
  241.           MessageBox(HWindow, S, 'Find error', mb_OK + mb_IconExclamation);
  242.         end;
  243.       end
  244.       else
  245.         if IsReplace then
  246.           if not PromptOnReplace then Editor^.Insert(ReplaceText)
  247.           else
  248.           begin
  249.             Rslt := MessageBox(HWindow, 'Replace this occurrence?',
  250.               'Search/Replace', mb_YesNoCancel + mb_IconQuestion);
  251.             if Rslt = id_Yes then Editor^.Insert(ReplaceText)
  252.             else if Rslt = id_Cancel then Exit;
  253.           end;
  254.     until (Rslt = -1) or not ReplaceAll or not IsReplace;
  255. end;
  256.  
  257. procedure TEditWindow.CMEditFind(var Msg: TMessage);
  258. var
  259.   Dialog: PChar;
  260. begin
  261.   if BWCCClassNames then
  262.     Dialog := sd_BCSearch
  263.   else
  264.     Dialog := sd_Search;
  265.   if Application^.ExecDialog(New(PSearchDialog, Init(@Self,
  266.     Dialog, SearchRec))) = id_OK then
  267.   begin
  268.     SearchRec.IsReplace := False;
  269.     DoSearch;
  270.   end;
  271. end;
  272.  
  273. procedure TEditWindow.CMEditFindNext(var Msg: TMessage);
  274. begin
  275.   DoSearch;
  276. end;
  277.  
  278. procedure TEditWindow.CMEditReplace(var Msg: TMessage);
  279. var
  280.   Dialog: PChar;
  281. begin
  282.   if BWCCClassNames then
  283.     Dialog := sd_BCReplace
  284.   else
  285.     Dialog := sd_Replace;
  286.   if Application^.ExecDialog(New(PSearchDialog, Init(@Self,
  287.     Dialog, SearchRec))) = id_OK then
  288.   begin
  289.     SearchRec.IsReplace := True;
  290.     DoSearch;
  291.   end;
  292. end;
  293.  
  294. { TFileWindow }
  295.  
  296. { Constructor for a TFileWindow.  Initializes its data fields using
  297.   passed parameters and default values. }
  298. constructor TFileWindow.Init(AParent: PWindowsObject; ATitle,
  299.   AFileName: PChar);
  300. begin
  301.   TEditWindow.Init(AParent, ATitle);
  302.   IsNewFile := True;
  303.   FileName := StrNew(AFileName);
  304. end;
  305.  
  306. { Dispose of the file name }
  307. destructor TFileWindow.Done;
  308. begin
  309.   StrDispose(FileName);
  310.   TEditWindow.Done;
  311. end;
  312.  
  313. { Load a TFileWindow from the stream }
  314. constructor TFileWindow.Load(var S: TStream);
  315. begin
  316.   TEditWindow.Load(S);
  317.   FileName := S.StrRead;
  318.   IsNewFile := FileName = nil;
  319. end;
  320.  
  321. { Store a TFileWindow from the stream }
  322. procedure TFileWindow.Store(var S: TStream);
  323. begin
  324.   TEditWindow.Store(S);
  325.   S.StrWrite(FileName);
  326. end;
  327.  
  328. { Performs setup for a TFileWindow, appending 'Untitled' to its caption }
  329. procedure TFileWindow.SetupWindow;
  330. begin
  331.   TEditWindow.SetupWindow;
  332.   SetFileName(FileName);
  333.   if FileName <> nil then Read;
  334. end;
  335.  
  336. { Sets the file name of the window and updates the caption.  Assumes
  337.   that the AFileName parameter and the FileName instance variable were
  338.   allocated by StrNew. }
  339. procedure TFileWindow.SetFileName(AFileName: PChar);
  340. var
  341.   NewCaption: array[0..80] of Char;
  342.   P: array[0..1] of PChar;
  343. begin
  344.   if FileName <> AFileName then
  345.   begin
  346.     StrDispose(FileName);
  347.     FileName := StrNew(AFileName);
  348.   end;
  349.   P[0] := Attr.Title;
  350.   if FileName = nil then P[1] := '(Untitled)'
  351.   else P[1] := AFileName;
  352.   if Attr.Title = nil then SetWindowText(HWindow, P[1])
  353.   else
  354.   begin
  355.     WVSPrintF(NewCaption, '%0.40s - %0.37s', P[0]);
  356.     SetWindowText(HWindow, NewCaption);
  357.   end;
  358. end;
  359.  
  360. { Begins the edit of a new file, after determining that it is Ok to
  361.   clear the TEdit's text. }
  362. procedure TFileWindow.NewFile;
  363. begin
  364.   if CanClear then
  365.   begin
  366.     Editor^.Clear;
  367.     InvalidateRect(Editor^.HWindow, nil, False);
  368.     Editor^.ClearModify;
  369.     IsNewFile := True;
  370.     SetFileName(nil);
  371.   end;
  372. end;
  373.  
  374. { Replaces the current file with the given file. }
  375. procedure TFileWindow.ReplaceWith(AFileName: PChar);
  376. begin
  377.   SetFileName(AFileName);
  378.   Read;
  379.   InvalidateRect(Editor^.HWindow, nil, False);
  380. end;
  381.  
  382. { Brings up a dialog allowing the user to open a file into this
  383.   window.  Save as selecting File|Open from the menus. }
  384. procedure TFileWindow.Open;
  385. var
  386.   TmpName: array[0..fsPathName] of Char;
  387. begin
  388.   if CanClear and (Application^.ExecDialog(New(PFileDialog,
  389.      Init(@Self, PChar(sd_FileOpen), StrCopy(TmpName, '*.*')))) = id_Ok) then
  390.     ReplaceWith(TmpName);
  391. end;
  392.  
  393. { Reads the contents of a previously-specified file into the TEdit
  394.   child control. }
  395. procedure TFileWindow.Read;
  396. const
  397.   BufferSize = 1024;
  398. var
  399.   CharsToRead: LongInt;
  400.   BlockSize: Integer;
  401.   AStream: PDosStream;
  402.   ABuffer: PChar;
  403. begin
  404.   AStream := New(PDosStream, Init(FileName, stOpen));
  405.   ABuffer := MemAlloc(BufferSize + 1);
  406.   CharsToRead := AStream^.GetSize;
  407.   if ABuffer <> nil then
  408.   begin
  409.     Editor^.Clear;
  410.     while CharsToRead > 0 do
  411.     begin
  412.       if CharsToRead > BufferSize then
  413.         BlockSize := BufferSize
  414.       else BlockSize := CharsToRead;
  415.       AStream^.Read(ABuffer^, BlockSize);
  416.       ABuffer[BlockSize] := Char(0);
  417.       Editor^.Insert(ABuffer);
  418.       CharsToRead := CharsToRead - BlockSize;
  419.     end;
  420.     IsNewFile := False;
  421.     Editor^.ClearModify;
  422.     Editor^.SetSelection(0, 0);
  423.     FreeMem(ABuffer, BufferSize + 1);
  424.   end;
  425.   Dispose(AStream, Done);
  426. end;
  427.  
  428. { Saves the contents of the TEdit child control into the file currently
  429.   being editted.  Returns true if the file was saved. }
  430. function TFileWindow.Save: Boolean;
  431. begin
  432.   Save := True;
  433.   if Editor^.IsModified then
  434.     if IsNewFile then Save := SaveAs
  435.     else Write;
  436. end;
  437.  
  438. { Saves the contents of the TEdit child control into a file whose name
  439.   is retrieved from the user, through execution of a "Save" file
  440.   dialog.  Returns true if the file was saved. }
  441. function TFileWindow.SaveAs: Boolean;
  442. var
  443.   TmpName: array[0..fsPathName] of Char;
  444. begin
  445.   SaveAs := False;
  446.   if FileName <> nil then StrCopy(TmpName, FileName)
  447.   else TmpName[0] := #0;
  448.   if Application^.ExecDialog(New(PFileDialog,
  449.       Init(@Self, PChar(sd_FileSave), TmpName))) = id_Ok then
  450.   begin
  451.     SetFileName(TmpName);
  452.     Write;
  453.     SaveAs := True;
  454.   end;
  455. end;
  456.  
  457. { Writes the contents of the TEdit child control to a previously-specified
  458.   file.  If the operation will cause truncation of the text, first confirms
  459.   (through displaying a message box) that it is OK to proceed. }
  460. procedure TFileWindow.Write;
  461. const
  462.   BufferSize = 1024;
  463. var
  464.   CharsToWrite, CharsWritten: LongInt;
  465.   BlockSize: Integer;
  466.   AStream: PDosStream;
  467.   ABuffer: pointer;
  468.   NumLines: Integer;
  469. begin
  470.   NumLines := Editor^.GetNumLines;
  471.   CharsToWrite := Editor^.GetLineIndex(NumLines-1) +
  472.     Editor^.GetLineLength(NumLines-1);
  473.   AStream := New(PDosStream, Init(FileName, stCreate));
  474.   ABuffer := MemAlloc(BufferSize + 1);
  475.   CharsWritten := 0;
  476.   if ABuffer <> nil then
  477.   begin
  478.     while CharsWritten < CharsToWrite do
  479.     begin
  480.       if CharsToWrite - CharsWritten > BufferSize then
  481.         BlockSize := BufferSize
  482.       else BlockSize := CharsToWrite - CharsWritten;
  483.       Editor^.GetSubText(ABuffer, CharsWritten, CharsWritten + BlockSize);
  484.       AStream^.Write(ABuffer^, BlockSize);
  485.       CharsWritten := CharsWritten + BlockSize;
  486.     end;
  487.     IsNewFile := False;
  488.     Editor^.ClearModify;
  489.     FreeMem(ABuffer, BufferSize + 1);
  490.   end;
  491.   Dispose(AStream, Done);
  492. end;
  493.  
  494. { Returns a Boolean value indicating whether or not it is Ok to clear
  495.   the TEdit's text.  Returns True if the text has not been changed, or
  496.   if the user Oks the clearing of the text. }
  497. function TFileWindow.CanClear: Boolean;
  498. var
  499.   S: array[0..fsPathName+27] of Char;
  500.   P: PChar;
  501.   Rslt: Integer;
  502. begin
  503.   CanClear := True;
  504.   if Editor^.IsModified then
  505.   begin
  506.     if FileName = nil then StrCopy(S, 'Untitled file has changed. Save?')
  507.     else
  508.     begin
  509.       P := FileName;
  510.       WVSPrintF(S, 'File "%s" has changed.  Save?', P);
  511.     end;
  512.     Rslt := MessageBox(HWindow, S, 'File Changed', mb_YesNoCancel or
  513.       mb_IconQuestion);
  514.     if Rslt = id_Yes then CanClear := Save
  515.     else CanClear := Rslt <> id_Cancel;
  516.   end;
  517. end;
  518.  
  519. { Returns a Boolean value indicating whether or not it is Ok to close
  520.   the TEdit's text.  Returns the result of a call to Self.CanClear. }
  521. function TFileWindow.CanClose: Boolean;
  522. begin
  523.   CanClose := CanClear;
  524. end;
  525.  
  526. { Responds to an incoming "New" command (with a cm_FileNew command
  527.   identifier) by calling Self.New. }
  528. procedure TFileWindow.CMFileNew(var Msg: TMessage);
  529. begin
  530.   NewFile;
  531. end;
  532.  
  533. { Responds to an incoming "Open" command (with a cm_FileOpen command
  534.   identifier) by calling Self.Open. }
  535. procedure TFileWindow.CMFileOpen(var Msg: TMessage);
  536. begin
  537.   Open;
  538. end;
  539.  
  540. { Responds to an incoming "Save" command (with a cm_FileSave command
  541.   identifier) by calling Self.Save. }
  542. procedure TFileWindow.CMFileSave(var Msg: TMessage);
  543. begin
  544.   Save;
  545. end;
  546.  
  547. { Responds to an incoming "SaveAs" command (with a cm_FileSaveAs command
  548.   identifier) by calling Self.SaveAs. }
  549. procedure TFileWindow.CMFileSaveAs(var Msg: TMessage);
  550. begin
  551.   SaveAs;
  552. end;
  553.  
  554. procedure RegisterStdWnds;
  555. begin
  556.   RegisterType(REditWindow);
  557.   RegisterType(RFileWindow);
  558. end;
  559.  
  560. {Here is our EditWindows Spell method}
  561. procedure TEditWindow.CMSpell;
  562. var
  563. startpos,endpos,i,chs,lines,origin,countoffset:integer;
  564. chz:array[0..1] of char;
  565. ch:char;
  566. AWord,NewWord : array[0..30] of char;
  567. Handle,EdHandle :THandle;
  568. EdPnt : pointer;
  569. nextcount,result,FirstLine,CurrentLine,NOLinesVisible,
  570.           DistFromMenuBar,NCAHeight,TextY,ScreenHeight : integer;
  571. Dialog : PDlgWindow;
  572. Tm : TTextMetric;
  573. EditDC: HDC;
  574. W:Word;
  575. Points :TPoint;
  576.  
  577. { Given a text buffer, read it and return the next word }
  578. { We can use out Edit contol like a very long PChar string by
  579.  getting a pointer to the text it contains, then parsing this long string
  580.  and extacting the words one by one}
  581.  
  582. function GetWord(S,F:Pchar): PChar;
  583. var
  584.   C : Char;
  585.   I: Integer;
  586. begin
  587.   I := 0;
  588.   C := #0;
  589.   { find first letter }
  590.   while not (nextcount > Strlen(F)) and not (UpCase(C) in ['A'..'Z']) do
  591.   begin
  592.     C:= F[nextcount];
  593.     inc(nextcount);
  594.   end;
  595.   { special test in case end of file }
  596.   if (nextcount = Strlen(F)) and (UpCase(C) in ['A'..'Z']) then
  597.   begin
  598.     if (I < MaxWordLen) then
  599.      begin
  600.       S[I] := C;
  601.       inc(I);
  602.      end;
  603.   end
  604.   else
  605.     { read chars from file, append to S }
  606.     while (UpCase(C) in ['A'..'Z','''','-']) and not (nextcount > Strlen(F)) do
  607.     begin
  608.       if I < MaxWordLen then
  609.       begin
  610.         S[I] := C;
  611.         Inc(I);
  612.       end;
  613.       C:= F[nextcount];
  614.       inc(nextcount);
  615.     end;
  616.   S[I] := #0;
  617.   GetWord := S;
  618. end;
  619.  
  620. begin
  621.   {Load Spelling DLL}
  622.   LoadCursor(0,IDC_WAIT);
  623.   Handle := LoadLibrary('Spelmate.Dll');
  624.   LoadCursor(0,IDC_ARROW);
  625.   if Handle < 32 then  {if failed to load/find DLL inform user}
  626.   begin
  627.    MessageBeep(0);
  628.    MessageBox(HWindow,'Unable to Load Spelling Dll','Application Error',MB_OK or
  629.    MB_ICONSTOP);
  630.    Exit;
  631.   end;
  632.   {Set our function addresses up to those in the DLL, should check really
  633.    that they are not nil, as this indicates an error}
  634.   @SpelmateInit := GetProcAddress(Handle,'SpelmateInit');
  635.   @SpellCheck := GetProcAddress(Handle,'Spellcheck');
  636.   @SuggestWord := GetProcAddress(Handle,'SuggestWord');
  637.   @displayAtTop := GetProcAddress(Handle,'DisplayAtTop');
  638.   {This dialog is just to keep the user happy while the main dictionary is
  639.    being loaded as this can take a few seconds}
  640.   Dialog :=New(PDlgWindow,Init(nil,'LoadSpell'));
  641.   Application^.MakeWindow(Dialog);
  642.   {Ask the DLL to init, and get back the status information}
  643.   result := SpelmateInit;
  644.   {remove the dialog now DLL loaded}
  645.   Dialog^.done;
  646.   {if result = -1 then OK}
  647.   if result <> -1 then
  648.   begin
  649.     MessageBox(HWindow,'Cannot Access Spelling Dictionary','Application Error',MB_OK or MB_ICONSTOP);
  650.     Exit;
  651.   { if result not -1 then an error occurred, and so do not spell check}
  652.   { Possible error codes are }
  653.   { 0 not enough memory }
  654.   { 1 Main dictionary not found}
  655.   { 2 Stream access error, main dictionary}
  656.   { 3 Initialisation error, main dictionary}
  657.   { 4 Read error, main dictionary}
  658.   { 5 Corrupt file or wrong file type, error, main dictionary}
  659.   { 6 Stream access error, private dictionary}
  660.   { 7 Initialisation error, private dictionary}
  661.   { 8 Read error, private dictionary}
  662.   { 9 Corrupt file or wrong file type, error, private dictionary}
  663.   end;
  664.   Editor^.GetSelection(startpos,endpos); {set pointers to current cursor position}
  665.   nextcount := startpos;
  666.   origin := startpos;{ remember where started}
  667.   Edhandle := Editor^.GetHandle;{ get a handle to local edit buffer}
  668.   EdPnt := LocalLock(EdHandle); { make a pointer to editor text buffer}
  669.   repeat
  670.   if GetWord(AWord,EdPnt)^ <> #0 then  {while not end of editor text,scan}
  671.   begin
  672.   if AWord[StrLen(AWord)-1] = '''' then
  673.   AWord[Strlen(AWord)-1] := #0;{if word was in quotes,remove end one}
  674.   if not spellcheck(AWord) then {if word not found in main,private or IgnoreAll dictionary}
  675.   begin
  676.     Editor^.SetSelection(nextcount-Strlen(AWord)-1,nextcount-1); {Highlight Word not in dictionary}
  677.  
  678.     W := LoWord(GetVersion);
  679.     if (Lo(W) = 3) and (Hi(W) >= 10) then {check Windows > 3.0 as using 3.1 call}
  680.     begin
  681.       {Find if text in upper half of screen (NOT trivial!)}
  682.       FirstLine := SendMessage(Editor^.HWindow,EM_GETFIRSTVISIBLELINE,0,0);
  683.       CurrentLine := Editor^.GetLineFromPos(-1);  {-1 gets line selected text is on}
  684.       NoLinesVisible := CurrentLine - FirstLine + 1;
  685.  
  686.       {get the height of each line}
  687.       EditDC := GetDC(Editor^.HWindow);
  688.       GetTextMetrics(EditDC,Tm);
  689.       ReleaseDC(Editor^.HWindow,EditDC);
  690.  
  691.       {Now get the distance from the text to the top of the client area}
  692.       {The following is not 100% accurate but is good enough for our purposes}
  693.       DistFromMenuBar := Tm.tmHeight * NoLinesVisible;
  694.  
  695.       {get height of menu bar + title + frame (SM_CYCAPTION does title & frame)}
  696.       NCAHeight := GetSystemMetrics(SM_CYMENU) + GetSystemMetrics(SM_CYCAPTION);
  697.  
  698.  
  699.       {calculate relative Y location of text}
  700.       TextY := NCAHeight + DistFromMenuBar;
  701.  
  702.       {convert to absolute screen coordinates}
  703.       Points.X := 0;
  704.       Points.Y := TextY;
  705.       ClienttoScreen(Editor^.HWindow,Points);
  706.       TextY := Points.Y;
  707.  
  708.       {get height of screen}
  709.       ScreenHeight := GetSystemMetrics(SM_CYSCREEN);
  710.  
  711.       {FINALLY! if text in lower half of screen put suggest word dialog at top}
  712.       if (TextY > (ScreenHeight div 2)) then
  713.          DisplayAtTop;
  714.     end;
  715.  
  716.     StrCopy(NewWord,suggestword(AWord)); {get word user chose during suggestion}
  717.     if NewWord[0] = #0 then {if blank, cancel was selected}
  718.     begin
  719.     Editor^.SetSelection(origin,origin); {return to start position}
  720.     Exit;
  721.     end
  722.   else
  723.     begin
  724.       if StrComp(Aword,NewWord) <> 0 then {if words are not the same,change}
  725.       begin
  726.         countoffset := Strlen(NewWord) - Strlen(AWord);
  727.         Editor^.DeleteSubText(nextcount-Strlen(AWord)-1,nextcount-1); {remove old highlighted word}
  728.         Editor^.Insert(NewWord); {replace with new one}
  729.         nextcount := nextcount + countoffset; {adjust pointer in case new word was larger or smaller}
  730.       end;
  731.     end;
  732.   end;
  733.   end;
  734.   until AWord[0] = #0;
  735. LocalUnlock(EdHandle); {release Editor Memory Block}
  736. FreeLibrary(Handle); {release Spelmate DLL, or you may wait until your program exits, and do it in your destructor}
  737. MessageBox(HWindow,'Spell Checking Complete','All Done!',MB_OK);
  738. Editor^.SetSelection(origin,origin); {return to start position}
  739. end;
  740.  
  741. end.
  742.