using System; using System.Diagnostics; using System.Windows.Forms; using System.Text.RegularExpressions; using System.Collections.Generic; using System.Text; using System.IO; /// <summary> /// Helper class to decode HTML from the clipboard. /// See http://blogs.msdn.com/jmstall/archive/2007/01/21/html-clipboard.aspx for details. /// </summary> class HtmlFragment { #region Read and decode from clipboard /// <summary> /// Get a HTML fragment from the clipboard. /// </summary> /// <example> /// string html = "<b>Hello!</b>"; /// HtmlFragment.CopyToClipboard(html); /// HtmlFragment html2 = HtmlFragment.FromClipboard(); /// Debug.Assert(html2.Fragment == html); /// </example> static public HtmlFragment FromClipboard() { if (Clipboard.ContainsText(TextDataFormat.Html)) { MemoryStream ms = (MemoryStream)Clipboard.GetData("Html Format"); ms.Position = 0; byte[] vBytes = new byte[ms.Length]; ms.Read(vBytes, 0, (int)ms.Length); string rawClipboardText = Encoding.UTF8.GetString(vBytes); //string rawClipboardText = Clipboard.GetText(TextDataFormat.Html ); HtmlFragment h = new HtmlFragment(rawClipboardText); return h; } else { return null; } } /// <summary> /// Create an HTML fragment decoder around raw HTML text from the clipboard. /// This text should have the header. /// </summary> /// <param name="rawClipboardText">raw html text, with header.</param> public HtmlFragment(string rawClipboardText) { // This decodes CF_HTML, which is an entirely text format using UTF-8. // Format of this header is described at: // http://msdn.microsoft.com/library/default.asp?url=/workshop/networking/clipboard/htmlclipboard.asp // Note the counters are byte counts in the original string, which may be Ansi. So byte counts // may be the same as character counts (since sizeof(char) == 1). // But System.String is unicode, and so byte couns are no longer the same as character counts, // (since sizeof(wchar) == 2). int startHMTL = 0; int endHTML = 0; int startFragment = 0; int endFragment = 0; Regex r; Match m; r = new Regex("([a-zA-Z]+):(.+?)[\r\n]", RegexOptions.IgnoreCase | RegexOptions.Compiled); for (m = r.Match(rawClipboardText); m.Success; m = m.NextMatch()) { string key = m.Groups[1].Value.ToLower(); string val = m.Groups[2].Value; switch (key) { // Version number of the clipboard. Starting version is 0.9. case "version": m_version = val; break; // Byte count from the beginning of the clipboard to the start of the context, or -1 if no context case "starthtml": if (startHMTL != 0) throw new FormatException("StartHtml is already declared"); startHMTL = int.Parse(val); break; // Byte count from the beginning of the clipboard to the end of the context, or -1 if no context. case "endhtml": if (startHMTL == 0) throw new FormatException("StartHTML must be declared before endHTML"); endHTML = int.Parse(val); //m_fullText = rawClipboardText.Substring(startHMTL, 3); m_fullText = rawClipboardText.Substring(startHMTL); //Console.WriteLine(m_fullText.Length ); //m_fullText = rawClipboardText.Substring(startHMTL, endHTML - startHMTL); break; // Byte count from the beginning of the clipboard to the start of the fragment. case "startfragment": if (startFragment != 0) throw new FormatException("StartFragment is already declared"); startFragment = int.Parse(val); break; // Byte count from the beginning of the clipboard to the end of the fragment. case "endfragment": if (startFragment == 0) throw new FormatException("StartFragment must be declared before EndFragment"); endFragment = int.Parse(val); m_fragment = rawClipboardText.Substring(startFragment, endFragment - startFragment); break; // Optional Source URL, used for resolving relative links. case "sourceurl": m_source = new System.Uri(val); break; } } // end for if (m_fullText == null && m_fragment == null) { throw new FormatException("No data specified"); } } // Data. See properties for descriptions. string m_version; string m_fullText; string m_fragment; System.Uri m_source; /// <summary> /// Get the Version of the html. Usually something like "1.0". /// </summary> public string Version { get { return m_version; } } /// <summary> /// Get the full text (context) of the HTML fragment. This includes tags that the HTML is enclosed in. /// May be null if context is not specified. /// </summary> public string Context { get { return m_fullText; } } /// <summary> /// Get just the fragment of HTML text. /// </summary> public string Fragment { get { return m_fragment; } } /// <summary> /// Get the Source URL of the HTML. May be null if no SourceUrl is specified. This is useful for resolving relative urls. /// </summary> public System.Uri SourceUrl { get { return m_source; } } #endregion // Read and decode from clipboard #region Write to Clipboard // Helper to convert an integer into an 8 digit string. // String must be 8 characters, because it will be used to replace an 8 character string within a larger string. static string To8DigitString(int x) { //return String.Format("{0,8}", x); return x.ToString().PadLeft(8, '0'); } /// <summary> /// Clears clipboard and copy a HTML fragment to the clipboard. This generates the header. /// </summary> /// <param name="htmlFragment">A html fragment.</param> /// <example> /// HtmlFragment.CopyToClipboard("<b>Hello!</b>"); /// </example> /// <summary> /// Clears clipboard and copy a HTML fragment to the clipboard, providing additional meta-information. /// </summary> /// <param name="htmlFragment">a html fragment</param> /// <param name="title">optional title of the HTML document (can be null)</param> /// <param name="sourceUrl">optional Source URL of the HTML document, for resolving relative links (can be null)</param> public static void CopyToClipboard(string htmlFragment) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); // Builds the CF_HTML header. See format specification here: // http://msdn.microsoft.com/library/default.asp?url=/workshop/networking/clipboard/htmlclipboard.asp // The string contains index references to other spots in the string, so we need placeholders so we can compute the offsets. // The <<<<<<<_ strings are just placeholders. We'll backpatch them actual values afterwards. // The string layout (<<<) also ensures that it can't appear in the body of the html because the < // character must be escaped. string header = @"Version:0.9 StartHTML:<<<<<<<1 EndHTML:<<<<<<<2 StartFragment:<<<<<<<3 EndFragment:<<<<<<<4 "; string pre = @"<!doctype html><html><BODY><!--StartFragment-->"; string post = @"<!--EndFragment--></BODY></HTML>"; sb.Append(header); int startHTML = sb.Length; sb.Append(pre); int fragmentStart = sb.Length; sb.Append(htmlFragment); int fragmentEnd = sb.Length; sb.Append(post); int endHTML = sb.Length; // Backpatch offsets sb.Replace("<<<<<<<1", To8DigitString(startHTML)); sb.Replace("<<<<<<<2", To8DigitString(endHTML)); sb.Replace("<<<<<<<3", To8DigitString(fragmentStart)); sb.Replace("<<<<<<<4", To8DigitString(fragmentEnd)); // Finally copy to clipboard. string data = sb.ToString(); Clipboard.Clear(); byte[] b = Encoding.Default.GetBytes(data); MemoryStream ms = new MemoryStream(); ms.Write(b, 0, b.Length); Clipboard.SetData("Html Format", b); //Clipboard.SetText(data, TextDataFormat.Html); } public static void CopyHtmlToClipBoard(string html) { Encoding enc = Encoding.UTF8; string begin = "Version:0.9\r\nStartHTML:{0:000000}\r\nEndHTML:{1:000000}\r\nStartFragment:{2:000000}\r\nEndFragment:{3:000000}\r\n"; string html_begin = "<html>\r\n<body>\r\n" + "<!--StartFragment-->"; string html_end = "<!--EndFragment-->\r\n</body>\r\n</html>\r\n"; string begin_sample = String.Format(begin, 0, 0, 0, 0); int count_begin = enc.GetByteCount(begin_sample); int count_html_begin = enc.GetByteCount(html_begin); int count_html = enc.GetByteCount(html); int count_html_end = enc.GetByteCount(html_end); string html_total = String.Format( begin , count_begin , count_begin + count_html_begin + count_html + count_html_end , count_begin + count_html_begin , count_begin + count_html_begin + count_html ) + html_begin + html + html_end; DataObject obj = new DataObject(); obj.SetData(DataFormats.Html, new System.IO.MemoryStream( enc.GetBytes(html_total))); Clipboard.SetDataObject(obj, true); } #endregion // Write to Clipboard } // end of class
HtmlFragment h = HtmlFragment.FromClipboard();
Console.WriteLine(h.Context );
//string htmlFragment = Encoding.UTF8.GetString(Encoding.Default.GetBytes("呵呵,测试一下"));
//HtmlFragment.CopyHtmlToClipBoard("<DIV>好像可以了</br>oh,mygod<IMG src=\"file:///C:\\b.jpg\"></DIV>");
原文见
http://blogs.msdn.com/b/jmstall/archive/2007/01/21/sample-code-html-clipboard.aspx
http://blog.tcx.be/2005/08/copying-html-fragment-to-clipboard.html