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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2010-12-15 集装箱货柜号码 公式算法
2007-12-15 VB6中判断用户是否按下了InputBox的取消按钮
2007-12-15 无锡之行