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
浙公网安备 33010602011771号