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 = @"{ tf1ansi "+text+@"v #"+hyperlink+@"v0}";// 只能显示英文 304 this.SelectedRtf = @"{ tf1ansicpg936 " + 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 }