DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

クリップボードにHTML形式のデータをコピーする

ここでは、クリップボードにHTML形式(HTML Format)のデータをコピーする方法を紹介します。また、クリップボードにあるHTML形式のデータを取得(ペースト、貼り付け)する方法にも触れます。

HTML形式のデータをクリップボードにコピーする

クリップボードにHTML形式のデータをコピーするには、まず、「HTML Clipboard Format」で説明されているような、適切なフォーマットに従って文字列のデータを作成する必要があります。

詳しくは説明しませんが、例えば「<b>こんにちは</b>」という内容をHTML形式でコピーしたい場合、次のような文字列を作成し、文字コードをUTF8として、クリップボードに貼り付けます。

このデータをHTML形式でクリップボードにコピーするには、次のようにします。

VB.NET
コードを隠すコードを選択
'Imports System.Windows.Forms

'HTML形式でコピーするデータ
Dim htmlFormatString As String = "Version:0.9" & vbCrLf & _
    "StartHTML:00000097" & vbCrLf & _
    "EndHTML:00000187" & vbCrLf & _
    "StartFragment:00000131" & vbCrLf & _
    "EndFragment:00000153" & vbCrLf & _
    "<html><body>" & vbCrLf & _
    "<!--StartFragment--><b>こんにちは</b><!--EndFragment-->" & vbCrLf & _
    "</body></html>"
'DataObjectを作成し、データをセットする
Dim dataObj As New DataObject()
dataObj.SetData(DataFormats.Html, htmlFormatString)
'クリップボードにコピーする
Clipboard.SetDataObject(dataObj)
C#
コードを隠すコードを選択
//using System.Windows.Forms;

//HTML形式でコピーするデータ
string htmlFormatString = "Version:0.9\r\n" +
    "StartHTML:00000097\r\n" +
    "EndHTML:00000187\r\n" +
    "StartFragment:00000131\r\n" +
    "EndFragment:00000153\r\n" +
    "<html><body>\r\n" +
    "<!--StartFragment--><b>こんにちは</b><!--EndFragment-->\r\n" +
    "</body></html>";
//DataObjectを作成し、データをセットする
DataObject dataObj = new DataObject();
dataObj.SetData(DataFormats.Html, htmlFormatString);
//クリップボードにコピーする
Clipboard.SetDataObject(dataObj);

しかし、私が試した限りでは、.NET Framework 4.0以下では、上記のようにすると、データの文字コードはANSI(日本語では、通常Shift JIS)となり、UTF8になりません。以下のように、文字列の代わりにMemoryStreamを使用すると、うまく行きます。.NET Framework 4.5でこの問題は修正されたようですが、.NET Framework 4.5以上で以下のコードを使用しても問題ありませんので、このようにしておいた方が良いでしょう。

VB.NET
コードを隠すコードを選択
'Imports System.Windows.Forms

'HTML形式でコピーするデータ
Dim htmlFormatString As String = "Version:0.9" & vbCrLf & _
    "StartHTML:00000097" & vbCrLf & _
    "EndHTML:00000187" & vbCrLf & _
    "StartFragment:00000131" & vbCrLf & _
    "EndFragment:00000153" & vbCrLf & _
    "<html><body>" & vbCrLf & _
    "<!--StartFragment--><b>こんにちは</b><!--EndFragment-->" & vbCrLf & _
    "</body></html>"
'UTF8のMemoryStreamを作成する
Dim htmlFormatData As New System.IO.MemoryStream( _
    System.Text.Encoding.UTF8.GetBytes(htmlFormatString))
'DataObjectを作成し、データをセットする
Dim dataObj As New DataObject()
dataObj.SetData(DataFormats.Html, htmlFormatData)
'クリップボードにコピーする
Clipboard.SetDataObject(dataObj)
C#
コードを隠すコードを選択
//using System.Windows.Forms;

//HTML形式でコピーするデータ
string htmlFormatString = "Version:0.9\r\n" +
    "StartHTML:00000097\r\n"+
    "EndHTML:00000187\r\n"+
    "StartFragment:00000131\r\n"+
    "EndFragment:00000153\r\n"+
    "<html><body>\r\n"+
    "<!--StartFragment--><b>こんにちは</b><!--EndFragment-->\r\n" +
    "</body></html>";
//UTF8のMemoryStreamを作成する
System.IO.MemoryStream htmlFormatData = new System.IO.MemoryStream(
    System.Text.Encoding.UTF8.GetBytes(htmlFormatString));
//DataObjectを作成し、データをセットする
DataObject dataObj = new DataObject();
dataObj.SetData(DataFormats.Html, htmlFormatData);
//クリップボードにコピーする
Clipboard.SetDataObject(dataObj);

HTML形式のデータを作成する簡単なメソッドを作ってみましたので、参考にしてください。

