1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Windows.Forms;
5 using System.Drawing;
6 using ImageOleLib;
7 using DynamicGifLib;
8 using System.ComponentModel;
9 using System.Runtime.InteropServices;
10 using System.Diagnostics;
11
12 namespace EmotionPanel
13 {
14
15 public class ChatRichTextBox : RichTextBox
16 {
17
18 RichEditOle ole;
19 private IRichEditOle _richEditOle;
20 private Dictionary<int, REOBJECT> _oleObjectList;
21 private int _index;
22
23 #region Interop-Defines
24 [StructLayout(LayoutKind.Sequential)]
25 public struct CHARFORMAT2_STRUCT
26 {
27 public UInt32 cbSize;
28 public UInt32 dwMask;
29 public UInt32 dwEffects;
30 public Int32 yHeight;
31 public Int32 yOffset;
32 public Int32 crTextColor;
33 public byte bCharSet;
34 public byte bPitchAndFamily;
35 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
36 public char[] szFaceName;
37 public UInt16 wWeight;
38 public UInt16 sSpacing;
39 public int crBackColor; // Color.ToArgb() -> int
40 public int lcid;
41 public int dwReserved;
42 public Int16 sStyle;
43 public Int16 wKerning;
44 public byte bUnderlineType;
45 public byte bAnimation;
46 public byte bRevAuthor;
47 public byte bReserved1;
48 }
49
50 [DllImport("user32.dll", CharSet = CharSet.Auto)]
51 public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
52
53 private const int WM_USER = 0x0400;
54 private const int EM_GETCHARFORMAT = WM_USER + 58;
55 public const int EM_SETCHARFORMAT = WM_USER + 68;
56
57 public const int SCF_SELECTION = 0x0001;
58 private const int SCF_WORD = 0x0002;
59 private const int SCF_ALL = 0x0004;
60
61 #region CHARFORMAT2 Flags
62 private const UInt32 CFE_BOLD = 0x0001;
63 private const UInt32 CFE_ITALIC = 0x0002;
64 private const UInt32 CFE_UNDERLINE = 0x0004;
65 private const UInt32 CFE_STRIKEOUT = 0x0008;
66 private const UInt32 CFE_PROTECTED = 0x0010;
67 public const UInt32 CFE_LINK = 0x0020;
68 private const UInt32 CFE_AUTOCOLOR = 0x40000000;
69 private const UInt32 CFE_SUBSCRIPT = 0x00010000; /* Superscript and subscript are */
70 private const UInt32 CFE_SUPERSCRIPT = 0x00020000; /* mutually exclusive */
71
72 private const int CFM_SMALLCAPS = 0x0040; /* (*) */
73 private const int CFM_ALLCAPS = 0x0080; /* Displayed by 3.0 */
74 private const int CFM_HIDDEN = 0x0100; /* Hidden by 3.0 */
75 private const int CFM_OUTLINE = 0x0200; /* (*) */
76 private const int CFM_SHADOW = 0x0400; /* (*) */
77 private const int CFM_EMBOSS = 0x0800; /* (*) */
78 private const int CFM_IMPRINT = 0x1000; /* (*) */
79 private const int CFM_DISABLED = 0x2000;
80 private const int CFM_REVISED = 0x4000;
81
82 private const int CFM_BACKCOLOR = 0x04000000;
83 private const int CFM_LCID = 0x02000000;
84 private const int CFM_UNDERLINETYPE = 0x00800000; /* Many displayed by 3.0 */
85 private const int CFM_WEIGHT = 0x00400000;
86 private const int CFM_SPACING = 0x00200000; /* Displayed by 3.0 */
87 private const int CFM_KERNING = 0x00100000; /* (*) */
88 private const int CFM_STYLE = 0x00080000; /* (*) */
89 private const int CFM_ANIMATION = 0x00040000; /* (*) */
90 private const int CFM_REVAUTHOR = 0x00008000;
91
92
93 private const UInt32 CFM_BOLD = 0x00000001;
94 private const UInt32 CFM_ITALIC = 0x00000002;
95 private const UInt32 CFM_UNDERLINE = 0x00000004;
96 private const UInt32 CFM_STRIKEOUT = 0x00000008;
97 private const UInt32 CFM_PROTECTED = 0x00000010;
98 public const UInt32 CFM_LINK = 0x00000020;
99 private const UInt32 CFM_SIZE = 0x80000000;
100 private const UInt32 CFM_COLOR = 0x40000000;
101 private const UInt32 CFM_FACE = 0x20000000;
102 private const UInt32 CFM_OFFSET = 0x10000000;
103 private const UInt32 CFM_CHARSET = 0x08000000;
104 private const UInt32 CFM_SUBSCRIPT = CFE_SUBSCRIPT | CFE_SUPERSCRIPT;
105 private const UInt32 CFM_SUPERSCRIPT = CFM_SUBSCRIPT;
106
107 private const byte CFU_UNDERLINENONE = 0x00000000;
108 private const byte CFU_UNDERLINE = 0x00000001;
109 private const byte CFU_UNDERLINEWORD = 0x00000002; /* (*) displayed as ordinary underline */
110 private const byte CFU_UNDERLINEDOUBLE = 0x00000003; /* (*) displayed as ordinary underline */
111 private const byte CFU_UNDERLINEDOTTED = 0x00000004;
112 private const byte CFU_UNDERLINEDASH = 0x00000005;
113 private const byte CFU_UNDERLINEDASHDOT = 0x00000006;
114 private const byte CFU_UNDERLINEDASHDOTDOT = 0x00000007;
115 private const byte CFU_UNDERLINEWAVE = 0x00000008;
116 private const byte CFU_UNDERLINETHICK = 0x00000009;
117 private const byte CFU_UNDERLINEHAIRLINE = 0x0000000A; /* (*) displayed as ordinary underline */
118
119 #endregion
120
121 #endregion
122
123
124 public ChatRichTextBox()
125 : base()
126 {
127 base.BorderStyle = BorderStyle.FixedSingle;
128 this.DetectUrls = false;
129 }
130
131 public Dictionary<int, REOBJECT> OleObjectList
132 {
133 get
134 {
135 if (_oleObjectList == null)
136 {
137 _oleObjectList = new Dictionary<int, REOBJECT>(10);
138 }
139 return _oleObjectList;
140 }
141 }
142
143 internal RichEditOle RichEditOle
144 {
145 get
146 {
147 if (ole == null)
148 {
149 if (base.IsHandleCreated)
150 {
151 ole = new RichEditOle(this);
152 }
153 }
154
155 return ole;
156 }
157 }
158
159 public bool InsertImageUseImageOle(string path)
160 {
161 try
162 {
163 IGifAnimator gif = new GifAnimatorClass();
164 gif.LoadFromFile(path);
165 gif.TriggerFrameChange();
166 if (gif is IOleObject)
167 {
168 int index = _index ++;
169 REOBJECT reObj = RichEditOle.InsertOleObject(
170 (IOleObject)gif,
171 index);
172 RichEditOle.UpdateObjects(reObj.cp);
173 OleObjectList.Add(index, reObj);
174 return true;
175 }
176 return false;
177 }
178 catch (Exception)
179 {
180 return false;
181 }
182 }
183
184 public bool InsertImageUseDynamic(string path)
185 {
186 try
187 {
188 IDynamicGif gif = new DynamicGifClass();
189 gif.LoadFromFile(path);
190 gif.Play();
191 if (gif is IOleObject)
192 {
193 int index = _index++;
194 REOBJECT reObj = RichEditOle.InsertOleObject(
195 (IOleObject)gif,
196 index);
197 RichEditOle.UpdateObjects(reObj.cp);
198 OleObjectList.Add(index, reObj);
199 return true;
200 }
201 return false;
202 }
203 catch (Exception)
204 {
205 return false;
206 }
207 }
208
209 public bool InsertImageUseGifBox(Image path)
210 {
211 try
212 {
213 GifBox gif = new GifBox();
214 gif.BackColor = base.BackColor;
215 gif.Image = path;
216 RichEditOle.InsertControl(gif);
217 return true;
218 }
219 catch (Exception)
220 {
221 return false;
222 }
223 }
224
225 public bool InsertImageUseGifBox(string path)
226 {
227 try
228 {
229 GifBox gif = new GifBox();
230 gif.BackColor = base.BackColor;
231 gif.Image = Image.FromFile(path);
232 RichEditOle.InsertControl(gif);
233 return true;
234 }
235 catch (Exception)
236 {
237 return false;
238 }
239 }
240
241 [DefaultValue(false)]
242 public new bool DetectUrls
243 {
244 get { return base.DetectUrls; }
245 set { base.DetectUrls = value; }
246 }
247
248 /// <summary>
249 /// Insert a given text as a link into the RichTextBox at the current insert position.
250 /// </summary>
251 /// <param name="text">Text to be inserted</param>
252 public void InsertLink(string text)
253 {
254 InsertLink(text, this.SelectionStart);
255 }
256
257 /// <summary>
258 /// Insert a given text at a given position as a link.
259 /// </summary>
260 /// <param name="text">Text to be inserted</param>
261 /// <param name="position">Insert position</param>
262 public void InsertLink(string text, int position)
263 {
264 if (position < 0 || position > this.Text.Length)
265 throw new ArgumentOutOfRangeException("position");
266
267 this.SelectionStart = position;
268 this.SelectedText = text;
269 this.Select(position, text.Length);
270 this.SetSelectionLink(true);
271 this.Select(position + text.Length, 0);
272 }
273
274 /// <summary>
275 /// Insert a given text at at the current input position as a link.
276 /// The link text is followed by a hash (#) and the given hyperlink text, both of
277 /// them invisible.
278 /// When clicked on, the whole link text and hyperlink string are given in the
279 /// LinkClickedEventArgs.
280 /// </summary>
281 /// <param name="text">Text to be inserted</param>
282 /// <param name="hyperlink">Invisible hyperlink string to be inserted</param>
283 public void InsertLink(string text, string hyperlink)
284 {
285 InsertLink(text, hyperlink, this.SelectionStart);
286 }
287
288 /// <summary>
289 /// Insert a given text at a given position as a link. The link text is followed by
290 /// a hash (#) and the given hyperlink text, both of them invisible.
291 /// When clicked on, the whole link text and hyperlink string are given in the
292 /// LinkClickedEventArgs.
293 /// </summary>
294 /// <param name="text">Text to be inserted</param>
295 /// <param name="hyperlink">Invisible hyperlink string to be inserted</param>
296 /// <param name="position">Insert position</param>
297 public void InsertLink(string text, string hyperlink, int position)
298 {
299 if (position < 0 || position > this.Text.Length)
300 throw new ArgumentOutOfRangeException("position");
301
302 this.SelectionStart = position;
303 //this.SelectedRtf = @"{\rtf1\ansi "+text+@"\v #"+hyperlink+@"\v0}";// 只能显示英文
304 this.SelectedRtf = @"{\rtf1\ansi\cpg936 " + text + @"\v #" + hyperlink + @"\v0}"; // 可以显示中文
305 this.Select(position, text.Length + hyperlink.Length + 1);
306 this.SetSelectionLink(true);
307 this.Select(position + text.Length + hyperlink.Length + 1, 0);
308 }
309
310 /// <summary>
311 /// Set the current selection's link style
312 /// </summary>
313 /// <param name="link">true: set link style, false: clear link style</param>
314 public void SetSelectionLink(bool link)
315 {
316 SetSelectionStyle(CFM_LINK, link ? CFE_LINK : 0);
317 }
318 /// <summary>
319 /// Get the link style for the current selection
320 /// </summary>
321 /// <returns>0: link style not set, 1: link style set, -1: mixed</returns>
322 public int GetSelectionLink()
323 {
324 return GetSelectionStyle(CFM_LINK, CFE_LINK);
325 }
326
327
328 private void SetSelectionStyle(UInt32 mask, UInt32 effect)
329 {
330 CHARFORMAT2_STRUCT cf = new CHARFORMAT2_STRUCT();
331 cf.cbSize = (UInt32)Marshal.SizeOf(cf);
332 cf.dwMask = mask;
333 cf.dwEffects = effect;
334
335 IntPtr wpar = new IntPtr(SCF_SELECTION);
336 IntPtr lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
337 Marshal.StructureToPtr(cf, lpar, false);
338
339 IntPtr res = SendMessage(Handle, EM_SETCHARFORMAT, wpar, lpar);
340
341 Marshal.FreeCoTaskMem(lpar);
342 }
343
344 private int GetSelectionStyle(UInt32 mask, UInt32 effect)
345 {
346 CHARFORMAT2_STRUCT cf = new CHARFORMAT2_STRUCT();
347 cf.cbSize = (UInt32)Marshal.SizeOf(cf);
348 cf.szFaceName = new char[32];
349
350 IntPtr wpar = new IntPtr(SCF_SELECTION);
351 IntPtr lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
352 Marshal.StructureToPtr(cf, lpar, false);
353
354 IntPtr res = SendMessage(Handle, EM_GETCHARFORMAT, wpar, lpar);
355
356 cf = (CHARFORMAT2_STRUCT)Marshal.PtrToStructure(lpar, typeof(CHARFORMAT2_STRUCT));
357
358 int state;
359 // dwMask holds the information which properties are consistent throughout the selection:
360 if ((cf.dwMask & mask) == mask)
361 {
362 if ((cf.dwEffects & effect) == effect)
363 state = 1;
364 else
365 state = 0;
366 }
367 else
368 {
369 state = -1;
370 }
371
372 Marshal.FreeCoTaskMem(lpar);
373 return state;
374 }
375 ///////////////////////////////////////////
376 /////////////////////////////////////////////
377
378 IRichEditOle richEditOle
379 {
380 get
381 {
382 if (this._richEditOle == null)
383 {
384 IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(IntPtr)));
385 IntPtr richEditOleIntPtr = IntPtr.Zero;
386 Marshal.WriteIntPtr(ptr, IntPtr.Zero);
387 try
388 {
389 int msgResult = (int)SendMessage(this.Handle, EmotionPanel.NativeMethods.EM_GETOLEINTERFACE, IntPtr.Zero, ptr);
390 if (msgResult != 0)
391 {
392 IntPtr intPtr = Marshal.ReadIntPtr(ptr);
393 try
394 {
395 if (intPtr != IntPtr.Zero)
396 {
397 Guid guid = new Guid("00020D00-0000-0000-c000-000000000046");
398 Marshal.QueryInterface(intPtr, ref guid, out richEditOleIntPtr);
399
400 this._richEditOle = (IRichEditOle)Marshal.GetTypedObjectForIUnknown(richEditOleIntPtr, typeof(IRichEditOle));
401 }
402 }
403 finally
404 {
405 Marshal.Release(intPtr);
406 }
407 }
408 }
409 catch (Exception err)
410 {
411 Trace.WriteLine(err.ToString());
412 }
413 finally
414 {
415 Marshal.FreeCoTaskMem(ptr);
416 }
417 }
418 return this._richEditOle;
419 }
420 }
421
422 public new bool ReadOnly { get; set; }
423
424 protected override void WndProc(ref Message m)
425 {
426 switch (m.Msg)
427 {
428 case 0x0100:
429 if (this.ReadOnly)
430 return;
431 break;
432 case 0X0102:
433 if (this.ReadOnly)
434 return;
435 break;
436 default:
437 break;
438 }
439 base.WndProc(ref m);
440 }
441
442 List<MyGIF> gifList = new List<MyGIF>();
443 Panel gifPanel = new Panel();
444 public void ClearGif()
445 {
446 this.gifPanel.Controls.Clear();
447 this.gifList.Clear();
448 }
449
450 public void InsertGIF(string Name, Image Data)
451 {
452
453 MyGIF gif = new MyGIF(Name, Data);
454 gif.Box.Invalidate();
455 this.gifPanel.Controls.Add(gif.Box);
456 this.gifList.Add(gif);
457
458 //RichEditOle ole = new RichEditOle(this);
459 ole.InsertControl(gif);
460
461
462 this.Invalidate();
463
464
465 }
466
467 public string GetGIFInfo()
468 {
469 string imageInfo = "";
470 REOBJECT reObject = new REOBJECT();
471 for (int i = 0; i < this.richEditOle.GetObjectCount(); i++)
472 {
473 this.richEditOle.GetObject(i, reObject, GETOBJECTOPTIONS.REO_GETOBJ_ALL_INTERFACES);
474 MyGIF gif = this.gifList.Find(p => p != null && p.Index == reObject.dwUser);
475 if (gif != null)
476 {
477 imageInfo += reObject.cp.ToString() + ":" + gif.Name + "|";
478 }
479 }
480 return imageInfo;
481 }
482
483 private void SetSelectionStyle()
484 {
485 CHARFORMAT2_STRUCT cf = new CHARFORMAT2_STRUCT();
486 cf.cbSize = (UInt32)Marshal.SizeOf(cf);
487 cf.dwMask = CFM_LINK;
488 cf.dwEffects = CFE_LINK;
489
490 IntPtr wpar = new IntPtr(SCF_SELECTION);
491 IntPtr lpar = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
492 Marshal.StructureToPtr(cf, lpar, false);
493
494 IntPtr res = (IntPtr)SendMessage(Handle, EM_SETCHARFORMAT, wpar, lpar);
495
496 Marshal.FreeCoTaskMem(lpar);
497 }
498
499 public void SetFont(string Name, bool Bold, bool Italic, bool Underline, Color Color, float Size)
500 {
501 FontStyle style = FontStyle.Regular;
502 if (Bold) style |= FontStyle.Bold;
503 if (Italic) style |= FontStyle.Italic;
504 if (Underline) style |= FontStyle.Underline;
505
506 this.Font = new Font(Name, Size, style);
507 this.ForeColor = Color;
508 }
509
510 public string GetTextToSend()
511 {
512 string value = string.Empty;
513 value += "\\n" + this.Font.Name;
514 value += "\\b" + (this.Font.Bold ? "1" : "0");
515 value += "\\i" + (this.Font.Italic ? "1" : "0");
516 value += "\\u" + (this.Font.Underline ? "1" : "0");
517 value += "\\s" + this.Font.Size.ToString();
518 value += "\\c" + ColorTranslator.ToHtml(this.ForeColor);
519 value += "\\t" + this.Text;
520 value += "\\p" + this.GetGIFInfo();
521
522 return value;
523 }
524 }
525 }