/Laboratory/hppadd/my_rtf.pas

http://delphi-miranda-plugins.googlecode.com/ · Pascal · 419 lines · 312 code · 30 blank · 77 comment · 26 complexity · 22b6238cd8ced67e19fc107aaf8fdd18 MD5 · raw file

  1. unit my_rtf;
  2. interface
  3. uses
  4. richedit,
  5. windows;
  6. //function InitRichEditLibrary: Integer;
  7. function GetRichRTFW(RichEditHandle: THandle; var RTFStream: WideString;
  8. SelectionOnly, PlainText, NoObjects, PlainRTF: Boolean): Integer;// overload;
  9. function GetRichRTFA(RichEditHandle: THandle; var RTFStream: AnsiString;
  10. SelectionOnly, PlainText, NoObjects, PlainRTF: Boolean): Integer;// overload;
  11. function GetRichString(RichEditHandle: THandle; SelectionOnly: Boolean = false): WideString;
  12. function SetRichRTFW(RichEditHandle: THandle; const RTFStream: WideString;
  13. SelectionOnly, PlainText, PlainRTF: Boolean): Integer;// overload;
  14. function SetRichRTFA(RichEditHandle: THandle; const RTFStream: AnsiString;
  15. SelectionOnly, PlainText, PlainRTF: Boolean): Integer;// overload;
  16. function FormatString2RTFW(const Source: WideString; const Suffix: AnsiString = ''): AnsiString;// overload;
  17. function FormatString2RTFA(const Source: AnsiString; const Suffix: AnsiString = ''): AnsiString;// overload;
  18. procedure ReplaceCharFormatRange(RichEditHandle: THandle;
  19. const fromCF, toCF: CHARFORMAT2; idx, len: Integer);
  20. procedure ReplaceCharFormat(RichEditHandle: THandle; const fromCF, toCF: CHARFORMAT2);
  21. function GetTextLength(RichEditHandle:THandle): Integer;
  22. function GetTextRange(RichEditHandle:THandle; cpMin,cpMax: Integer): AnsiString;
  23. implementation
  24. uses
  25. common, // inttostr
  26. hpp_global; // AnsiToWideString, WideToAnsiString
  27. type
  28. PTextStream = ^TTextStream;
  29. TTextStream = record
  30. Size: Integer;
  31. case Boolean of
  32. false: (Data: PAnsiChar);
  33. true: (DataW: PWideChar);
  34. end;
  35. {
  36. var
  37. FRichEditModule: THandle = 0;
  38. FRichEditVersion: Integer = 0;
  39. function GetModuleVersionFile(hModule: THandle): Integer;
  40. var
  41. dwVersion: Cardinal;
  42. begin
  43. Result := -1;
  44. if hModule = 0 then exit;
  45. try
  46. dwVersion := GetFileVersion(GetModuleName(hModule));
  47. if dwVersion <> Cardinal(-1) then
  48. Result := LoWord(dwVersion);
  49. except
  50. end;
  51. end;
  52. function InitRichEditLibrary: Integer;
  53. const
  54. RICHED20_DLL = 'RICHED20.DLL';
  55. MSFTEDIT_DLL = 'MSFTEDIT.DLL';
  56. var
  57. hModule : THandle;
  58. hVersion: Integer;
  59. emError : DWord;
  60. begin
  61. if FRichEditModule = 0 then
  62. begin
  63. FRichEditVersion := -1;
  64. emError := SetErrorMode(SEM_NOOPENFILEERRORBOX);
  65. try
  66. FRichEditModule := LoadLibrary(RICHED20_DLL);
  67. if FRichEditModule <= HINSTANCE_ERROR then
  68. FRichEditModule := 0;
  69. if FRichEditModule <> 0 then
  70. FRichEditVersion := GetModuleVersionFile(FRichEditModule);
  71. repeat
  72. if FRichEditVersion > 40 then
  73. break;
  74. hModule := LoadLibrary(MSFTEDIT_DLL);
  75. if hModule <= HINSTANCE_ERROR then
  76. hModule := 0;
  77. if hModule <> 0 then
  78. begin
  79. hVersion := GetModuleVersionFile(hModule);
  80. if hVersion > FRichEditVersion then
  81. begin
  82. if FRichEditModule <> 0 then
  83. FreeLibrary(FRichEditModule);
  84. FRichEditModule := hModule;
  85. FRichEditVersion := hVersion;
  86. break;
  87. end;
  88. FreeLibrary(hModule);
  89. end;
  90. until True;
  91. if (FRichEditModule <> 0) and (FRichEditVersion = 0) then
  92. FRichEditVersion := 20;
  93. finally
  94. SetErrorMode(emError);
  95. end;
  96. end;
  97. Result := FRichEditVersion;
  98. end;
  99. }
  100. function RichEditStreamLoad(dwCookie: DWORD_PTR; pbBuff: PByte; cb: Longint; var pcb: Longint): dword; stdcall;
  101. var
  102. pBuff: PAnsiChar;
  103. begin
  104. with PTextStream(dwCookie)^ do
  105. begin
  106. pBuff := Data;
  107. pcb := Size;
  108. if pcb > cb then
  109. pcb := cb;
  110. Move(pBuff^, pbBuff^, pcb);
  111. Inc(Data, pcb);
  112. Dec(Size, pcb);
  113. end;
  114. Result := 0;
  115. end;
  116. function RichEditStreamSave(dwCookie: DWORD_PTR; pbBuff: PByte; cb: Longint; var pcb: Longint): dword; stdcall;
  117. var
  118. prevSize: Integer;
  119. begin
  120. with PTextStream(dwCookie)^ do
  121. begin
  122. prevSize := Size;
  123. Inc(Size,cb);
  124. ReallocMem(Data,Size);
  125. Move(pbBuff^,(Data+prevSize)^,cb);
  126. pcb := cb;
  127. end;
  128. Result := 0;
  129. end;
  130. function _GetRichRTF(RichEditHandle: THandle; TextStream: PTextStream;
  131. SelectionOnly, PlainText, NoObjects, PlainRTF, Unicode: Boolean): Integer;
  132. var
  133. es: TEditStream;
  134. Format: Longint;
  135. begin
  136. format := 0;
  137. if SelectionOnly then
  138. Format := Format or SFF_SELECTION;
  139. if PlainText then
  140. begin
  141. if NoObjects then
  142. Format := Format or SF_TEXT
  143. else
  144. Format := Format or SF_TEXTIZED;
  145. if Unicode then
  146. Format := Format or SF_UNICODE;
  147. end
  148. else
  149. begin
  150. if NoObjects then
  151. Format := Format or SF_RTFNOOBJS
  152. else
  153. Format := Format or SF_RTF;
  154. if PlainRTF then
  155. Format := Format or SFF_PLAINRTF;
  156. // if Unicode then format := format or SF_USECODEPAGE or (CP_UTF16 shl 16);
  157. end;
  158. TextStream^.Size := 0;
  159. TextStream^.Data := nil;
  160. es.dwCookie := DWORD_PTR(TextStream);
  161. es.dwError := 0;
  162. es.pfnCallback := @RichEditStreamSave;
  163. SendMessage(RichEditHandle, EM_STREAMOUT, format, LPARAM(@es));
  164. Result := es.dwError;
  165. end;
  166. function GetRichRTFW(RichEditHandle: THandle; var RTFStream: WideString;
  167. SelectionOnly, PlainText, NoObjects, PlainRTF: Boolean): Integer;
  168. var
  169. Stream: TTextStream;
  170. begin
  171. Result := _GetRichRTF(RichEditHandle, @Stream,
  172. SelectionOnly, PlainText, NoObjects, PlainRTF, PlainText);
  173. if Assigned(Stream.DataW) then
  174. begin
  175. if PlainText then
  176. SetString(RTFStream, Stream.DataW, Stream.Size div SizeOf(WideChar))
  177. else
  178. RTFStream := AnsiToWideString(Stream.Data, CP_ACP);
  179. FreeMem(Stream.Data, Stream.Size);
  180. end;
  181. end;
  182. function GetRichRTFA(RichEditHandle: THandle; var RTFStream: AnsiString;
  183. SelectionOnly, PlainText, NoObjects, PlainRTF: Boolean): Integer;
  184. var
  185. Stream: TTextStream;
  186. begin
  187. Result := _GetRichRTF(RichEditHandle, @Stream,
  188. SelectionOnly, PlainText, NoObjects, PlainRTF, False);
  189. if Assigned(Stream.Data) then
  190. begin
  191. SetString(RTFStream, Stream.Data, Stream.Size - 1);
  192. FreeMem(Stream.Data, Stream.Size);
  193. end;
  194. end;
  195. function GetRichString(RichEditHandle: THandle; SelectionOnly: Boolean = false): WideString;
  196. begin
  197. GetRichRTFW(RichEditHandle,Result,SelectionOnly,True,True,False);
  198. end;
  199. function _SetRichRTF(RichEditHandle: THandle; TextStream: PTextStream;
  200. SelectionOnly, PlainText, PlainRTF, Unicode: Boolean): Integer;
  201. var
  202. es: TEditStream;
  203. Format: Longint;
  204. begin
  205. Format := 0;
  206. if SelectionOnly then
  207. Format := Format or SFF_SELECTION;
  208. if PlainText then
  209. begin
  210. Format := Format or SF_TEXT;
  211. if Unicode then
  212. Format := Format or SF_UNICODE;
  213. end
  214. else
  215. begin
  216. Format := Format or SF_RTF;
  217. if PlainRTF then
  218. Format := Format or SFF_PLAINRTF;
  219. // if Unicode then format := format or SF_USECODEPAGE or (CP_UTF16 shl 16);
  220. end;
  221. es.dwCookie := LPARAM(TextStream);
  222. es.dwError := 0;
  223. es.pfnCallback := @RichEditStreamLoad;
  224. SendMessage(RichEditHandle, EM_STREAMIN, format, LPARAM(@es));
  225. Result := es.dwError;
  226. end;
  227. function SetRichRTFW(RichEditHandle: THandle; const RTFStream: WideString;
  228. SelectionOnly, PlainText, PlainRTF: Boolean): Integer;
  229. var
  230. Stream: TTextStream;
  231. Buffer: AnsiString;
  232. begin
  233. if PlainText then
  234. begin
  235. Stream.DataW := @RTFStream[1];
  236. Stream.Size := Length(RTFStream) * SizeOf(WideChar);
  237. end
  238. else
  239. begin
  240. Buffer := WideToAnsiString(RTFStream, CP_ACP);
  241. Stream.Data := @Buffer[1];
  242. Stream.Size := Length(Buffer);
  243. end;
  244. Result := _SetRichRTF(RichEditHandle, @Stream,
  245. SelectionOnly, PlainText, PlainRTF, PlainText);
  246. end;
  247. function SetRichRTFA(RichEditHandle: THandle; const RTFStream: AnsiString;
  248. SelectionOnly, PlainText, PlainRTF: Boolean): Integer;
  249. var
  250. Stream: TTextStream;
  251. begin
  252. Stream.Data := @RTFStream[1];
  253. Stream.Size := Length(RTFStream);
  254. Result := _SetRichRTF(RichEditHandle, @Stream,
  255. SelectionOnly, PlainText, PlainRTF, False);
  256. end;
  257. function FormatString2RTFW(const Source: WideString; const Suffix: AnsiString = ''): AnsiString;
  258. var
  259. Text: PWideChar;
  260. buf:array [0..15] of AnsiChar;
  261. begin
  262. Text := PWideChar(Source);
  263. Result := '{\uc1 ';
  264. while Text[0] <> #0 do
  265. begin
  266. if (Text[0] = #13) and (Text[1] = #10) then
  267. begin
  268. Result := Result + '\par ';
  269. Inc(Text);
  270. end
  271. else
  272. case Text[0] of
  273. #10:
  274. Result := Result + '\par ';
  275. #09:
  276. Result := Result + '\tab ';
  277. '\', '{', '}':
  278. Result := Result + '\' + AnsiChar(Text[0]);
  279. else
  280. if Word(Text[0]) < 128 then
  281. Result := Result + AnsiChar(Word(Text[0]))
  282. else
  283. Result := Result + '\u'+IntToStr(buf,Word(Text[0]))+'?';
  284. end;
  285. Inc(Text);
  286. end;
  287. Result := Result + Suffix + '}';
  288. end;
  289. function FormatString2RTFA(const Source: AnsiString; const Suffix: AnsiString = ''): AnsiString;
  290. var
  291. Text: PAnsiChar;
  292. begin
  293. Text := PAnsiChar(Source);
  294. Result := '{';
  295. while Text[0] <> #0 do
  296. begin
  297. if (Text[0] = #13) and (Text[1] = #10) then
  298. begin
  299. Result := Result + '\line ';
  300. Inc(Text);
  301. end
  302. else
  303. case Text[0] of
  304. #10:
  305. Result := Result + '\line ';
  306. #09:
  307. Result := Result + '\tab ';
  308. '\', '{', '}':
  309. Result := Result + '\' + Text[0];
  310. else
  311. Result := Result + Text[0];
  312. end;
  313. Inc(Text);
  314. end;
  315. Result := Result + Suffix + '}';
  316. end;
  317. function GetTextLength(RichEditHandle: THandle): Integer;
  318. var
  319. gtxl: GETTEXTLENGTHEX;
  320. begin
  321. gtxl.flags := GTL_DEFAULT or GTL_PRECISE;
  322. gtxl.codepage := 1200;
  323. gtxl.flags := gtxl.flags or GTL_NUMCHARS;
  324. Result := SendMessage(RichEditHandle, EM_GETTEXTLENGTHEX, WPARAM(@gtxl), 0);
  325. end;
  326. procedure ReplaceCharFormatRange(RichEditHandle: THandle;
  327. const fromCF, toCF: CHARFORMAT2; idx, len: Integer);
  328. var
  329. cr: CHARRANGE;
  330. cf: CHARFORMAT2;
  331. loglen: Integer;
  332. res: DWord;
  333. begin
  334. if len = 0 then
  335. exit;
  336. cr.cpMin := idx;
  337. cr.cpMax := idx + len;
  338. SendMessage(RichEditHandle, EM_EXSETSEL, 0, LPARAM(@cr));
  339. ZeroMemory(@cf, SizeOf(cf));
  340. cf.cbSize := SizeOf(cf);
  341. cf.dwMask := fromCF.dwMask;
  342. res := SendMessage(RichEditHandle, EM_GETCHARFORMAT, SCF_SELECTION, LPARAM(@cf));
  343. if (res and fromCF.dwMask) = 0 then
  344. begin
  345. if len = 2 then
  346. begin
  347. // wtf, msdn tells that cf will get the format of the first AnsiChar,
  348. // and then we have to select it, if format match or second, if not
  349. // instead we got format of the last AnsiChar... weired
  350. if (cf.dwEffects and fromCF.dwEffects) = fromCF.dwEffects then
  351. Inc(cr.cpMin)
  352. else
  353. Dec(cr.cpMax);
  354. SendMessage(RichEditHandle, EM_EXSETSEL, 0, LPARAM(@cr));
  355. SendMessage(RichEditHandle, EM_SETCHARFORMAT, SCF_SELECTION, LPARAM(@toCF));
  356. end
  357. else
  358. begin
  359. loglen := len div 2;
  360. ReplaceCharFormatRange(RichEditHandle, fromCF, toCF, idx, loglen);
  361. ReplaceCharFormatRange(RichEditHandle, fromCF, toCF, idx + loglen, len - loglen);
  362. end;
  363. end
  364. else if (cf.dwEffects and fromCF.dwEffects) = fromCF.dwEffects then
  365. SendMessage(RichEditHandle, EM_SETCHARFORMAT, SCF_SELECTION, LPARAM(@toCF));
  366. end;
  367. procedure ReplaceCharFormat(RichEditHandle: THandle; const fromCF, toCF: CHARFORMAT2);
  368. begin
  369. ReplaceCharFormatRange(RichEditHandle,fromCF,toCF,0,GetTextLength(RichEditHandle));
  370. end;
  371. function GetTextRange(RichEditHandle: THandle; cpMin,cpMax: Integer): AnsiString;
  372. var
  373. tr: TextRange;
  374. begin
  375. tr.chrg.cpMin := cpMin;
  376. tr.chrg.cpMax := cpMax;
  377. SetLength(Result,cpMax-cpMin);
  378. tr.lpstrText := @Result[1];
  379. SendMessage(RichEditHandle,EM_GETTEXTRANGE,0,LPARAM(@tr));
  380. end;
  381. initialization
  382. finalization
  383. // if FRichEditModule <> 0 then FreeLibrary(FRichEditModule);
  384. end.