VB.NET
コードを隠すコードを選択
''' <summary>
''' HTML形式のデータを作成する。
''' </summary>
''' <param name="htmlFragment">HTML形式としてコピーする文字列。</param>
''' <returns>クリップボードに貼り付けるHTML形式のデータ。</returns>
Public Shared Function CreateHtmlClipboardFormat(htmlFragment As String) _
        As System.IO.MemoryStream
    'データの先頭に付けるDescription
    Const description As String = "Version:0.9" & vbCrLf & _
        "StartHTML:AAAAAAAAAA" & vbCrLf & _
        "EndHTML:BBBBBBBBBB" & vbCrLf & _
        "StartFragment:CCCCCCCCCC" & vbCrLf & _
        "EndFragment:DDDDDDDDDD" & vbCrLf
    'Contextの先頭と末尾
    Const htmlHeader As String = "<html><body>" & vbCrLf
    Const htmlFooter As String = vbCrLf & "</body></html>"
    'Fragmentを囲むコメント
    Const startFragmentComment As String = "<!--StartFragment-->"
    Const endFragmentComment As String = "<!--EndFragment-->"

    'StartHTML
    Dim startHtmlPos As Integer = description.Length
    'Fragmentのバイト長
    Dim fragmentLen As Integer = _
        System.Text.Encoding.UTF8.GetByteCount(htmlFragment)
    'StartFragment
    Dim startFragmentPos As Integer = _
        startHtmlPos + htmlHeader.Length + startFragmentComment.Length
    'EndFragment
    Dim endFragmentPos As Integer = startFragmentPos + fragmentLen
    'EndHTML
    Dim endHtmlPos As Integer = _
        endFragmentPos + endFragmentComment.Length + htmlFooter.Length

    'データを作成する
    Dim buf As New System.Text.StringBuilder()
    buf.Append(description)
    'Descriptionを書き換える
    buf.Replace("AAAAAAAAAA", startHtmlPos.ToString("D10"))
    buf.Replace("BBBBBBBBBB", endHtmlPos.ToString("D10"))
    buf.Replace("CCCCCCCCCC", startFragmentPos.ToString("D10"))
    buf.Replace("DDDDDDDDDD", endFragmentPos.ToString("D10"))
    buf.Append(htmlHeader)
    buf.Append(startFragmentComment)
    buf.Append(htmlFragment)
    buf.Append(endFragmentComment)
    buf.Append(htmlFooter)

    '文字列をUTF8でエンコードして、MemoryStreamにする
    Return New System.IO.MemoryStream( _
        System.Text.Encoding.UTF8.GetBytes(buf.ToString()))
End Function
C#
コードを隠すコードを選択
/// <summary>
/// HTML形式のデータを作成する。
/// </summary>
/// <param name="htmlFragment">HTML形式としてコピーする文字列。</param>
/// <returns>クリップボードに貼り付けるHTML形式のデータ。</returns>
public static System.IO.MemoryStream CreateHtmlClipboardFormat(
    string htmlFragment)
{
    //データの先頭に付けるDescription
    const string description = "Version:0.9\r\n" +
        "StartHTML:AAAAAAAAAA\r\n"+
        "EndHTML:BBBBBBBBBB\r\n"+
        "StartFragment:CCCCCCCCCC\r\n"+
        "EndFragment:DDDDDDDDDD\r\n";
    //Contextの先頭と末尾
    const string htmlHeader = "<html><body>\r\n";
    const string htmlFooter = "\r\n</body></html>";
    //Fragmentを囲むコメント
    const string startFragmentComment = "<!--StartFragment-->";
    const string endFragmentComment = "<!--EndFragment-->";

    //StartHTML
    int startHtmlPos = description.Length;
    //Fragmentのバイト長
    int fragmentLen = System.Text.Encoding.UTF8.GetByteCount(htmlFragment);
    //StartFragment
    int startFragmentPos =
        startHtmlPos + htmlHeader.Length + startFragmentComment.Length;
    //EndFragment
    int endFragmentPos = startFragmentPos + fragmentLen;
    //EndHTML
    int endHtmlPos =
        endFragmentPos + endFragmentComment.Length + htmlFooter.Length;

    //データを作成する
    System.Text.StringBuilder buf = new System.Text.StringBuilder();
    buf.Append(description);
    //Descriptionを書き換える
    buf.Replace("AAAAAAAAAA", startHtmlPos.ToString("D10"));
    buf.Replace("BBBBBBBBBB", endHtmlPos.ToString("D10"));
    buf.Replace("CCCCCCCCCC", startFragmentPos.ToString("D10"));
    buf.Replace("DDDDDDDDDD", endFragmentPos.ToString("D10"));
    buf.Append(htmlHeader);
    buf.Append(startFragmentComment);
    buf.Append(htmlFragment);
    buf.Append(endFragmentComment);
    buf.Append(htmlFooter);

    //文字列をUTF8でエンコードして、MemoryStreamにする
    return new System.IO.MemoryStream(
        System.Text.Encoding.UTF8.GetBytes(buf.ToString()));
}

HTML形式のデータをクリップボードから取得する

.NET Framework 4.0以下では、UTF8のHTML形式のデータをクリップボードから正しく取得することができません(文字コードがANSIならば、正しく取得できます)。.NET Framework 4.5でこの不具合が修正されました(MSDNの「DataObject.GetDataメソッド」に明記されています)。

.NET Framework 4.0以下で、この問題の解決法は、今のところありません。

以下に、HTML形式のデータをクリップボードから取得する例を示します。繰り返しになりますが、.NET Framework 4.0以下では、まず間違いなく文字化けします。

VB.NET
コードを隠すコードを選択
'Imports System.Windows.Forms

'クリップボードのデータを取得する
Dim data As IDataObject = Clipboard.GetDataObject()
'データがある時
If data IsNot Nothing Then
    'HTML形式のデータを文字列として取得する
    Dim str As String = DirectCast(data.GetData(DataFormats.Html), String)
    Console.WriteLine(str)
End If
C#
コードを隠すコードを選択
//using System.Windows.Forms;

//クリップボードのデータを取得する
IDataObject data = Clipboard.GetDataObject();
//データがある時
if (data != null)
{
    //HTML形式のデータを文字列として取得する
    string str = (string)data.GetData(DataFormats.Html);
    Console.WriteLine(str);
}

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。