RxRichEd.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:155k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1.     Frame := FFrameForm;
  2.     Doc := FDocForm;
  3.     CreateAccelTable;
  4.     with lpFrameInfo^ do begin
  5.       fMDIApp := False;
  6.       FFrameForm.GetWindow(hWndFrame);
  7.       hAccel := FAccelTable;
  8.       cAccelEntries := FAccelCount;
  9.     end;
  10.     Result := S_OK;
  11.   end
  12.   else Result := E_NOTIMPL;
  13. {$ELSE}
  14.   Result := E_NOTIMPL;
  15. {$ENDIF}
  16. end;
  17. function TRichEditOleCallback.QueryInsertObject(const clsid: TCLSID; const stg: IStorage;
  18.   cp: Longint): HResult;
  19. begin
  20.   Result := NOERROR;
  21. end;
  22. function TRichEditOleCallback.DeleteObject(const oleobj: IOleObject): HResult;
  23. begin
  24.   if Assigned(oleobj) then oleobj.Close(OLECLOSE_NOSAVE);
  25.   Result := NOERROR;
  26. end;
  27. function TRichEditOleCallback.QueryAcceptData(const dataobj: IDataObject;
  28.   var cfFormat: TClipFormat; reco: DWORD; fReally: BOOL;
  29.   hMetaPict: HGLOBAL): HResult;
  30. begin
  31.   Result := S_OK;
  32. end;
  33. function TRichEditOleCallback.ContextSensitiveHelp(fEnterMode: BOOL): HResult;
  34. begin
  35.   Result := NOERROR;
  36. end;
  37. function TRichEditOleCallback.GetClipboardData(const chrg: TCharRange; reco: DWORD;
  38.   {$IFDEF RX_D3} out {$ELSE} var {$ENDIF} dataobj: IDataObject): HResult;
  39. begin
  40.   Result := E_NOTIMPL;
  41. end;
  42. function TRichEditOleCallback.GetDragDropEffect(fDrag: BOOL; grfKeyState: DWORD;
  43.   var dwEffect: DWORD): HResult;
  44. begin
  45.   Result := E_NOTIMPL;
  46. end;
  47. function TRichEditOleCallback.GetContextMenu(seltype: Word;
  48.   const oleobj: IOleObject; const chrg: TCharRange;
  49.   {$IFDEF RX_D3} out {$ELSE} var {$ENDIF} menu: HMENU): HResult;
  50. begin
  51.   Result := E_NOTIMPL;
  52. end;
  53. function TRichEditOleCallback.ShowContainerUI(fShow: BOOL): HResult;
  54. begin
  55. {$IFDEF RX_D3}
  56.   if not fShow then AssignFrame;
  57.   if Assigned(FFrameForm) then begin
  58.     if fShow then begin
  59.       FFrameForm.SetMenu(0, 0, 0);
  60.       FFrameForm.ClearBorderSpace;
  61.       FRichEdit.SetUIActive(False);
  62.       DestroyAccelTable;
  63. {$IFDEF RX_D4}
  64.       TForm(FFrameForm.Form).AutoScroll := FAutoScroll;
  65. {$ENDIF}
  66.       FFrameForm := nil;
  67.       FDocForm := nil;
  68.     end
  69.     else begin
  70. {$IFDEF RX_D4}
  71.       FAutoScroll := TForm(FFrameForm.Form).AutoScroll;
  72.       TForm(FFrameForm.Form).AutoScroll := False;
  73. {$ENDIF}
  74.       FRichEdit.SetUIActive(True);
  75.     end;
  76.     Result := S_OK;
  77.   end
  78.   else Result := E_NOTIMPL;
  79. {$ELSE}
  80.   Result := E_NOTIMPL;
  81. {$ENDIF}
  82. end;
  83. { TOleUIObjInfo - helper interface for Object Properties dialog }
  84. type
  85. {$IFDEF RX_D3}
  86.   TOleUIObjInfo = class(TInterfacedObject, IOleUIObjInfo)
  87. {$ELSE}
  88.   TOleUIObjInfo = class(IOleUIObjInfo)
  89. {$ENDIF}
  90.   private
  91.     FRichEdit: TRxCustomRichEdit;
  92.     FReObject: TReObject;
  93.   public
  94.     constructor Create(RichEdit: TRxCustomRichEdit; ReObject: TReObject);
  95. {$IFNDEF RX_D3}
  96.     function QueryInterface(const iid: TIID; var obj): HResult; override;
  97.     function AddRef: Longint; override;
  98.     function Release: Longint; override;
  99. {$ENDIF}
  100.     function GetObjectInfo(dwObject: Longint;
  101.       var dwObjSize: Longint; var lpszLabel: PChar;
  102.       var lpszType: PChar; var lpszShortType: PChar;
  103.       var lpszLocation: PChar): HResult;
  104.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  105.     function GetConvertInfo(dwObject: Longint; var ClassID: TCLSID;
  106.       var wFormat: Word; var ConvertDefaultClassID: TCLSID;
  107.       var lpClsidExclude: PCLSID; var cClsidExclude: Longint): HResult;
  108.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  109.     function ConvertObject(dwObject: Longint;
  110.       const clsidNew: TCLSID): HResult;
  111.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  112.     function GetViewInfo(dwObject: Longint; var hMetaPict: HGlobal;
  113.       var dvAspect: Longint; var nCurrentScale: Integer): HResult;
  114.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  115.     function SetViewInfo(dwObject: Longint; hMetaPict: HGlobal;
  116.       dvAspect: Longint; nCurrentScale: Integer;
  117.       bRelativeToOrig: BOOL): HResult;
  118.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  119.   end;
  120. constructor TOleUIObjInfo.Create(RichEdit: TRxCustomRichEdit;
  121.   ReObject: TReObject);
  122. begin
  123.   inherited Create;
  124.   FRichEdit := RichEdit;
  125.   FReObject := ReObject;
  126. end;
  127. {$IFNDEF RX_D3}
  128. function TOleUIObjInfo.QueryInterface(const iid: TIID; var obj): HResult;
  129. begin
  130.   Pointer(obj) := nil;
  131.   Result := E_NOINTERFACE;
  132. end;
  133. function TOleUIObjInfo.AddRef: Longint;
  134. begin
  135.   Result := 0;
  136. end;
  137. function TOleUIObjInfo.Release: Longint;
  138. begin
  139.   Result := 0;
  140. end;
  141. {$ENDIF RX_D3}
  142. function TOleUIObjInfo.GetObjectInfo(dwObject: Longint;
  143.   var dwObjSize: Longint; var lpszLabel: PChar;
  144.   var lpszType: PChar; var lpszShortType: PChar;
  145.   var lpszLocation: PChar): HResult;
  146. begin
  147.   if @dwObjSize <> nil then
  148.     dwObjSize := -1 { Unknown size };
  149.   if @lpszLabel <> nil then
  150.     lpszLabel := CoAllocCStr(GetFullNameStr(FReObject.poleobj));
  151.   if @lpszType <> nil then
  152.     lpszType := CoAllocCStr(GetFullNameStr(FReObject.poleobj));
  153.   if @lpszShortType <> nil then
  154.     lpszShortType := CoAllocCStr(GetShortNameStr(FReObject.poleobj));
  155.   if (@lpszLocation <> nil) then begin
  156.     if Trim(FRichEdit.Title) <> '' then
  157.       lpszLocation := CoAllocCStr(Format('%s - %s',
  158.         [FRichEdit.Title, Application.Title]))
  159.     else
  160.       lpszLocation := CoAllocCStr(Application.Title);
  161.   end;
  162.   Result := S_OK;
  163. end;
  164. function TOleUIObjInfo.GetConvertInfo(dwObject: Longint; var ClassID: TCLSID;
  165.   var wFormat: Word; var ConvertDefaultClassID: TCLSID;
  166.   var lpClsidExclude: PCLSID; var cClsidExclude: Longint): HResult;
  167. begin
  168.   FReObject.poleobj.GetUserClassID(ClassID);
  169.   Result := S_OK;
  170. end;
  171. function TOleUIObjInfo.ConvertObject(dwObject: Longint;
  172.   const clsidNew: TCLSID): HResult;
  173. begin
  174.   Result := E_NOTIMPL;
  175. end;
  176. function TOleUIObjInfo.GetViewInfo(dwObject: Longint; var hMetaPict: HGlobal;
  177.   var dvAspect: Longint; var nCurrentScale: Integer): HResult;
  178. begin
  179.   if @hMetaPict <> nil then
  180.     hMetaPict := GetIconMetaPict(FReObject.poleobj, FReObject.dvAspect);
  181.   if @dvAspect <> nil then dvAspect := FReObject.dvAspect;
  182.   if @nCurrentScale <> nil then nCurrentScale := 0;
  183.   Result := S_OK;
  184. end;
  185. function TOleUIObjInfo.SetViewInfo(dwObject: Longint; hMetaPict: HGlobal;
  186.   dvAspect: Longint; nCurrentScale: Integer;
  187.   bRelativeToOrig: BOOL): HResult;
  188. var
  189.   Iconic: Boolean;
  190. begin
  191.   if Assigned(FRichEdit.FRichEditOle) then begin
  192.     case dvAspect of
  193.       DVASPECT_CONTENT:
  194.         Iconic := False;
  195.       DVASPECT_ICON:
  196.         Iconic := True;
  197.       else
  198.         Iconic := FReObject.dvAspect = DVASPECT_ICON;
  199.     end;
  200.     IRichEditOle(FRichEdit.FRichEditOle).InPlaceDeactivate;
  201.     Result := OleSetDrawAspect(FReObject.poleobj, Iconic, hMetaPict,
  202.       FReObject.dvAspect);
  203.     if Succeeded(Result) then
  204.       IRichEditOle(FRichEdit.FRichEditOle).SetDvaspect(
  205.         Longint(REO_IOB_SELECTION), FReObject.dvAspect);
  206.   end
  207.   else Result := E_NOTIMPL;
  208. end;
  209. { TOleUILinkInfo - helper interface for Object Properties dialog }
  210. type
  211. {$IFDEF RX_D3}
  212.   TOleUILinkInfo = class(TInterfacedObject, IOleUILinkInfo)
  213. {$ELSE}
  214.   TOleUILinkInfo = class(IOleUILinkInfo)
  215. {$ENDIF}
  216.   private
  217.     FReObject: TReObject;
  218.     FRichEdit: TRxCustomRichEdit;
  219.     FOleLink: IOleLink;
  220.   public
  221.     constructor Create(RichEdit: TRxCustomRichEdit; ReObject: TReObject);
  222. {$IFNDEF RX_D3}
  223.     destructor Destroy; override;
  224.     function QueryInterface(const iid: TIID; var obj): HResult; override;
  225.     function AddRef: Longint; override;
  226.     function Release: Longint; override;
  227. {$ENDIF}
  228.     function GetNextLink(dwLink: Longint): Longint;
  229.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  230.     function SetLinkUpdateOptions(dwLink: Longint;
  231.       dwUpdateOpt: Longint): HResult;
  232.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  233.     function GetLinkUpdateOptions(dwLink: Longint;
  234.       var dwUpdateOpt: Longint): HResult;
  235.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  236.     function SetLinkSource(dwLink: Longint; pszDisplayName: PChar;
  237.       lenFileName: Longint; var chEaten: Longint;
  238.       fValidateSource: BOOL): HResult;
  239.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  240.     function GetLinkSource(dwLink: Longint; var pszDisplayName: PChar;
  241.       var lenFileName: Longint; var pszFullLinkType: PChar;
  242.       var pszShortLinkType: PChar; var fSourceAvailable: BOOL;
  243.       var fIsSelected: BOOL): HResult;
  244.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  245.     function OpenLinkSource(dwLink: Longint): HResult;
  246.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  247.     function UpdateLink(dwLink: Longint; fErrorMessage: BOOL;
  248.       fErrorAction: BOOL): HResult;
  249.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  250.     function CancelLink(dwLink: Longint): HResult;
  251.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  252.     function GetLastUpdate(dwLink: Longint;
  253.       var LastUpdate: TFileTime): HResult;
  254.       {$IFDEF RX_D3} stdcall {$ELSE} override {$ENDIF};
  255.   end;
  256. {$IFDEF RX_D3}
  257. procedure LinkError(const Ident: string);
  258. begin
  259.   Application.MessageBox(PChar(Ident), PChar(SLinkProperties),
  260.     MB_OK or MB_ICONSTOP);
  261. end;
  262. {$ELSE}
  263. procedure LinkError(Ident: Integer);
  264. begin
  265.   Application.MessageBox(PChar(LoadStr(Ident)),
  266.     PChar(LoadStr(SLinkProperties)), MB_OK or MB_ICONSTOP);
  267. end;
  268. {$ENDIF}
  269. constructor TOleUILinkInfo.Create(RichEdit: TRxCustomRichEdit;
  270.   ReObject: TReObject);
  271. begin
  272.   inherited Create;
  273.   FReObject := ReObject;
  274.   FRichEdit := RichEdit;
  275. {$IFDEF RX_D3}
  276.   OleCheck(FReObject.poleobj.QueryInterface(IOleLink, FOleLink));
  277. {$ELSE}
  278.   OleCheck(FReObject.poleobj.QueryInterface(IID_IOleLink, FOleLink));
  279. {$ENDIF}
  280. end;
  281. {$IFNDEF RX_D3}
  282. destructor TOleUILinkInfo.Destroy;
  283. begin
  284.   ReleaseObject(FOleLink);
  285.   inherited Destroy;
  286. end;
  287. function TOleUILinkInfo.QueryInterface(const iid: TIID; var obj): HResult;
  288. begin
  289.   Pointer(obj) := nil;
  290.   Result := E_NOINTERFACE;
  291. end;
  292. function TOleUILinkInfo.AddRef: Longint;
  293. begin
  294.   Result := 0;
  295. end;
  296. function TOleUILinkInfo.Release: Longint;
  297. begin
  298.   Result := 0;
  299. end;
  300. {$ENDIF}
  301. function TOleUILinkInfo.GetNextLink(dwLink: Longint): Longint;
  302. begin
  303.   if dwLink = 0 then Result := Longint(FRichEdit)
  304.   else Result := 0;
  305. end;
  306. function TOleUILinkInfo.SetLinkUpdateOptions(dwLink: Longint;
  307.   dwUpdateOpt: Longint): HResult;
  308. begin
  309.   Result := FOleLink.SetUpdateOptions(dwUpdateOpt);
  310.   if Succeeded(Result) then FRichEdit.Modified := True;
  311. end;
  312. function TOleUILinkInfo.GetLinkUpdateOptions(dwLink: Longint;
  313.   var dwUpdateOpt: Longint): HResult;
  314. begin
  315.   Result := FOleLink.GetUpdateOptions(dwUpdateOpt);
  316. end;
  317. function TOleUILinkInfo.SetLinkSource(dwLink: Longint; pszDisplayName: PChar;
  318.   lenFileName: Longint; var chEaten: Longint;
  319.   fValidateSource: BOOL): HResult;
  320. var
  321.   DisplayName: string;
  322.   Buffer: array[0..255] of WideChar;
  323. begin
  324.   Result := E_FAIL;
  325.   if fValidateSource then begin
  326.     DisplayName := pszDisplayName;
  327.     if Succeeded(FOleLink.SetSourceDisplayName(StringToWideChar(DisplayName,
  328.       Buffer, SizeOf(Buffer) div 2))) then
  329.     begin
  330.       chEaten := Length(DisplayName);
  331.       try
  332.         OleCheck(FReObject.poleobj.Update);
  333.       except
  334.         Application.HandleException(FRichEdit);
  335.       end;
  336.       Result := S_OK;
  337.     end;
  338.   end
  339.   else LinkError(SInvalidLinkSource);
  340. end;
  341. function TOleUILinkInfo.GetLinkSource(dwLink: Longint; var pszDisplayName: PChar;
  342.   var lenFileName: Longint; var pszFullLinkType: PChar;
  343.   var pszShortLinkType: PChar; var fSourceAvailable: BOOL;
  344.   var fIsSelected: BOOL): HResult;
  345. var
  346.   Moniker: IMoniker;
  347. begin
  348.   if @pszDisplayName <> nil then
  349.     pszDisplayName := CoAllocCStr(GetDisplayNameStr(FOleLink));
  350.   if @lenFileName <> nil then begin
  351.     lenFileName := 0;
  352.     FOleLink.GetSourceMoniker(Moniker);
  353.     if Moniker <> nil then begin
  354.       lenFileName := OleStdGetLenFilePrefixOfMoniker(Moniker);
  355.       ReleaseObject(Moniker);
  356.     end;
  357.   end;
  358.   if @pszFullLinkType <> nil then
  359.     pszFullLinkType := CoAllocCStr(GetFullNameStr(FReObject.poleobj));
  360.   if @pszShortLinkType <> nil then
  361.     pszShortLinkType := CoAllocCStr(GetShortNameStr(FReObject.poleobj));
  362.   Result := S_OK;
  363. end;
  364. function TOleUILinkInfo.OpenLinkSource(dwLink: Longint): HResult;
  365. begin
  366.   try
  367.     OleCheck(FReObject.poleobj.DoVerb(OLEIVERB_SHOW, nil, FReObject.polesite,
  368.       0, FRichEdit.Handle, FRichEdit.ClientRect));
  369.   except
  370.     Application.HandleException(FRichEdit);
  371.   end;
  372.   Result := S_OK;
  373. end;
  374. function TOleUILinkInfo.UpdateLink(dwLink: Longint; fErrorMessage: BOOL;
  375.   fErrorAction: BOOL): HResult;
  376. begin
  377.   try
  378.     OleCheck(FReObject.poleobj.Update);
  379.   except
  380.     Application.HandleException(FRichEdit);
  381.   end;
  382.   Result := S_OK;
  383. end;
  384. function TOleUILinkInfo.CancelLink(dwLink: Longint): HResult;
  385. begin
  386.   LinkError(SCannotBreakLink);
  387.   Result := E_NOTIMPL;
  388. end;
  389. function TOleUILinkInfo.GetLastUpdate(dwLink: Longint;
  390.   var LastUpdate: TFileTime): HResult;
  391. begin
  392.   Result := S_OK;
  393. end;
  394. { Get RichEdit OLE interface }
  395. function GetRichEditOle(Wnd: HWnd; var RichEditOle): Boolean;
  396. begin
  397.   Result := SendMessage(Wnd, EM_GETOLEINTERFACE, 0, Longint(@RichEditOle)) <> 0;
  398. end;
  399. { TRichEditStrings }
  400. const
  401.   ReadError  = $0001;
  402.   WriteError = $0002;
  403.   NoError    = $0000;
  404. type
  405.   TRichEditStrings = class(TStrings)
  406.   private
  407.     RichEdit: TRxCustomRichEdit;
  408.     FFormat: TRichStreamFormat;
  409.     FMode: TRichStreamModes;
  410.     FConverter: TConversion;
  411.     procedure EnableChange(const Value: Boolean);
  412.   protected
  413.     function Get(Index: Integer): string; override;
  414.     function GetCount: Integer; override;
  415.     procedure Put(Index: Integer; const S: string); override;
  416.     procedure SetUpdateState(Updating: Boolean); override;
  417.     procedure SetTextStr(const Value: string); override;
  418.   public
  419.     destructor Destroy; override;
  420.     procedure Clear; override;
  421.     procedure AddStrings(Strings: TStrings); override;
  422.     procedure Delete(Index: Integer); override;
  423.     procedure Insert(Index: Integer; const S: string); override;
  424.     procedure LoadFromFile(const FileName: string); override;
  425.     procedure LoadFromStream(Stream: TStream); override;
  426.     procedure SaveToFile(const FileName: string); override;
  427.     procedure SaveToStream(Stream: TStream); override;
  428.     property Format: TRichStreamFormat read FFormat write FFormat;
  429.     property Mode: TRichStreamModes read FMode write FMode;
  430.   end;
  431. destructor TRichEditStrings.Destroy;
  432. begin
  433.   FConverter.Free;
  434.   inherited Destroy;
  435. end;
  436. procedure TRichEditStrings.AddStrings(Strings: TStrings);
  437. var
  438.   SelChange: TNotifyEvent;
  439. begin
  440.   SelChange := RichEdit.OnSelectionChange;
  441.   RichEdit.OnSelectionChange := nil;
  442.   try
  443.     inherited AddStrings(Strings);
  444.   finally
  445.     RichEdit.OnSelectionChange := SelChange;
  446.   end;
  447. end;
  448. function TRichEditStrings.GetCount: Integer;
  449. begin
  450.   with RichEdit do begin
  451.     Result := SendMessage(Handle, EM_GETLINECOUNT, 0, 0);
  452.     if GetLineLength(GetLineIndex(Result - 1)) = 0 then Dec(Result);
  453.   end;
  454. end;
  455. function TRichEditStrings.Get(Index: Integer): string;
  456. var
  457.   Text: array[0..4095] of Char;
  458.   L: Integer;
  459. begin
  460.   Word((@Text)^) := SizeOf(Text);
  461.   L := SendMessage(RichEdit.Handle, EM_GETLINE, Index, Longint(@Text));
  462.   if (Text[L - 2] = #13) and (Text[L - 1] = #10) then Dec(L, 2)
  463.   else if (RichEditVersion >= 2) and (Text[L - 1] = #13) then Dec(L);
  464.   SetString(Result, Text, L);
  465. end;
  466. procedure TRichEditStrings.Put(Index: Integer; const S: string);
  467. var
  468.   Selection: TCharRange;
  469. begin
  470.   if Index >= 0 then
  471.   begin
  472.     Selection.cpMin := RichEdit.GetLineIndex(Index);
  473.     if Selection.cpMin <> -1 then begin
  474.       Selection.cpMax := Selection.cpMin +
  475.         RichEdit.GetLineLength(Selection.cpMin);
  476.       SendMessage(RichEdit.Handle, EM_EXSETSEL, 0, Longint(@Selection));
  477.       RichEdit.FLinesUpdating := True;
  478.       try
  479.         SendMessage(RichEdit.Handle, EM_REPLACESEL, 0, Longint(PChar(S)));
  480.       finally
  481.         RichEdit.FLinesUpdating := False;
  482.       end;
  483.     end;
  484.   end;
  485. end;
  486. procedure TRichEditStrings.Insert(Index: Integer; const S: string);
  487. var
  488.   L: Integer;
  489.   Selection: TCharRange;
  490.   Fmt: PChar;
  491.   Str: string;
  492. begin
  493.   if Index >= 0 then begin
  494.     Selection.cpMin := RichEdit.GetLineIndex(Index);
  495.     if Selection.cpMin >= 0 then begin
  496.       if RichEditVersion = 1 then Fmt := '%s'#13#10
  497.       else Fmt := '%s'#13;
  498.     end
  499.     else begin
  500.       Selection.cpMin := RichEdit.GetLineIndex(Index - 1);
  501.       if Selection.cpMin < 0 then Exit;
  502.       L := RichEdit.GetLineLength(Selection.cpMin);
  503.       if L = 0 then Exit;
  504.       Inc(Selection.cpMin, L);
  505.       if RichEditVersion = 1 then Fmt := #13#10'%s'
  506.       else Fmt := #13'%s';
  507.     end;
  508.     Selection.cpMax := Selection.cpMin;
  509.     SendMessage(RichEdit.Handle, EM_EXSETSEL, 0, Longint(@Selection));
  510.     Str := SysUtils.Format(Fmt, [S]);
  511.     RichEdit.FLinesUpdating := True;
  512.     try
  513.       SendMessage(RichEdit.Handle, EM_REPLACESEL, 0, Longint(PChar(Str)));
  514.     finally
  515.       RichEdit.FLinesUpdating := False;
  516.     end;
  517.     if RichEditVersion = 1 then
  518.       if RichEdit.SelStart <> (Selection.cpMax + Length(Str)) then
  519.         raise EOutOfResources.Create(ResStr(sRichEditInsertError));
  520.   end;
  521. end;
  522. procedure TRichEditStrings.Delete(Index: Integer);
  523. const
  524.   Empty: PChar = '';
  525. var
  526.   Selection: TCharRange;
  527. begin
  528.   if Index < 0 then Exit;
  529.   Selection.cpMin := RichEdit.GetLineIndex(Index);
  530.   if Selection.cpMin <> -1 then begin
  531.     Selection.cpMax := RichEdit.GetLineIndex(Index + 1);
  532.     if Selection.cpMax = -1 then
  533.       Selection.cpMax := Selection.cpMin +
  534.         RichEdit.GetLineLength(Selection.cpMin);
  535.     SendMessage(RichEdit.Handle, EM_EXSETSEL, 0, Longint(@Selection));
  536.     RichEdit.FLinesUpdating := True;
  537.     try
  538.       SendMessage(RichEdit.Handle, EM_REPLACESEL, 0, Longint(Empty));
  539.     finally
  540.       RichEdit.FLinesUpdating := False;
  541.     end;
  542.   end;
  543. end;
  544. procedure TRichEditStrings.Clear;
  545. begin
  546.   RichEdit.Clear;
  547. end;
  548. procedure TRichEditStrings.SetUpdateState(Updating: Boolean);
  549. begin
  550.   if RichEdit.Showing then
  551.     SendMessage(RichEdit.Handle, WM_SETREDRAW, Ord(not Updating), 0);
  552.   if not Updating then begin
  553.     RichEdit.Refresh;
  554.     RichEdit.Perform(CM_TEXTCHANGED, 0, 0);
  555.   end;
  556. end;
  557. procedure TRichEditStrings.EnableChange(const Value: Boolean);
  558. var
  559.   EventMask: Longint;
  560. begin
  561.   with RichEdit do begin
  562.     EventMask := SendMessage(Handle, EM_GETEVENTMASK, 0, 0);
  563.     if Value then
  564.       EventMask := EventMask or ENM_CHANGE
  565.     else
  566.       EventMask := EventMask and not ENM_CHANGE;
  567.     SendMessage(Handle, EM_SETEVENTMASK, 0, EventMask);
  568.   end;
  569. end;
  570. procedure TRichEditStrings.SetTextStr(const Value: string);
  571. begin
  572.   EnableChange(False);
  573.   try
  574.     inherited SetTextStr(Value);
  575.   finally
  576.     EnableChange(True);
  577.   end;
  578. end;
  579. function AdjustLineBreaks(Dest, Source: PChar): Integer; assembler;
  580. asm
  581.         PUSH    ESI
  582.         PUSH    EDI
  583.         MOV     EDI,EAX
  584.         MOV     ESI,EDX
  585.         MOV     EDX,EAX
  586.         CLD
  587. @@1:    LODSB
  588. @@2:    OR      AL,AL
  589.         JE      @@4
  590.         CMP     AL,0AH
  591.         JE      @@3
  592.         STOSB
  593.         CMP     AL,0DH
  594.         JNE     @@1
  595.         MOV     AL,0AH
  596.         STOSB
  597.         LODSB
  598.         CMP     AL,0AH
  599.         JE      @@1
  600.         JMP     @@2
  601. @@3:    MOV     EAX,0A0DH
  602.         STOSW
  603.         JMP     @@1
  604. @@4:    STOSB
  605.         LEA     EAX,[EDI-1]
  606.         SUB     EAX,EDX
  607.         POP     EDI
  608.         POP     ESI
  609. end;
  610. function StreamSave(dwCookie: Longint; pbBuff: PByte;
  611.   cb: Longint; var pcb: Longint): Longint; stdcall;
  612. var
  613.   StreamInfo: PRichEditStreamInfo;
  614. begin
  615.   Result := NoError;
  616.   StreamInfo := PRichEditStreamInfo(Pointer(dwCookie));
  617.   try
  618.     pcb := 0;
  619.     if StreamInfo^.Converter <> nil then
  620.       pcb := StreamInfo^.Converter.ConvertWriteStream(StreamInfo^.Stream, PChar(pbBuff), cb);
  621.   except
  622.     Result := WriteError;
  623.   end;
  624. end;
  625. function StreamLoad(dwCookie: Longint; pbBuff: PByte;
  626.   cb: Longint; var pcb: Longint): Longint; stdcall;
  627. var
  628.   Buffer, pBuff: PChar;
  629.   StreamInfo: PRichEditStreamInfo;
  630. begin
  631.   Result := NoError;
  632.   StreamInfo := PRichEditStreamInfo(Pointer(dwCookie));
  633.   Buffer := StrAlloc(cb + 1);
  634.   try
  635.     cb := cb div 2;
  636.     pcb := 0;
  637.     pBuff := Buffer + cb;
  638.     try
  639.       if StreamInfo^.Converter <> nil then
  640.         pcb := StreamInfo^.Converter.ConvertReadStream(StreamInfo^.Stream, pBuff, cb);
  641.       if pcb > 0 then
  642.       begin
  643.         pBuff[pcb] := #0;
  644.         if pBuff[pcb - 1] = #13 then pBuff[pcb - 1] := #0;
  645.         pcb := AdjustLineBreaks(Buffer, pBuff);
  646.         Move(Buffer^, pbBuff^, pcb);
  647.       end;
  648.     except
  649.       Result := ReadError;
  650.     end;
  651.   finally
  652.     StrDispose(Buffer);
  653.   end;
  654. end;
  655. procedure TRichEditStrings.LoadFromStream(Stream: TStream);
  656. var
  657.   EditStream: TEditStream;
  658.   Position: Longint;
  659.   TextType: Longint;
  660.   StreamInfo: TRichEditStreamInfo;
  661.   Converter: TConversion;
  662. begin
  663.   StreamInfo.Stream := Stream;
  664.   if FConverter <> nil then Converter := FConverter
  665.   else Converter := RichEdit.DefaultConverter.Create;
  666.   StreamInfo.Converter := Converter;
  667.   try
  668.     with EditStream do
  669.     begin
  670.       dwCookie := Longint(Pointer(@StreamInfo));
  671.       pfnCallBack := @StreamLoad;
  672.       dwError := 0;
  673.     end;
  674.     Position := Stream.Position;
  675.     case FFormat of
  676.       sfDefault:
  677.         if RichEdit.PlainText then TextType := SF_TEXT
  678.         else TextType := SF_RTF;
  679.       sfRichText: TextType := SF_RTF;
  680.       else {sfPlainText} TextType := SF_TEXT;
  681.     end;
  682.     if TextType = SF_RTF then begin
  683.       if smPlainRtf in Mode then TextType := TextType or SFF_PLAINRTF;
  684.     end;
  685.     if TextType = SF_TEXT then begin
  686.       if (smUnicode in Mode) and (RichEditVersion > 1) then
  687.         TextType := TextType or SF_UNICODE;
  688.     end;
  689.     if smSelection in Mode then TextType := TextType or SFF_SELECTION;
  690.     SendMessage(RichEdit.Handle, EM_STREAMIN, TextType, Longint(@EditStream));
  691.     if (EditStream.dwError <> 0) then begin
  692.       Stream.Position := Position;
  693.       if (TextType and SF_RTF = SF_RTF) then TextType := SF_TEXT
  694.       else TextType := SF_RTF;
  695.       SendMessage(RichEdit.Handle, EM_STREAMIN, TextType, Longint(@EditStream));
  696.       if EditStream.dwError <> 0 then
  697.         raise EOutOfResources.Create(ResStr(sRichEditLoadFail));
  698.     end;
  699.     RichEdit.SetSelection(0, 0, True);
  700.   finally
  701.     if FConverter = nil then Converter.Free;
  702.   end;
  703. end;
  704. procedure TRichEditStrings.SaveToStream(Stream: TStream);
  705. var
  706.   EditStream: TEditStream;
  707.   TextType: Longint;
  708.   StreamInfo: TRichEditStreamInfo;
  709.   Converter: TConversion;
  710. begin
  711.   if FConverter <> nil then Converter := FConverter
  712.   else Converter := RichEdit.DefaultConverter.Create;
  713.   StreamInfo.Stream := Stream;
  714.   StreamInfo.Converter := Converter;
  715.   try
  716.     with EditStream do
  717.     begin
  718.       dwCookie := Longint(Pointer(@StreamInfo));
  719.       pfnCallBack := @StreamSave;
  720.       dwError := 0;
  721.     end;
  722.     case FFormat of
  723.       sfDefault:
  724.         if RichEdit.PlainText then TextType := SF_TEXT
  725.         else TextType := SF_RTF;
  726.       sfRichText: TextType := SF_RTF;
  727.       else {sfPlainText} TextType := SF_TEXT;
  728.     end;
  729.     if TextType = SF_RTF then begin
  730.       if smNoObjects in Mode then TextType := SF_RTFNOOBJS;
  731.       if smPlainRtf in Mode then TextType := TextType or SFF_PLAINRTF;
  732.     end
  733.     else if TextType = SF_TEXT then begin
  734.       if (smUnicode in Mode) and (RichEditVersion > 1) then
  735.         TextType := TextType or SF_UNICODE;
  736.     end;
  737.     if smSelection in Mode then TextType := TextType or SFF_SELECTION;
  738.     SendMessage(RichEdit.Handle, EM_STREAMOUT, TextType, Longint(@EditStream));
  739.     if EditStream.dwError <> 0 then
  740.       raise EOutOfResources.Create(ResStr(sRichEditSaveFail));
  741.   finally
  742.     if FConverter = nil then Converter.Free;
  743.   end;
  744. end;
  745. procedure TRichEditStrings.LoadFromFile(const FileName: string);
  746. var
  747.   Ext: string;
  748.   Convert: PRichConversionFormat;
  749.   SaveFormat: TRichStreamFormat;
  750. begin
  751. {$IFNDEF VER90}
  752.   Ext := AnsiLowerCaseFileName(ExtractFileExt(Filename));
  753. {$ELSE}
  754.   Ext := LowerCase(ExtractFileExt(Filename));
  755. {$ENDIF}
  756.   System.Delete(Ext, 1, 1);
  757.   Convert := ConversionFormatList;
  758.   while Convert <> nil do
  759.     with Convert^ do
  760.       if Extension <> Ext then Convert := Next
  761.       else Break;
  762.   if (FConverter = nil) and (Convert <> nil) then
  763.     FConverter := Convert^.ConversionClass.Create;
  764.   try
  765.     SaveFormat := Format;
  766.     try
  767.       if Convert <> nil then begin
  768.         if Convert^.PlainText then FFormat := sfPlainText
  769.         else FFormat := sfRichText;
  770.       end;
  771.       inherited LoadFromFile(FileName);
  772.     finally
  773.       FFormat := SaveFormat;
  774.     end;
  775.   except
  776.     FConverter.Free;
  777.     FConverter := nil;
  778.     raise;
  779.   end;
  780. end;
  781. procedure TRichEditStrings.SaveToFile(const FileName: string);
  782. var
  783.   Ext: string;
  784.   Convert: PRichConversionFormat;
  785.   SaveFormat: TRichStreamFormat;
  786. begin
  787. {$IFNDEF VER90}
  788.   Ext := AnsiLowerCaseFileName(ExtractFileExt(Filename));
  789. {$ELSE}
  790.   Ext := LowerCase(ExtractFileExt(Filename));
  791. {$ENDIF}
  792.   System.Delete(Ext, 1, 1);
  793.   Convert := ConversionFormatList;
  794.   while Convert <> nil do
  795.     with Convert^ do
  796.       if Extension <> Ext then Convert := Next
  797.       else Break;
  798.   if (FConverter = nil) and (Convert <> nil) then
  799.     FConverter := Convert^.ConversionClass.Create;
  800.   try
  801.     SaveFormat := Format;
  802.     try
  803.       if Convert <> nil then begin
  804.         if Convert^.PlainText then FFormat := sfPlainText
  805.         else FFormat := sfRichText;
  806.       end;
  807.       inherited SaveToFile(FileName);
  808.     finally
  809.       FFormat := SaveFormat;
  810.     end;
  811.   except
  812.     FConverter.Free;
  813.     FConverter := nil;
  814.     raise;
  815.   end;
  816. end;
  817. { TOEMConversion }
  818. function TOEMConversion.ConvertReadStream(Stream: TStream; Buffer: PChar;
  819.   BufSize: Integer): Integer;
  820. var
  821.   Mem: TMemoryStream;
  822. begin
  823.   Mem := TMemoryStream.Create;
  824.   try
  825.     Mem.SetSize(BufSize);
  826.     Result := inherited ConvertReadStream(Stream, PChar(Mem.Memory), BufSize);
  827.     OemToCharBuff(PChar(Mem.Memory), Buffer, Result);
  828.   finally
  829.     Mem.Free;
  830.   end;
  831. end;
  832. function TOEMConversion.ConvertWriteStream(Stream: TStream; Buffer: PChar;
  833.   BufSize: Integer): Integer;
  834. var
  835.   Mem: TMemoryStream;
  836. begin
  837.   Mem := TMemoryStream.Create;
  838.   try
  839.     Mem.SetSize(BufSize);
  840.     CharToOemBuff(Buffer, PChar(Mem.Memory), BufSize);
  841.     Result := inherited ConvertWriteStream(Stream, PChar(Mem.Memory), BufSize);
  842.   finally
  843.     Mem.Free;
  844.   end;
  845. end;
  846. { TRxCustomRichEdit }
  847. constructor TRxCustomRichEdit.Create(AOwner: TComponent);
  848. var
  849.   DC: HDC;
  850. begin
  851.   inherited Create(AOwner);
  852.   ControlStyle := ControlStyle - [csSetCaption];
  853.   FSelAttributes := TRxTextAttributes.Create(Self, atSelected);
  854.   FDefAttributes := TRxTextAttributes.Create(Self, atDefaultText);
  855.   FWordAttributes := TRxTextAttributes.Create(Self, atWord);
  856.   FParagraph := TRxParaAttributes.Create(Self);
  857.   FRichEditStrings := TRichEditStrings.Create;
  858.   TRichEditStrings(FRichEditStrings).RichEdit := Self;
  859.   TabStop := True;
  860.   Width := 185;
  861.   Height := 89;
  862.   AutoSize := False;
  863. {$IFDEF RX_D4}
  864.   DoubleBuffered := False;
  865. {$ENDIF}
  866.   FAllowObjects := True;
  867. {$IFDEF RX_D3}
  868.   FAllowInPlace := True;
  869. {$ENDIF}
  870.   FAutoVerbMenu := True;
  871.   FHideSelection := True;
  872.   FHideScrollBars := True;
  873.   ScrollBars := ssBoth;
  874.   FSelectionBar := True;
  875.   FLangOptions := [rlAutoFont];
  876.   DC := GetDC(0);
  877.   FScreenLogPixels := GetDeviceCaps(DC, LOGPIXELSY);
  878.   ReleaseDC(0, DC);
  879.   DefaultConverter := TConversion;
  880.   FOldParaAlignment := TParaAlignment(Alignment);
  881.   FUndoLimit := 100;
  882.   FAutoURLDetect := True;
  883.   FWordSelection := True;
  884.   with FClickRange do begin
  885.     cpMin := -1;
  886.     cpMax := -1;
  887.   end;
  888.   FCallback := TRichEditOleCallback.Create(Self);
  889. {$IFDEF RX_D4}
  890.   Perform(CM_PARENTBIDIMODECHANGED, 0, 0);
  891. {$ENDIF}
  892. end;
  893. destructor TRxCustomRichEdit.Destroy;
  894. begin
  895.   FLastFind := nil;
  896.   FSelAttributes.Free;
  897.   FDefAttributes.Free;
  898.   FWordAttributes.Free;
  899.   FParagraph.Free;
  900.   FRichEditStrings.Free;
  901.   FMemStream.Free;
  902.   FPopupVerbMenu.Free;
  903.   FFindDialog.Free;
  904.   FReplaceDialog.Free;
  905.   inherited Destroy;
  906.   { be sure that callback object is destroyed after inherited Destroy }
  907.   TRichEditOleCallback(FCallback).Free;
  908. end;
  909. procedure TRxCustomRichEdit.Clear;
  910. begin
  911.   CloseObjects;
  912.   inherited Clear;
  913.   Modified := False;
  914. end;
  915. procedure TRxCustomRichEdit.CreateParams(var Params: TCreateParams);
  916. const
  917.   HideScrollBars: array[Boolean] of DWORD = (ES_DISABLENOSCROLL, 0);
  918.   HideSelections: array[Boolean] of DWORD = (ES_NOHIDESEL, 0);
  919.   WordWraps: array[Boolean] of DWORD = (0, ES_AUTOHSCROLL);
  920.   SelectionBars: array[Boolean] of DWORD = (0, ES_SELECTIONBAR);
  921. begin
  922.   inherited CreateParams(Params);
  923.   case RichEditVersion of
  924.     1: CreateSubClass(Params, RICHEDIT_CLASS10A);
  925.     else CreateSubClass(Params, RICHEDIT_CLASS);
  926.   end;
  927.   with Params do begin
  928.     Style := (Style and not (WS_HSCROLL or WS_VSCROLL)) or ES_SAVESEL or
  929.       (WS_CLIPSIBLINGS or WS_CLIPCHILDREN);
  930.     { NOTE: WS_CLIPCHILDREN and WS_CLIPSIBLINGS are essential otherwise }
  931.     { once the object is inserted you see some painting problems.       }
  932.     Style := Style and not (WS_HSCROLL or WS_VSCROLL);
  933.     if ScrollBars in [ssVertical, ssBoth] then
  934.       Style := Style or WS_VSCROLL;
  935.     if (ScrollBars in [ssHorizontal, ssBoth]) and not WordWrap then
  936.       Style := Style or WS_HSCROLL;
  937.     Style := Style or HideScrollBars[FHideScrollBars] or
  938.       SelectionBars[FSelectionBar] or HideSelections[FHideSelection] and
  939.       not WordWraps[WordWrap];
  940.     WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW);
  941.   end;
  942. end;
  943. procedure TRxCustomRichEdit.CreateWnd;
  944. var
  945.   StreamFmt: TRichStreamFormat;
  946.   Mode: TRichStreamModes;
  947.   DesignMode: Boolean;
  948.   Mask: Longint;
  949. begin
  950.   StreamFmt := TRichEditStrings(Lines).Format;
  951.   Mode := TRichEditStrings(Lines).Mode;
  952.   inherited CreateWnd;
  953. {$IFNDEF VER90}
  954.   if (SysLocale.FarEast) and not (SysLocale.PriLangID = LANG_JAPANESE) then
  955.     Font.Charset := GetDefFontCharSet;
  956. {$ENDIF}
  957.   Mask := ENM_CHANGE or ENM_SELCHANGE or ENM_REQUESTRESIZE or ENM_PROTECTED;
  958.   if RichEditVersion >= 2 then Mask := Mask or ENM_LINK;
  959.   SendMessage(Handle, EM_SETEVENTMASK, 0, Mask);
  960.   SendMessage(Handle, EM_SETBKGNDCOLOR, 0, ColorToRGB(Color));
  961. {$IFDEF RX_D3}
  962.   DoSetMaxLength(MaxLength);
  963. {$ENDIF}
  964.   SetWordSelection(FWordSelection);
  965.   if RichEditVersion >= 2 then begin
  966.     SendMessage(Handle, EM_AUTOURLDETECT, Longint(FAutoURLDetect), 0);
  967.     FUndoLimit := SendMessage(Handle, EM_SETUNDOLIMIT, FUndoLimit, 0);
  968.     UpdateTextModes(PlainText);
  969.     SetLangOptions(FLangOptions);
  970.   end;
  971.   if FAllowObjects then begin
  972.     SendMessage(Handle, EM_SETOLECALLBACK, 0,
  973.       LPARAM(TRichEditOleCallback(FCallback) as IRichEditOleCallback));
  974.     GetRichEditOle(Handle, FRichEditOle);
  975.     UpdateHostNames;
  976.   end;
  977.   if FMemStream <> nil then begin
  978.     FMemStream.ReadBuffer(DesignMode, SizeOf(DesignMode));
  979.     if DesignMode then begin
  980.       TRichEditStrings(Lines).Format := sfPlainText;
  981.       TRichEditStrings(Lines).Mode := [];
  982.     end;
  983.     try
  984.       Lines.LoadFromStream(FMemStream);
  985.       FMemStream.Free;
  986.       FMemStream := nil;
  987.     finally
  988.       TRichEditStrings(Lines).Format := StreamFmt;
  989.       TRichEditStrings(Lines).Mode := Mode;
  990.     end;
  991.   end;
  992.   if RichEditVersion < 2 then
  993.     SendMessage(Handle, WM_SETFONT, 0, 0);
  994.   Modified := FModified;
  995. end;
  996. procedure TRxCustomRichEdit.DestroyWnd;
  997. var
  998.   StreamFmt: TRichStreamFormat;
  999.   Mode: TRichStreamModes;
  1000.   DesignMode: Boolean;
  1001. begin
  1002.   FModified := Modified;
  1003.   FMemStream := TMemoryStream.Create;
  1004.   StreamFmt := TRichEditStrings(Lines).Format;
  1005.   Mode := TRichEditStrings(Lines).Mode;
  1006.   DesignMode := (csDesigning in ComponentState);
  1007.   FMemStream.WriteBuffer(DesignMode, SizeOf(DesignMode));
  1008.   if DesignMode then begin
  1009.     TRichEditStrings(Lines).Format := sfPlainText;
  1010.     TRichEditStrings(Lines).Mode := [];
  1011.   end;
  1012.   try
  1013.     Lines.SaveToStream(FMemStream);
  1014.     FMemStream.Position := 0;
  1015.   finally
  1016.     TRichEditStrings(Lines).Format := StreamFmt;
  1017.     TRichEditStrings(Lines).Mode := Mode;
  1018.   end;
  1019.   inherited DestroyWnd;
  1020. end;
  1021. procedure TRxCustomRichEdit.SetAllowObjects(Value: Boolean);
  1022. begin
  1023.   if FAllowObjects <> Value then begin
  1024.     FAllowObjects := Value;
  1025.     RecreateWnd;    
  1026.   end;
  1027. end;
  1028. procedure TRxCustomRichEdit.UpdateHostNames;
  1029. var
  1030.   AppName: string;
  1031. begin
  1032.   if HandleAllocated and Assigned(FRichEditOle) then begin
  1033.     AppName := Application.Title;
  1034.     if Trim(AppName) = '' then
  1035.       AppName := ExtractFileName(Application.ExeName);
  1036.     if Trim(Title) = '' then
  1037.       IRichEditOle(FRichEditOle).SetHostNames(PChar(AppName), PChar(AppName))
  1038.     else
  1039.       IRichEditOle(FRichEditOle).SetHostNames(PChar(AppName), PChar(Title));
  1040.   end;
  1041. end;
  1042. procedure TRxCustomRichEdit.SetTitle(const Value: string);
  1043. begin
  1044.   if FTitle <> Value then begin
  1045.     FTitle := Value;
  1046.     UpdateHostNames;
  1047.   end;
  1048. end;
  1049. function TRxCustomRichEdit.GetPopupMenu: TPopupMenu;
  1050. var
  1051.   EnumOleVerb: IEnumOleVerb;
  1052.   OleVerb: TOleVerb;
  1053.   Item: TMenuItem;
  1054.   ReObject: TReObject;
  1055. begin
  1056.   FPopupVerbMenu.Free;
  1057.   FPopupVerbMenu := nil;
  1058.   Result := inherited GetPopupMenu;
  1059.   if FAutoVerbMenu and (SelectionType = [stObject]) and
  1060.     Assigned(FRichEditOle) then
  1061.   begin
  1062.     FillChar(ReObject, SizeOf(ReObject), 0);
  1063.     ReObject.cbStruct := SizeOf(ReObject);
  1064.     if Succeeded(IRichEditOle(FRichEditOle).GetObject(
  1065.       Longint(REO_IOB_SELECTION), ReObject, REO_GETOBJ_POLEOBJ)) then
  1066.     try
  1067.       if Assigned(ReObject.poleobj) and
  1068.         (ReObject.dwFlags and REO_INPLACEACTIVE = 0) then
  1069.       begin
  1070.         FPopupVerbMenu := TPopupMenu.Create(Self);
  1071.         if ReObject.poleobj.EnumVerbs(EnumOleVerb) = 0 then
  1072.         try
  1073.           while (EnumOleVerb.Next(1, OleVerb, nil) = 0) and
  1074.             (OleVerb.lVerb >= 0) and
  1075.             (OleVerb.grfAttribs and OLEVERBATTRIB_ONCONTAINERMENU <> 0) do
  1076.           begin
  1077.             Item := TMenuItem.Create(FPopupVerbMenu);
  1078.             Item.Caption := WideCharToString(OleVerb.lpszVerbName);
  1079.             Item.Tag := OleVerb.lVerb;
  1080.             Item.Default := (OleVerb.lVerb = OLEIVERB_PRIMARY);
  1081.             Item.OnClick := PopupVerbClick;
  1082.             FPopupVerbMenu.Items.Add(Item);
  1083.           end;
  1084.         finally
  1085.           ReleaseObject(EnumOleVerb);
  1086.         end;
  1087.         if (Result <> nil) and (Result.Items.Count > 0) then begin
  1088.           Item := TMenuItem.Create(FPopupVerbMenu);
  1089.           Item.Caption := '-';
  1090.           Result.Items.Add(Item);
  1091.           Item := TMenuItem.Create(FPopupVerbMenu);
  1092.           Item.Caption := Format(ResStr(SPropDlgCaption),
  1093.             [GetFullNameStr(ReObject.poleobj)]);
  1094.           Item.OnClick := ObjectPropsClick;
  1095.           Result.Items.Add(Item);
  1096.           if FPopupVerbMenu.Items.Count > 0 then begin
  1097.             FPopupVerbMenu.Items.Caption := GetFullNameStr(ReObject.poleobj);
  1098.             Result.Items.Add(FPopupVerbMenu.Items);
  1099.           end;
  1100.         end
  1101.         else if FPopupVerbMenu.Items.Count > 0 then begin
  1102.           Item := TMenuItem.Create(FPopupVerbMenu);
  1103.           Item.Caption := Format(ResStr(SPropDlgCaption),
  1104.             [GetFullNameStr(ReObject.poleobj)]);
  1105.           Item.OnClick := ObjectPropsClick;
  1106.           FPopupVerbMenu.Items.Insert(0, Item);
  1107.           Result := FPopupVerbMenu;
  1108.         end;
  1109.       end;
  1110.     finally
  1111.       ReleaseObject(ReObject.poleobj);
  1112.     end;
  1113.   end;
  1114. end;
  1115. procedure TRxCustomRichEdit.PopupVerbClick(Sender: TObject);
  1116. var
  1117.   ReObject: TReObject;
  1118. begin
  1119.   if Assigned(FRichEditOle) then begin
  1120.     FillChar(ReObject, SizeOf(ReObject), 0);
  1121.     ReObject.cbStruct := SizeOf(ReObject);
  1122.     if Succeeded(IRichEditOle(FRichEditOle).GetObject(
  1123.       Longint(REO_IOB_SELECTION), ReObject, REO_GETOBJ_POLEOBJ or
  1124.       REO_GETOBJ_POLESITE)) then
  1125.     try
  1126.       if ReObject.dwFlags and REO_INPLACEACTIVE = 0 then
  1127.         OleCheck(ReObject.poleobj.DoVerb((Sender as TMenuItem).Tag, nil,
  1128.           ReObject.polesite, 0, Handle, ClientRect));
  1129.     finally
  1130.       ReleaseObject(ReObject.polesite);
  1131.       ReleaseObject(ReObject.poleobj);
  1132.     end;
  1133.   end;
  1134. end;
  1135. procedure TRxCustomRichEdit.ObjectPropsClick(Sender: TObject);
  1136. begin
  1137.   ObjectPropertiesDialog;
  1138. end;
  1139. procedure TRxCustomRichEdit.WMSetFont(var Message: TWMSetFont);
  1140. begin
  1141.   FDefAttributes.Assign(Font);
  1142. end;
  1143. procedure TRxCustomRichEdit.CMFontChanged(var Message: TMessage);
  1144. begin
  1145.   inherited;
  1146.   FDefAttributes.Assign(Font);
  1147. end;
  1148. procedure TRxCustomRichEdit.CreateWindowHandle(const Params: TCreateParams);
  1149. var
  1150.   Bounds: TRect;
  1151. begin
  1152.   Bounds := BoundsRect;
  1153.   inherited CreateWindowHandle(Params);
  1154.   if HandleAllocated then BoundsRect := Bounds;
  1155. end;
  1156. {$IFDEF RX_D3}
  1157. procedure TRxCustomRichEdit.DoSetMaxLength(Value: Integer);
  1158. begin
  1159.   { The rich edit control's default maximum amount of text is 32K }
  1160.   { Let's set it at 16M by default }
  1161.   if Value = 0 then Value := $FFFFFF;
  1162.   SendMessage(Handle, EM_EXLIMITTEXT, 0, Value);
  1163. end;
  1164. {$ENDIF}
  1165. function TRxCustomRichEdit.GetCaretPos: TPoint;
  1166. var
  1167.   CharRange: TCharRange;
  1168. begin
  1169.   SendMessage(Handle, EM_EXGETSEL, 0, Longint(@CharRange));
  1170.   Result.X := CharRange.cpMax;
  1171.   Result.Y := LineFromChar(Result.X);
  1172.   Dec(Result.X, GetLineIndex(-1));
  1173. end;
  1174. {$IFDEF RX_D3}
  1175. function TRxCustomRichEdit.GetSelLength: Integer;
  1176. begin
  1177.   with GetSelection do
  1178.     Result := cpMax - cpMin;
  1179. end;
  1180. function TRxCustomRichEdit.GetSelStart: Integer;
  1181. begin
  1182.   Result := GetSelection.cpMin;
  1183. end;
  1184. function TRxCustomRichEdit.GetSelText: string;
  1185. begin
  1186.   with GetSelection do
  1187.     Result := GetTextRange(cpMin, cpMax);
  1188. end;
  1189. {$ENDIF RX_D3}
  1190. function TRxCustomRichEdit.GetSelTextBuf(Buffer: PChar; BufSize: Integer): Integer;
  1191. var
  1192.   S: string;
  1193. begin
  1194.   S := SelText;
  1195.   Result := Length(S);
  1196.   if BufSize < Length(S) then Result := BufSize;
  1197.   StrPLCopy(Buffer, S, Result);
  1198. end;
  1199. {$IFDEF RX_D4}
  1200. procedure TRxCustomRichEdit.CMBiDiModeChanged(var Message: TMessage);
  1201. var
  1202.   AParagraph: TParaFormat2;
  1203. begin
  1204.   HandleNeeded; { we REALLY need the handle for BiDi }
  1205.   inherited;
  1206.   Paragraph.GetAttributes(AParagraph);
  1207.   AParagraph.dwMask := PFM_ALIGNMENT;
  1208.   AParagraph.wAlignment := Ord(Alignment) + 1;
  1209.   Paragraph.SetAttributes(AParagraph);
  1210. end;
  1211. {$ENDIF}
  1212. procedure TRxCustomRichEdit.SetHideScrollBars(Value: Boolean);
  1213. begin
  1214.   if HideScrollBars <> Value then begin
  1215.     FHideScrollBars := Value;
  1216.     RecreateWnd;
  1217.   end;
  1218. end;
  1219. procedure TRxCustomRichEdit.SetSelectionBar(Value: Boolean);
  1220. begin
  1221.   if FSelectionBar <> Value then begin
  1222.     FSelectionBar := Value;
  1223.     RecreateWnd;
  1224.   end;
  1225. end;
  1226. procedure TRxCustomRichEdit.SetHideSelection(Value: Boolean);
  1227. begin
  1228.   if HideSelection <> Value then begin
  1229.     FHideSelection := Value;
  1230.     SendMessage(Handle, EM_HIDESELECTION, Ord(HideSelection), LPARAM(True));
  1231.   end;
  1232. end;
  1233. function TRxCustomRichEdit.GetAutoURLDetect: Boolean;
  1234. begin
  1235.   Result := FAutoURLDetect;
  1236.   if HandleAllocated and not (csDesigning in ComponentState) then begin
  1237.     if RichEditVersion >= 2 then
  1238.       Result := Boolean(SendMessage(Handle, EM_GETAUTOURLDETECT, 0, 0));
  1239.   end;
  1240. end;
  1241. procedure TRxCustomRichEdit.SetAutoURLDetect(Value: Boolean);
  1242. begin
  1243.   if Value <> FAutoURLDetect then begin
  1244.     FAutoURLDetect := Value;
  1245.     if HandleAllocated and (RichEditVersion >= 2) then
  1246.       SendMessage(Handle, EM_AUTOURLDETECT, Longint(FAutoURLDetect), 0);
  1247.   end;
  1248. end;
  1249. function TRxCustomRichEdit.GetWordSelection: Boolean;
  1250. begin
  1251.   Result := FWordSelection;
  1252.   if HandleAllocated then
  1253.     Result := (SendMessage(Handle, EM_GETOPTIONS, 0, 0) and
  1254.       ECO_AUTOWORDSELECTION) <> 0;
  1255. end;
  1256. procedure TRxCustomRichEdit.SetWordSelection(Value: Boolean);
  1257. var
  1258.   Options: LPARAM;
  1259. begin
  1260.   FWordSelection := Value;
  1261.   if HandleAllocated then begin
  1262.     Options := SendMessage(Handle, EM_GETOPTIONS, 0, 0);
  1263.     if Value then Options := Options or ECO_AUTOWORDSELECTION
  1264.     else Options := Options and not ECO_AUTOWORDSELECTION;
  1265.     SendMessage(Handle, EM_SETOPTIONS, ECOOP_SET, Options);
  1266.   end;
  1267. end;
  1268. const
  1269.   RichLangOptions: array[TRichLangOption] of DWORD = (IMF_AUTOKEYBOARD,
  1270.     IMF_AUTOFONT, IMF_IMECANCELCOMPLETE, IMF_IMEALWAYSSENDNOTIFY);
  1271. function TRxCustomRichEdit.GetLangOptions: TRichLangOptions;
  1272. var
  1273.   Flags: Longint;
  1274.   I: TRichLangOption;
  1275. begin
  1276.   Result := FLangOptions;
  1277.   if HandleAllocated and not (csDesigning in ComponentState) and
  1278.     (RichEditVersion >= 2) then
  1279.   begin
  1280.     Result := [];
  1281.     Flags := SendMessage(Handle, EM_GETLANGOPTIONS, 0, 0);
  1282.     for I := Low(TRichLangOption) to High(TRichLangOption) do
  1283.       if Flags and RichLangOptions[I] <> 0 then Include(Result, I);
  1284.   end;
  1285. end;
  1286. procedure TRxCustomRichEdit.SetLangOptions(Value: TRichLangOptions);
  1287. var
  1288.   Flags: DWORD;
  1289.   I: TRichLangOption;
  1290. begin
  1291.   FLangOptions := Value;
  1292.   if HandleAllocated and (RichEditVersion >= 2) then begin
  1293.     Flags := 0;
  1294.     for I := Low(TRichLangOption) to High(TRichLangOption) do
  1295.       if I in Value then Flags := Flags or RichLangOptions[I];
  1296.     SendMessage(Handle, EM_SETLANGOPTIONS, 0, LPARAM(Flags));
  1297.   end;
  1298. end;
  1299. procedure TRxCustomRichEdit.SetSelAttributes(Value: TRxTextAttributes);
  1300. begin
  1301.   FSelAttributes.Assign(Value);
  1302. end;
  1303. function TRxCustomRichEdit.GetCanRedo: Boolean;
  1304. begin
  1305.   Result := False;
  1306.   if HandleAllocated and (RichEditVersion >= 2) then
  1307.     Result := SendMessage(Handle, EM_CANREDO, 0, 0) <> 0;
  1308. end;
  1309. function TRxCustomRichEdit.GetCanPaste: Boolean;
  1310. begin
  1311.   Result := False;
  1312.   if HandleAllocated then
  1313.     Result := SendMessage(Handle, EM_CANPASTE, 0, 0) <> 0;
  1314. end;
  1315. {$IFNDEF RX_V110}
  1316. function TRxCustomRichEdit.GetCanUndo: Boolean;
  1317. begin
  1318.   Result := False;
  1319.   if HandleAllocated then
  1320.     Result := SendMessage(Handle, EM_CANUNDO, 0, 0) <> 0;
  1321. end;
  1322. {$ENDIF}
  1323. function TRxCustomRichEdit.GetRedoName: TUndoName;
  1324. begin
  1325.   Result := unUnknown;
  1326.   if (RichEditVersion >= 2) and HandleAllocated then
  1327.     Result := TUndoName(SendMessage(Handle, EM_GETREDONAME, 0, 0));
  1328. end;
  1329. function TRxCustomRichEdit.GetUndoName: TUndoName;
  1330. begin
  1331.   Result := unUnknown;
  1332.   if (RichEditVersion >= 2) and HandleAllocated then
  1333.     Result := TUndoName(SendMessage(Handle, EM_GETUNDONAME, 0, 0));
  1334. end;
  1335. function TRxCustomRichEdit.GetSelectionType: TRichSelectionType;
  1336. const
  1337.   SelTypes: array[TRichSelection] of Integer = (
  1338.     SEL_TEXT, SEL_OBJECT, SEL_MULTICHAR, SEL_MULTIOBJECT);
  1339. var
  1340.   Selection: Integer;
  1341.   I: TRichSelection;
  1342. begin
  1343.   Result := [];
  1344.   if HandleAllocated then begin
  1345.     Selection := SendMessage(Handle, EM_SELECTIONTYPE, 0, 0);
  1346.     for I := Low(TRichSelection) to High(TRichSelection) do
  1347.       if SelTypes[I] and Selection <> 0 then Include(Result, I);
  1348.   end;
  1349. end;
  1350. function TRxCustomRichEdit.GetSelection: TCharRange;
  1351. begin
  1352.   SendMessage(Handle, EM_EXGETSEL, 0, Longint(@Result));
  1353. end;
  1354. procedure TRxCustomRichEdit.SetSelection(StartPos, EndPos: Longint;
  1355.   ScrollCaret: Boolean);
  1356. var
  1357.   CharRange: TCharRange;
  1358. begin
  1359.   with CharRange do begin
  1360.     cpMin := StartPos;
  1361.     cpMax := EndPos;
  1362.   end;
  1363.   SendMessage(Handle, EM_EXSETSEL, 0, Longint(@CharRange));
  1364.   if ScrollCaret then SendMessage(Handle, EM_SCROLLCARET, 0, 0);
  1365. end;
  1366. {$IFDEF RX_D3}
  1367. procedure TRxCustomRichEdit.SetSelLength(Value: Integer);
  1368. begin
  1369.   with GetSelection do SetSelection(cpMin, cpMin + Value, True);
  1370. end;
  1371. procedure TRxCustomRichEdit.SetSelStart(Value: Integer);
  1372. begin
  1373.   SetSelection(Value, Value, False);
  1374. end;
  1375. {$ENDIF RX_D3}
  1376. function TRxCustomRichEdit.GetCharPos(CharIndex: Integer): TPoint;
  1377. var
  1378.   Res: Longint;
  1379. begin
  1380.   FillChar(Result, SizeOf(Result), 0);
  1381.   if HandleAllocated then begin
  1382.     if RichEditVersion = 2 then begin
  1383.       Res := SendMessage(Handle, Messages.EM_POSFROMCHAR, CharIndex, 0);
  1384.       Result.X := LoWord(Res);
  1385.       Result.Y := HiWord(Res);
  1386.     end
  1387.     else { RichEdit 1.0 and 3.0 }
  1388.       SendMessage(Handle, Messages.EM_POSFROMCHAR, WPARAM(@Result), CharIndex);
  1389.   end;
  1390. end;
  1391. function TRxCustomRichEdit.GetTextRange(StartPos, EndPos: Longint): string;
  1392. var
  1393.   TextRange: TTextRange;
  1394. begin
  1395.   SetLength(Result, EndPos - StartPos + 1);
  1396.   TextRange.chrg.cpMin := StartPos;
  1397.   TextRange.chrg.cpMax := EndPos;
  1398.   TextRange.lpstrText := PAnsiChar(Result);
  1399.   SetLength(Result, SendMessage(Handle, EM_GETTEXTRANGE, 0, Longint(@TextRange)));
  1400. end;
  1401. function TRxCustomRichEdit.WordAtCursor: string;
  1402. var
  1403.   Range: TCharRange;
  1404. begin
  1405.   Result := '';
  1406.   if HandleAllocated then begin
  1407.     Range.cpMax := SelStart;
  1408.     if Range.cpMax = 0 then Range.cpMin := 0
  1409.     else if SendMessage(Handle, EM_FINDWORDBREAK, WB_ISDELIMITER, Range.cpMax) <> 0 then
  1410.       Range.cpMin := SendMessage(Handle, EM_FINDWORDBREAK, WB_MOVEWORDLEFT, Range.cpMax)
  1411.     else
  1412.       Range.cpMin := SendMessage(Handle, EM_FINDWORDBREAK, WB_LEFT, Range.cpMax);
  1413.     while SendMessage(Handle, EM_FINDWORDBREAK, WB_ISDELIMITER, Range.cpMin) <> 0 do
  1414.       Inc(Range.cpMin);
  1415.     Range.cpMax := SendMessage(Handle, EM_FINDWORDBREAK, WB_RIGHTBREAK, Range.cpMax);
  1416.     Result := Trim(GetTextRange(Range.cpMin, Range.cpMax));
  1417.   end;
  1418. end;
  1419. function TRxCustomRichEdit.LineFromChar(CharIndex: Integer): Integer;
  1420. begin
  1421.   Result := SendMessage(Handle, EM_EXLINEFROMCHAR, 0, CharIndex);
  1422. end;
  1423. function TRxCustomRichEdit.GetLineIndex(LineNo: Integer): Integer;
  1424. begin
  1425.   Result := SendMessage(Handle, EM_LINEINDEX, LineNo, 0);
  1426. end;
  1427. function TRxCustomRichEdit.GetLineLength(CharIndex: Integer): Integer;
  1428. begin
  1429.   Result := SendMessage(Handle, EM_LINELENGTH, CharIndex, 0);
  1430. end;
  1431. procedure TRxCustomRichEdit.SetUndoLimit(Value: Integer);
  1432. begin
  1433.   if (Value <> FUndoLimit) then begin
  1434.     FUndoLimit := Value;
  1435.     if (RichEditVersion >= 2) and HandleAllocated then
  1436.       FUndoLimit := SendMessage(Handle, EM_SETUNDOLIMIT, Value, 0);
  1437.   end;
  1438. end;
  1439. procedure TRxCustomRichEdit.SetDefAttributes(Value: TRxTextAttributes);
  1440. begin
  1441.   FDefAttributes.Assign(Value);
  1442. end;
  1443. procedure TRxCustomRichEdit.SetWordAttributes(Value: TRxTextAttributes);
  1444. begin
  1445.   FWordAttributes.Assign(Value);
  1446. end;
  1447. function TRxCustomRichEdit.GetStreamFormat: TRichStreamFormat;
  1448. begin
  1449.   Result := TRichEditStrings(Lines).Format;
  1450. end;
  1451. function TRxCustomRichEdit.GetStreamMode: TRichStreamModes;
  1452. begin
  1453.   Result := TRichEditStrings(Lines).Mode;
  1454. end;
  1455. procedure TRxCustomRichEdit.SetStreamFormat(Value: TRichStreamFormat);
  1456. begin
  1457.   TRichEditStrings(Lines).Format := Value;
  1458. end;
  1459. procedure TRxCustomRichEdit.SetStreamMode(Value: TRichStreamModes);
  1460. begin
  1461.   TRichEditStrings(Lines).Mode := Value;
  1462. end;
  1463. procedure TRxCustomRichEdit.SetPlainText(Value: Boolean);
  1464. var
  1465.   MemStream: TStream;
  1466.   StreamFmt: TRichStreamFormat;
  1467.   Mode: TRichStreamModes;
  1468. begin
  1469.   if PlainText <> Value then begin
  1470.     if HandleAllocated and (RichEditVersion >= 2) then begin
  1471.       MemStream := TMemoryStream.Create;
  1472.       try
  1473.         StreamFmt := TRichEditStrings(Lines).Format;
  1474.         Mode := TRichEditStrings(Lines).Mode;
  1475.         try
  1476.           if (csDesigning in ComponentState) or Value then
  1477.             TRichEditStrings(Lines).Format := sfPlainText
  1478.           else TRichEditStrings(Lines).Format := sfRichText;
  1479.           TRichEditStrings(Lines).Mode := [];
  1480.           Lines.SaveToStream(MemStream);
  1481.           MemStream.Position := 0;
  1482.           TRichEditStrings(Lines).EnableChange(False);
  1483.           try
  1484.             SendMessage(Handle, WM_SETTEXT, 0, 0);
  1485.             UpdateTextModes(Value);
  1486.             FPlainText := Value;
  1487.           finally
  1488.             TRichEditStrings(Lines).EnableChange(True);
  1489.           end;
  1490.           Lines.LoadFromStream(MemStream);
  1491.         finally
  1492.           TRichEditStrings(Lines).Format := StreamFmt;
  1493.           TRichEditStrings(Lines).Mode := Mode;
  1494.         end;
  1495.       finally
  1496.         MemStream.Free;
  1497.       end;
  1498.     end;
  1499.     FPlainText := Value;
  1500.   end;
  1501. end;
  1502. procedure TRxCustomRichEdit.UpdateTextModes(Plain: Boolean);
  1503. const
  1504.   TextModes: array[Boolean] of DWORD = (TM_RICHTEXT, TM_PLAINTEXT);
  1505.   UndoModes: array[Boolean] of DWORD = (TM_SINGLELEVELUNDO, TM_MULTILEVELUNDO);
  1506. begin
  1507.   if (RichEditVersion >= 2) and HandleAllocated then begin
  1508.     SendMessage(Handle, EM_SETTEXTMODE, TextModes[Plain] or
  1509.       UndoModes[FUndoLimit > 1], 0);
  1510.   end;
  1511. end;
  1512. procedure TRxCustomRichEdit.CMColorChanged(var Message: TMessage);
  1513. begin
  1514.   inherited;
  1515.   SendMessage(Handle, EM_SETBKGNDCOLOR, 0, ColorToRGB(Color))
  1516. end;
  1517. procedure TRxCustomRichEdit.EMReplaceSel(var Message: TMessage);
  1518. var
  1519.   CharRange: TCharRange;
  1520. begin
  1521.   Perform(EM_EXGETSEL, 0, Longint(@CharRange));
  1522.   with CharRange do
  1523.     cpMax := cpMin + Integer(StrLen(PChar(Message.lParam)));
  1524.   if (FUndoLimit > 1) and (RichEditVersion >= 2) and not FLinesUpdating then
  1525.     Message.wParam := 1; { allow Undo }
  1526.   inherited;
  1527.   if not FLinesUpdating then begin
  1528.     Perform(EM_EXSETSEL, 0, Longint(@CharRange));
  1529.     Perform(EM_SCROLLCARET, 0, 0);
  1530.   end;
  1531. end;
  1532. procedure TRxCustomRichEdit.SetRichEditStrings(Value: TStrings);
  1533. begin
  1534.   FRichEditStrings.Assign(Value);
  1535. end;
  1536. procedure TRxCustomRichEdit.CloseObjects;
  1537. var
  1538.   I: Integer;
  1539.   ReObject: TReObject;
  1540. begin
  1541.   if Assigned(FRichEditOle) then begin
  1542.     FillChar(ReObject, SizeOf(ReObject), 0);
  1543.     ReObject.cbStruct := SizeOf(ReObject);
  1544.     with IRichEditOle(FRichEditOle) do begin
  1545.       for I := GetObjectCount - 1 downto 0 do
  1546.         if Succeeded(GetObject(I, ReObject, REO_GETOBJ_POLEOBJ)) then begin
  1547.           if ReObject.dwFlags and REO_INPLACEACTIVE <> 0 then
  1548.             IRichEditOle(FRichEditOle).InPlaceDeactivate;
  1549.           ReObject.poleobj.Close(OLECLOSE_NOSAVE);
  1550.           ReleaseObject(ReObject.poleobj);
  1551.         end;
  1552.     end;
  1553.   end;
  1554. end;
  1555. function TRxCustomRichEdit.PasteSpecialDialog: Boolean;
  1556.   procedure SetPasteEntry(var Entry: TOleUIPasteEntry; Format: TClipFormat;
  1557.     tymed: DWORD; const FormatName, ResultText: string; Flags: DWORD);
  1558.   begin
  1559.     with Entry do begin
  1560.       fmtetc.cfFormat := Format;
  1561.       fmtetc.dwAspect := DVASPECT_CONTENT;
  1562.       fmtetc.lIndex := -1;
  1563.       fmtetc.tymed := tymed;
  1564.       if FormatName <> '' then lpstrFormatName := PChar(FormatName)
  1565.       else lpstrFormatName := '%s';
  1566.       if ResultText <> '' then lpstrResultText := PChar(ResultText)
  1567.       else lpstrResultText := '%s';
  1568.       dwFlags := Flags;
  1569.     end;
  1570.   end;
  1571. const
  1572.   PasteFormatCount = 6;
  1573. var
  1574.   Data: TOleUIPasteSpecial;
  1575.   PasteFormats: array[0..PasteFormatCount - 1] of TOleUIPasteEntry;
  1576.   Format: Integer;
  1577.   OleClientSite: IOleClientSite;
  1578.   Storage: IStorage;
  1579.   OleObject: IOleObject;
  1580.   ReObject: TReObject;
  1581.   Selection: TCharRange;
  1582. begin
  1583.   Result := False;
  1584.   if not CanPaste or not Assigned(FRichEditOle) then Exit;
  1585.   FillChar(Data, SizeOf(Data), 0);
  1586.   FillChar(PasteFormats, SizeOf(PasteFormats), 0);
  1587.   with Data do begin
  1588.     cbStruct := SizeOf(Data);
  1589.     hWndOwner := Handle;
  1590.     arrPasteEntries := @PasteFormats;
  1591.     cPasteEntries := PasteFormatCount;
  1592.     arrLinkTypes := @CFLinkSource;
  1593.     cLinkTypes := 1;
  1594.     dwFlags := PSF_SELECTPASTE;
  1595.   end;
  1596.   SetPasteEntry(PasteFormats[0], CFEmbeddedObject, TYMED_ISTORAGE, '', '',
  1597.     OLEUIPASTE_PASTE or OLEUIPASTE_ENABLEICON);
  1598.   SetPasteEntry(PasteFormats[1], CFLinkSource, TYMED_ISTREAM, '', '',
  1599.     OLEUIPASTE_LINKTYPE1 or OLEUIPASTE_ENABLEICON);
  1600.   SetPasteEntry(PasteFormats[2], CFRtf, TYMED_ISTORAGE,
  1601.     CF_RTF, CF_RTF, OLEUIPASTE_PASTE);
  1602.   SetPasteEntry(PasteFormats[3], CFRtfNoObjs, TYMED_ISTORAGE,
  1603.     CF_RTFNOOBJS, CF_RTFNOOBJS, OLEUIPASTE_PASTE);
  1604.   SetPasteEntry(PasteFormats[4], CF_TEXT, TYMED_HGLOBAL,
  1605.     'Unformatted text', 'text without any formatting', OLEUIPASTE_PASTE);
  1606.   SetPasteEntry(PasteFormats[5], CF_BITMAP, TYMED_GDI,
  1607.     'Windows Bitmap', 'bitmap image', OLEUIPASTE_PASTE);
  1608.   try
  1609.     if OleUIPasteSpecial(Data) = OLEUI_OK then begin
  1610.       Result := True;
  1611.       if Data.nSelectedIndex in [0, 1] then begin
  1612.         { CFEmbeddedObject, CFLinkSource }
  1613.         FillChar(ReObject, SizeOf(TReObject), 0);
  1614.         IRichEditOle(FRichEditOle).GetClientSite(OleClientSite);
  1615.         Storage := nil;
  1616.         try
  1617.           CreateStorage(Storage);
  1618.           case Data.nSelectedIndex of
  1619.             0: OleCheck(OleCreateFromData(Data.lpSrcDataObj,
  1620.                {$IFDEF RX_D3} IOleObject {$ELSE} IID_IOleObject {$ENDIF},
  1621.                OLERENDER_DRAW, nil, OleClientSite, Storage, OleObject));
  1622.             1: OleCheck(OleCreateLinkFromData(Data.lpSrcDataObj,
  1623.                {$IFDEF RX_D3} IOleObject {$ELSE} IID_IOleObject {$ENDIF},
  1624.                OLERENDER_DRAW, nil, OleClientSite, Storage, OleObject));
  1625.           end;
  1626.           try
  1627.             with ReObject do begin
  1628.               cbStruct := SizeOf(TReObject);
  1629.               cp := REO_CP_SELECTION;
  1630.               poleobj := OleObject;
  1631.               OleObject.GetUserClassID(clsid);
  1632.               pstg := Storage;
  1633.               polesite := OleClientSite;
  1634.               dvAspect := DVASPECT_CONTENT;
  1635.               dwFlags := REO_RESIZABLE;
  1636.               OleCheck(OleSetDrawAspect(OleObject,
  1637.                 Data.dwFlags and PSF_CHECKDISPLAYASICON <> 0,
  1638.                 Data.hMetaPict, dvAspect));
  1639.             end;
  1640.             SendMessage(Handle, EM_EXGETSEL, 0, Longint(@Selection));
  1641.             Selection.cpMax := Selection.cpMin + 1;
  1642.             OleCheck(IRichEditOle(FRichEditOle).InsertObject(ReObject));
  1643.             SendMessage(Handle, EM_EXSETSEL, 0, Longint(@Selection));
  1644.             IRichEditOle(FRichEditOle).SetDvaspect(
  1645.               Longint(REO_IOB_SELECTION), ReObject.dvAspect);
  1646.           finally
  1647.             ReleaseObject(OleObject);
  1648.           end;
  1649.         finally
  1650.           ReleaseObject(OleClientSite);
  1651.           ReleaseObject(Storage);
  1652.         end;
  1653.       end
  1654.       else begin
  1655.         Format := PasteFormats[Data.nSelectedIndex].fmtetc.cfFormat;
  1656.         OleCheck(IRichEditOle(FRichEditOle).ImportDataObject(
  1657.           Data.lpSrcDataObj, Format, Data.hMetaPict));
  1658.       end;
  1659.       SendMessage(Handle, EM_SCROLLCARET, 0, 0);
  1660.     end;
  1661.   finally
  1662.     DestroyMetaPict(Data.hMetaPict);
  1663.     ReleaseObject(Data.lpSrcDataObj);
  1664.   end;
  1665. end;
  1666. function TRxCustomRichEdit.InsertObjectDialog: Boolean;
  1667. var
  1668.   Data: TOleUIInsertObject;
  1669.   NameBuffer: array[0..255] of Char;
  1670.   OleClientSite: IOleClientSite;
  1671.   Storage: IStorage;
  1672.   OleObject: IOleObject;
  1673.   ReObject: TReObject;
  1674.   IsNewObject: Boolean;
  1675.   Selection: TCharRange;
  1676. begin
  1677.   FillChar(Data, SizeOf(Data), 0);
  1678.   FillChar(NameBuffer, SizeOf(NameBuffer), 0);
  1679.   FillChar(ReObject, SizeOf(TReObject), 0);
  1680.   if Assigned(FRichEditOle) then begin
  1681.     IRichEditOle(FRichEditOle).GetClientSite(OleClientSite);
  1682.     Storage := nil;
  1683.     try
  1684.       CreateStorage(Storage);
  1685.       with Data do begin
  1686.         cbStruct := SizeOf(Data);
  1687.         dwFlags := IOF_SELECTCREATENEW or IOF_VERIFYSERVERSEXIST or 
  1688.           IOF_CREATENEWOBJECT or IOF_CREATEFILEOBJECT or IOF_CREATELINKOBJECT;
  1689.         hWndOwner := Handle;
  1690.         lpszFile := NameBuffer;
  1691.         cchFile := SizeOf(NameBuffer);
  1692.         iid := {$IFDEF RX_D3} IOleObject {$ELSE} IID_IOleObject {$ENDIF};
  1693.         oleRender := OLERENDER_DRAW;
  1694.         lpIOleClientSite := OleClientSite;
  1695.         lpIStorage := Storage;
  1696.         ppvObj := @OleObject;
  1697.       end;
  1698.       try
  1699.         Result := OleUIInsertObject(Data) = OLEUI_OK;
  1700.         if Result then
  1701.         try
  1702.           IsNewObject := Data.dwFlags and IOF_SELECTCREATENEW = IOF_SELECTCREATENEW;
  1703.           with ReObject do begin
  1704.             cbStruct := SizeOf(TReObject);
  1705.             cp := REO_CP_SELECTION;
  1706.             clsid := Data.clsid;
  1707.             poleobj := OleObject;
  1708.             pstg := Storage;
  1709.             polesite := OleClientSite;
  1710.             dvAspect := DVASPECT_CONTENT;
  1711.             dwFlags := REO_RESIZABLE;
  1712.             if IsNewObject then dwFlags := dwFlags or REO_BLANK;
  1713.             OleCheck(OleSetDrawAspect(OleObject,
  1714.               Data.dwFlags and IOF_CHECKDISPLAYASICON <> 0,
  1715.               Data.hMetaPict, dvAspect));
  1716.           end;
  1717.           SendMessage(Handle, EM_EXGETSEL, 0, Longint(@Selection));
  1718.           Selection.cpMax := Selection.cpMin + 1;
  1719.           OleCheck(IRichEditOle(FRichEditOle).InsertObject(ReObject));
  1720.           SendMessage(Handle, EM_EXSETSEL, 0, Longint(@Selection));
  1721.           SendMessage(Handle, EM_SCROLLCARET, 0, 0);
  1722.           IRichEditOle(FRichEditOle).SetDvaspect(
  1723.             Longint(REO_IOB_SELECTION), ReObject.dvAspect);
  1724.           if IsNewObject then OleObject.DoVerb(OLEIVERB_SHOW, nil,
  1725.             OleClientSite, 0, Handle, ClientRect);
  1726.         finally
  1727.           ReleaseObject(OleObject);
  1728.         end;
  1729.       finally
  1730.         DestroyMetaPict(Data.hMetaPict);
  1731.       end;
  1732.     finally
  1733.       ReleaseObject(OleClientSite);
  1734.       ReleaseObject(Storage);
  1735.     end;
  1736.   end
  1737.   else Result := False;
  1738. end;
  1739. function TRxCustomRichEdit.ObjectPropertiesDialog: Boolean;
  1740. var
  1741.   ObjectProps: TOleUIObjectProps;
  1742.   PropSheet: TPropSheetHeader;
  1743.   GeneralProps: TOleUIGnrlProps;
  1744.   ViewProps: TOleUIViewProps;
  1745.   LinkProps: TOleUILinkProps;
  1746.   DialogCaption: string;
  1747.   ReObject: TReObject;
  1748. begin
  1749.   Result := False;
  1750.   if not Assigned(FRichEditOle) or (SelectionType <> [stObject]) then Exit;
  1751.   FillChar(ObjectProps, SizeOf(ObjectProps), 0);
  1752.   FillChar(PropSheet, SizeOf(PropSheet), 0);
  1753.   FillChar(GeneralProps, SizeOf(GeneralProps), 0);
  1754.   FillChar(ViewProps, SizeOf(ViewProps), 0);
  1755.   FillChar(LinkProps, SizeOf(LinkProps), 0);
  1756.   FillChar(ReObject, SizeOf(ReObject), 0);
  1757.   ReObject.cbStruct := SizeOf(ReObject);
  1758.   if Succeeded(IRichEditOle(FRichEditOle).GetObject(Longint(REO_IOB_SELECTION),
  1759.     ReObject, REO_GETOBJ_POLEOBJ or REO_GETOBJ_POLESITE)) then
  1760.   try
  1761.     if ReObject.dwFlags and REO_INPLACEACTIVE = 0 then begin
  1762.       ObjectProps.cbStruct := SizeOf(ObjectProps);
  1763.       ObjectProps.dwFlags := OPF_DISABLECONVERT;
  1764.       ObjectProps.lpPS := @PropSheet;
  1765.       ObjectProps.lpObjInfo := TOleUIObjInfo.Create(Self, ReObject);
  1766.       if (ReObject.dwFlags and REO_LINK) <> 0 then begin
  1767.         ObjectProps.dwFlags := ObjectProps.dwFlags or OPF_OBJECTISLINK;
  1768.         ObjectProps.lpLinkInfo := TOleUILinkInfo.Create(Self, ReObject);
  1769.       end;
  1770.       ObjectProps.lpGP := @GeneralProps;
  1771.       ObjectProps.lpVP := @ViewProps;
  1772.       ObjectProps.lpLP := @LinkProps;
  1773.       PropSheet.dwSize := SizeOf(PropSheet);
  1774.       PropSheet.hWndParent := Handle;
  1775. {$IFDEF RX_D3}
  1776.       PropSheet.hInstance := MainInstance;
  1777. {$ELSE}
  1778.       PropSheet.hInstance := HInstance;
  1779. {$ENDIF}
  1780.       DialogCaption := Format(ResStr(SPropDlgCaption),
  1781.         [GetFullNameStr(ReObject.poleobj)]);
  1782.       PropSheet.pszCaption := PChar(DialogCaption);
  1783.       GeneralProps.cbStruct := SizeOf(GeneralProps);
  1784.       ViewProps.cbStruct := SizeOf(ViewProps);
  1785.       ViewProps.dwFlags := VPF_DISABLESCALE;
  1786.       LinkProps.cbStruct := SizeOf(LinkProps);
  1787.       LinkProps.dwFlags := ELF_DISABLECANCELLINK;
  1788.       Result := OleUIObjectProperties(ObjectProps) = OLEUI_OK;
  1789.     end;
  1790.   finally
  1791. {$IFNDEF RX_D3}
  1792.     ObjectProps.lpLinkInfo.Free;
  1793.     ObjectProps.lpObjInfo.Free;
  1794.     ReleaseObject(ReObject.polesite);
  1795.     ReleaseObject(ReObject.poleobj);
  1796. {$ENDIF}
  1797.   end;
  1798. end;
  1799. procedure TRxCustomRichEdit.Print(const Caption: string);
  1800. var
  1801.   Range: TFormatRange;
  1802.   LastChar, MaxLen, LogX, LogY, OldMap: Integer;
  1803.   SaveRect: TRect;
  1804.   TextLenEx: TGetTextLengthEx;
  1805. begin
  1806.   FillChar(Range, SizeOf(TFormatRange), 0);
  1807.   with Printer, Range do begin
  1808.     Title := Caption;
  1809.     BeginDoc;
  1810.     hdc := Handle;
  1811.     hdcTarget := hdc;
  1812.     LogX := GetDeviceCaps(Handle, LOGPIXELSX);
  1813.     LogY := GetDeviceCaps(Handle, LOGPIXELSY);
  1814.     if IsRectEmpty(PageRect) then begin
  1815.       rc.right := PageWidth * 1440 div LogX;
  1816.       rc.bottom := PageHeight * 1440 div LogY;
  1817.     end
  1818.     else begin
  1819.       rc.left := PageRect.Left * 1440 div LogX;
  1820.       rc.top := PageRect.Top * 1440 div LogY;
  1821.       rc.right := PageRect.Right * 1440 div LogX;
  1822.       rc.bottom := PageRect.Bottom * 1440 div LogY;
  1823.     end;
  1824.     rcPage := rc;
  1825.     SaveRect := rc;
  1826.     LastChar := 0;
  1827.     if RichEditVersion >= 2 then begin
  1828.       with TextLenEx do begin
  1829.         flags := GTL_DEFAULT;
  1830.         codepage := CP_ACP;
  1831.       end;
  1832.       MaxLen := Perform(EM_GETTEXTLENGTHEX, WParam(@TextLenEx), 0);
  1833.     end
  1834.     else MaxLen := GetTextLen;
  1835.     chrg.cpMax := -1;
  1836.     { ensure printer DC is in text map mode }
  1837.     OldMap := SetMapMode(hdc, MM_TEXT);
  1838.     SendMessage(Self.Handle, EM_FORMATRANGE, 0, 0);    { flush buffer }
  1839.     try
  1840.       repeat
  1841.         rc := SaveRect;
  1842.         chrg.cpMin := LastChar;
  1843.         LastChar := SendMessage(Self.Handle, EM_FORMATRANGE, 1, Longint(@Range));
  1844.         if (LastChar < MaxLen) and (LastChar <> -1) then NewPage;
  1845.       until (LastChar >= MaxLen) or (LastChar = -1);
  1846.       EndDoc;
  1847.     finally
  1848.       SendMessage(Self.Handle, EM_FORMATRANGE, 0, 0);  { flush buffer }
  1849.       SetMapMode(hdc, OldMap);       { restore previous map mode }
  1850.     end;
  1851.   end;
  1852. end;
  1853. var
  1854.   Painting: Boolean = False;
  1855. procedure TRxCustomRichEdit.WMPaint(var Message: TWMPaint);
  1856. var
  1857.   R, R1: TRect;
  1858. begin
  1859.   if RichEditVersion >= 2 then
  1860.     inherited
  1861.   else begin
  1862.     if GetUpdateRect(Handle, R, True) then
  1863.     begin
  1864.       with ClientRect do R1 := Rect(Right - 3, Top, Right, Bottom);
  1865.       if IntersectRect(R, R, R1) then InvalidateRect(Handle, @R1, True);
  1866.     end;
  1867.     if Painting then
  1868.       Invalidate
  1869.     else begin
  1870.       Painting := True;
  1871.       try
  1872.         inherited;
  1873.       finally
  1874.         Painting := False;
  1875.       end;
  1876.     end;
  1877.   end;
  1878. end;
  1879. procedure TRxCustomRichEdit.WMDestroy(var Msg: TWMDestroy);
  1880. begin
  1881.   CloseObjects;
  1882.   ReleaseObject(FRichEditOle);
  1883.   inherited;
  1884. end;
  1885. procedure TRxCustomRichEdit.WMMouseMove(var Message: TMessage);
  1886. begin
  1887.   inherited;
  1888. end;
  1889. procedure TRxCustomRichEdit.WMSetCursor(var Message: TWMSetCursor);
  1890. begin
  1891.   inherited;
  1892. end;
  1893. {$IFDEF RX_D5}
  1894. procedure TRxCustomRichEdit.WMRButtonUp(var Message: TMessage);
  1895. begin
  1896.   { RichEd20 does not pass the WM_RBUTTONUP message to defwndproc, }
  1897.   { so we get no WM_CONTEXTMENU message. Simulate message here.    }
  1898.   if Win32MajorVersion < 5 then
  1899.     Perform(WM_CONTEXTMENU, Handle, LParam(PointToSmallPoint(
  1900.       ClientToScreen(SmallPointToPoint(TWMMouse(Message).Pos)))));
  1901.   inherited;
  1902. end;
  1903. {$ENDIF}
  1904. procedure TRxCustomRichEdit.CNNotify(var Message: TWMNotify);
  1905. var
  1906.   AMsg: TMessage;
  1907. begin
  1908.   with Message do
  1909.     case NMHdr^.code of
  1910.       EN_SELCHANGE: SelectionChange;
  1911.       EN_REQUESTRESIZE: RequestSize(PReqSize(NMHdr)^.rc);
  1912.       EN_SAVECLIPBOARD:
  1913.         with PENSaveClipboard(NMHdr)^ do
  1914.           if not SaveClipboard(cObjectCount, cch) then Result := 1;
  1915.       EN_PROTECTED:
  1916.         with PENProtected(NMHdr)^ do begin
  1917.           AMsg.Msg := Msg;
  1918.           AMsg.WParam := WParam;
  1919.           AMsg.LParam := LParam;
  1920.           AMsg.Result := 0;
  1921.           if not ProtectChange(AMsg, chrg.cpMin, chrg.cpMax) then
  1922.             Result := 1;
  1923.         end;
  1924.       EN_LINK:
  1925.         with PENLink(NMHdr)^ do begin
  1926.           case Msg of
  1927.             WM_RBUTTONDOWN:
  1928.               begin
  1929.                 FClickRange := chrg;
  1930.                 FClickBtn := mbRight;
  1931.               end;
  1932.             WM_RBUTTONUP:
  1933.               begin
  1934.                 if (FClickBtn = mbRight) and (FClickRange.cpMin = chrg.cpMin) and
  1935.                   (FClickRange.cpMax = chrg.cpMax) then
  1936.                   URLClick(GetTextRange(chrg.cpMin, chrg.cpMax), mbRight);
  1937.                 with FClickRange do begin
  1938.                   cpMin := -1;
  1939.                   cpMax := -1;
  1940.                 end;
  1941.               end;
  1942.             WM_LBUTTONDOWN:
  1943.               begin
  1944.                 FClickRange := chrg;
  1945.                 FClickBtn := mbLeft;
  1946.               end;
  1947.             WM_LBUTTONUP:
  1948.               begin
  1949.                 if (FClickBtn = mbLeft) and (FClickRange.cpMin = chrg.cpMin) and
  1950.                   (FClickRange.cpMax = chrg.cpMax) then
  1951.                   URLClick(GetTextRange(chrg.cpMin, chrg.cpMax), mbLeft);
  1952.                 with FClickRange do begin
  1953.                   cpMin := -1;
  1954.                   cpMax := -1;
  1955.                 end;
  1956.               end;
  1957.           end;
  1958.         end;
  1959.       EN_STOPNOUNDO:
  1960.         begin
  1961.           { cannot allocate enough memory to maintain the undo state }
  1962.         end;
  1963.     end;
  1964. end;
  1965. function TRxCustomRichEdit.SaveClipboard(NumObj, NumChars: Integer): Boolean;
  1966. begin
  1967.   Result := True;
  1968.   if Assigned(OnSaveClipboard) then
  1969.     OnSaveClipboard(Self, NumObj, NumChars, Result);
  1970. end;
  1971. function TRxCustomRichEdit.ProtectChange(const Message: TMessage; StartPos,
  1972.   EndPos: Integer): Boolean;
  1973. begin
  1974.   Result := False;
  1975.   if Assigned(OnProtectChangeEx) then
  1976.     OnProtectChangeEx(Self, Message, StartPos, EndPos, Result)
  1977.   else if Assigned(OnProtectChange) then
  1978.     OnProtectChange(Self, StartPos, EndPos, Result);
  1979. end;
  1980. procedure TRxCustomRichEdit.SelectionChange;
  1981. begin
  1982.   if Assigned(OnSelectionChange) then OnSelectionChange(Self);
  1983. end;
  1984. procedure TRxCustomRichEdit.RequestSize(const Rect: TRect);
  1985. begin
  1986.   if Assigned(OnResizeRequest) then OnResizeRequest(Self, Rect);
  1987. end;
  1988. procedure TRxCustomRichEdit.URLClick(const URLText: string; Button: TMouseButton);
  1989. begin
  1990.   if Assigned(OnURLClick) then OnURLClick(Self, URLText, Button);
  1991. end;
  1992. function TRxCustomRichEdit.FindText(const SearchStr: string;
  1993.   StartPos, Length: Integer; Options: TRichSearchTypes): Integer;
  1994. var
  1995.   Find: TFindTextEx;
  1996.   Flags: Integer;
  1997. begin
  1998.   with Find.chrg do begin
  1999.     cpMin := StartPos;
  2000.     cpMax := cpMin + Abs(Length);
  2001.   end;
  2002.   if RichEditVersion >= 2 then begin
  2003.     if not (stBackward in Options) then Flags := FT_DOWN
  2004.     else Flags := 0;
  2005.   end
  2006.   else begin
  2007.     Options := Options - [stBackward];
  2008.     Flags := 0;
  2009.   end;
  2010.   if stWholeWord in Options then Flags := Flags or FT_WHOLEWORD;
  2011.   if stMatchCase in Options then Flags := Flags or FT_MATCHCASE;
  2012.   Find.lpstrText := PChar(SearchStr);
  2013.   Result := SendMessage(Handle, EM_FINDTEXTEX, Flags, Longint(@Find));
  2014.   if (Result >= 0) and (stSetSelection in Options) then begin
  2015.     SendMessage(Handle, EM_EXSETSEL, 0, Longint(@Find.chrgText));
  2016.     SendMessage(Handle, EM_SCROLLCARET, 0, 0);
  2017.   end;
  2018. end;
  2019. procedure TRxCustomRichEdit.ClearUndo;
  2020. begin
  2021.   SendMessage(Handle, EM_EMPTYUNDOBUFFER, 0, 0);
  2022. end;
  2023. procedure TRxCustomRichEdit.Redo;
  2024. begin
  2025.   SendMessage(Handle, EM_REDO, 0, 0);
  2026. end;
  2027. {$IFNDEF RX_V110}
  2028. procedure TRxCustomRichEdit.Undo;
  2029. begin
  2030.   SendMessage(Handle, WM_UNDO, 0, 0);
  2031. end;
  2032. {$ENDIF}
  2033. procedure TRxCustomRichEdit.StopGroupTyping;
  2034. begin
  2035.   if (RichEditVersion >= 2) and HandleAllocated then
  2036.     SendMessage(Handle, EM_STOPGROUPTYPING, 0, 0);
  2037. end;
  2038. {$IFDEF RX_D3}
  2039. procedure TRxCustomRichEdit.SetUIActive(Active: Boolean);
  2040. var
  2041.   Form: TCustomForm;
  2042. begin
  2043.   try
  2044.     Form := GetParentForm(Self);
  2045.     if Form <> nil then
  2046.       if Active then begin
  2047.         if (Form.ActiveOleControl <> nil) and
  2048.           (Form.ActiveOleControl <> Self) then
  2049.           Form.ActiveOleControl.Perform(CM_UIDEACTIVATE, 0, 0);
  2050.         Form.ActiveOleControl := Self;
  2051.         if AllowInPlace and CanFocus then SetFocus;
  2052.       end
  2053.       else begin
  2054.         if Form.ActiveOleControl = Self then Form.ActiveOleControl := nil;
  2055.         if (Form.ActiveControl = Self) and AllowInPlace then begin
  2056.           Windows.SetFocus(Handle);
  2057.           SelectionChange;
  2058.         end;
  2059.       end;
  2060.   except
  2061.     Application.HandleException(Self);
  2062.   end;
  2063. end;
  2064. procedure TRxCustomRichEdit.CMDocWindowActivate(var Message: TMessage);
  2065. begin
  2066.   if Assigned(FCallback) then
  2067.     with TRichEditOleCallback(FCallback) do
  2068.       if Assigned(FDocForm) and IsFormMDIChild(FDocForm.Form) then begin
  2069.         if Message.WParam = 0 then begin
  2070.           FFrameForm.SetMenu(0, 0, 0);
  2071.           FFrameForm.ClearBorderSpace;
  2072.         end;
  2073.       end;
  2074. end;
  2075. procedure TRxCustomRichEdit.CMUIDeactivate(var Message: TMessage);
  2076. begin
  2077.   if (GetParentForm(Self) <> nil) and Assigned(FRichEditOle) and
  2078.     (GetParentForm(Self).ActiveOleControl = Self) then
  2079.     {IRichEditOle(FRichEditOle).InPlaceDeactivate};
  2080. end;
  2081. {$ENDIF RX_D3}
  2082. { Find & Replace Dialogs }
  2083. procedure TRxCustomRichEdit.SetupFindDialog(Dialog: TFindDialog;
  2084.   const SearchStr, ReplaceStr: string);
  2085. begin
  2086.   with Dialog do begin
  2087.     if SearchStr <> '' then FindText := SearchStr;
  2088.     if RichEditVersion = 1 then
  2089.       Options := Options + [frHideUpDown, frDown];
  2090.     OnFind := FindDialogFind;
  2091. {$IFDEF RX_D3}
  2092.     OnClose := FindDialogClose;
  2093. {$ENDIF}
  2094.   end;
  2095.   if Dialog is TReplaceDialog then
  2096.     with TReplaceDialog(Dialog) do begin
  2097.       if ReplaceStr <> '' then ReplaceText := ReplaceStr;
  2098.       OnReplace := ReplaceDialogReplace;
  2099.     end;
  2100. end;
  2101. function TRxCustomRichEdit.FindDialog(const SearchStr: string): TFindDialog;
  2102. begin
  2103.   if FFindDialog = nil then begin
  2104.     FFindDialog := TFindDialog.Create(Self);
  2105.     if FReplaceDialog <> nil then
  2106.       FFindDialog.FindText := FReplaceDialog.FindText;
  2107.   end;
  2108.   Result := FFindDialog;
  2109.   SetupFindDialog(FFindDialog, SearchStr, '');
  2110.   FFindDialog.Execute;
  2111. end;
  2112. function TRxCustomRichEdit.ReplaceDialog(const SearchStr,
  2113.   ReplaceStr: string): TReplaceDialog;
  2114. begin
  2115.   if FReplaceDialog = nil then begin
  2116.     FReplaceDialog := TReplaceDialog.Create(Self);
  2117.     if FFindDialog <> nil then
  2118.       FReplaceDialog.FindText := FFindDialog.FindText;
  2119.   end;
  2120.   Result := FReplaceDialog;
  2121.   SetupFindDialog(FReplaceDialog, SearchStr, ReplaceStr);
  2122.   FReplaceDialog.Execute;
  2123. end;
  2124. function TRxCustomRichEdit.GetCanFindNext: Boolean;
  2125. begin
  2126.   Result := HandleAllocated and (FLastFind <> nil) and
  2127.     (FLastFind.FindText <> '');
  2128. end;
  2129. function TRxCustomRichEdit.FindNext: Boolean;
  2130. begin
  2131.   if CanFindNext then Result := FindEditText(FLastFind, False, True)
  2132.   else Result := False;
  2133. end;
  2134. procedure TRxCustomRichEdit.AdjustFindDialogPosition(Dialog: TFindDialog);
  2135. var
  2136.   TextRect, R: TRect;
  2137. begin
  2138.   if Dialog.Handle = 0 then Exit;
  2139.   with TextRect do begin
  2140.     TopLeft := ClientToScreen(GetCharPos(SelStart));
  2141.     BottomRight := ClientToScreen(GetCharPos(SelStart + SelLength));
  2142.     Inc(Bottom, 20);
  2143.   end;
  2144.   with Dialog do begin
  2145.     GetWindowRect(Handle, R);
  2146.     if PtInRect(R, TextRect.TopLeft) or PtInRect(R, TextRect.BottomRight) then
  2147.     begin
  2148.       if TextRect.Top > R.Bottom - R.Top + 20 then
  2149.         OffsetRect(R, 0, TextRect.Top - R.Bottom - 20)
  2150.       else begin
  2151.         if TextRect.Top + R.Bottom - R.Top < GetSystemMetrics(SM_CYSCREEN) then
  2152.           OffsetRect(R, 0, 40 + TextRect.Top - R.Top);
  2153.       end;
  2154.       Position := R.TopLeft;
  2155.     end;
  2156.   end;
  2157. end;
  2158. function TRxCustomRichEdit.FindEditText(Dialog: TFindDialog; AdjustPos, Events: Boolean): Boolean;
  2159. var
  2160.   Length, StartPos: Integer;
  2161.   SrchOptions: TRichSearchTypes;
  2162. begin
  2163.   with TFindDialog(Dialog) do begin
  2164.     SrchOptions := [stSetSelection];
  2165.     if frDown in Options then begin
  2166.       StartPos := Max(SelStart, SelStart + SelLength);
  2167.       Length := System.Length(Text) - StartPos + 1;
  2168.     end
  2169.     else begin
  2170.       SrchOptions := SrchOptions + [stBackward];
  2171.       StartPos := Min(SelStart, SelStart + SelLength);
  2172.       Length := StartPos + 1;
  2173.     end;
  2174.     if frMatchCase in Options then
  2175.       SrchOptions := SrchOptions + [stMatchCase];
  2176.     if frWholeWord in Options then
  2177.       SrchOptions := SrchOptions + [stWholeWord];
  2178.     Result := Self.FindText(FindText, StartPos, Length, SrchOptions) >= 0;
  2179.     if FindText <> '' then FLastFind := Dialog;
  2180.     if Result then begin
  2181.       if AdjustPos then AdjustFindDialogPosition(Dialog);
  2182.     end
  2183.     else if Events then TextNotFound(Dialog);
  2184.   end;
  2185. end;
  2186. procedure TRxCustomRichEdit.TextNotFound(Dialog: TFindDialog);
  2187. begin
  2188.   with Dialog do
  2189.     if Assigned(FOnTextNotFound) then FOnTextNotFound(Self, FindText);
  2190. end;
  2191. procedure TRxCustomRichEdit.FindDialogFind(Sender: TObject);
  2192. begin
  2193.   FindEditText(TFindDialog(Sender), True, True);
  2194. end;
  2195. procedure TRxCustomRichEdit.ReplaceDialogReplace(Sender: TObject);
  2196. var
  2197.   Cnt: Integer;
  2198.   SaveSelChange: TNotifyEvent;
  2199. begin
  2200.   with TReplaceDialog(Sender) do begin
  2201.     if (frReplaceAll in Options) then begin
  2202.       Cnt := 0;
  2203.       SaveSelChange := FOnSelChange;
  2204.       TRichEditStrings(Lines).EnableChange(False);
  2205.       try
  2206.         FOnSelChange := nil;
  2207.         while FindEditText(TFindDialog(Sender), False, False) do begin
  2208.           SelText := ReplaceText;
  2209.           Inc(Cnt);
  2210.         end;
  2211.         if Cnt = 0 then TextNotFound(TFindDialog(Sender))
  2212.         else AdjustFindDialogPosition(TFindDialog(Sender));
  2213.       finally
  2214.         TRichEditStrings(Lines).EnableChange(True);
  2215.         FOnSelChange := SaveSelChange;
  2216.         if Cnt > 0 then begin
  2217.           Change;
  2218.           SelectionChange;
  2219.         end;
  2220.       end;
  2221.     end
  2222.     else if (frReplace in Options) then begin
  2223.       if FindEditText(TFindDialog(Sender), True, True) then
  2224.         SelText := ReplaceText;
  2225.     end;
  2226.   end;
  2227. end;
  2228. {$IFDEF RX_D3}
  2229. procedure TRxCustomRichEdit.FindDialogClose(Sender: TObject);
  2230. begin
  2231.   CloseFindDialog(Sender as TFindDialog);
  2232. end;
  2233. procedure TRxCustomRichEdit.CloseFindDialog(Dialog: TFindDialog);
  2234. begin
  2235.   if Assigned(FOnCloseFindDialog) then FOnCloseFindDialog(Self, Dialog);
  2236. end;
  2237. {$ENDIF RX_D3}
  2238. { Conversion formats }
  2239. procedure AppendConversionFormat(const Ext: string; Plain: Boolean;
  2240.   AClass: TConversionClass);
  2241. var
  2242.   NewRec: PRichConversionFormat;
  2243. begin
  2244.   New(NewRec);
  2245.   with NewRec^ do begin
  2246. {$IFNDEF VER90}
  2247.     Extension := AnsiLowerCaseFileName(Ext);
  2248. {$ELSE}
  2249.     Extension := LowerCase(Ext);
  2250. {$ENDIF}
  2251.     PlainText := Plain;
  2252.     ConversionClass := AClass;
  2253.     Next := ConversionFormatList;
  2254.   end;
  2255.   ConversionFormatList := NewRec;
  2256. end;
  2257. class procedure TRxCustomRichEdit.RegisterConversionFormat(const AExtension: string;
  2258.   APlainText: Boolean; AConversionClass: TConversionClass);
  2259. begin
  2260.   AppendConversionFormat(AExtension, APlainText, AConversionClass);
  2261. end;
  2262. { Initialization part }
  2263. var
  2264.   OldError: Longint;
  2265.   FLibHandle: THandle;
  2266.   Ver: TOsVersionInfo;
  2267. initialization
  2268.   RichEditVersion := 1;
  2269.   OldError := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  2270.   try
  2271. {$IFNDEF RICHEDIT_VER_10}
  2272.     FLibHandle := LoadLibrary(RichEdit20ModuleName);
  2273.     if (FLibHandle > 0) and (FLibHandle < HINSTANCE_ERROR) then FLibHandle := 0;
  2274. {$ELSE}
  2275.     FLibHandle := 0;
  2276. {$ENDIF}
  2277.     if FLibHandle = 0 then begin
  2278.       FLibHandle := LoadLibrary(RichEdit10ModuleName);
  2279.       if (FLibHandle > 0) and (FLibHandle < HINSTANCE_ERROR) then FLibHandle := 0;
  2280.     end
  2281.     else begin
  2282.       RichEditVersion := 2;
  2283.       Ver.dwOSVersionInfoSize := SizeOf(Ver);
  2284.       GetVersionEx(Ver);
  2285.       with Ver do begin
  2286.         if (dwPlatformId = VER_PLATFORM_WIN32_NT) and
  2287.           (dwMajorVersion >= 5) then
  2288.           RichEditVersion := 3;
  2289.       end;
  2290.     end;
  2291.   finally
  2292.     SetErrorMode(OldError);
  2293.   end;
  2294.   CFEmbeddedObject := RegisterClipboardFormat(CF_EMBEDDEDOBJECT);
  2295.   CFLinkSource := RegisterClipboardFormat(CF_LINKSOURCE);
  2296.   CFRtf := RegisterClipboardFormat(CF_RTF);
  2297.   CFRtfNoObjs := RegisterClipboardFormat(CF_RTFNOOBJS);
  2298. finalization
  2299.   if FLibHandle <> 0 then FreeLibrary(FLibHandle);
  2300. end.