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

Microsoft Officeでコピーした図をPictureBoxに表示する
クリップボードのメタファイルを取得する

Microsoft Office Word、Excel、Power Pointなどで作成した図をクリップボードにコピーした時、このデータを拡張メタファイル形式として以下のような方法でデータを取得しようとしてもうまくいきません。

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

Dim data As IDataObject = Clipboard.GetDataObject()
'クリップボードにデータがあるか調べる
If Not data Is Nothing Then
    '拡張メタファイル形式でデータを取得する
    PictureBox1.Image = DirectCast(data.GetData(DataFormats.EnhancedMetafile), Image)
End If
C#
コードを隠すコードを選択
//using System.Drawing;
//using System.Windows.Forms;

IDataObject data = Clipboard.GetDataObject();
//クリップボードにデータがあるか調べる
if (data != null)
{
    //拡張メタファイル形式でデータを取得する
    PictureBox1.Image = (Image)data.GetData(DataFormats.EnhancedMetafile);
}

.NET Frameworkの機能だけでは残念ながらクリップボードのメタファイルデータは取得できません(.NET Framework 1.1現在)。

しかし、Microsoft Officeからクリップボードにコピーされたデータは、EnhancedMetafile形式の他に様々な形式に関連付けられており、それらの形式で取得することはできます。

Microsoft Office 2007以降であれば、Bitmap形式で取得できますので、「クリップボードの画像を表示する」で紹介している方法で可能です。

Microsoft Office 2003以前ではこの方法は無理です。例えばOffice 2003のクリップボードのデータは、Office Drawing Shape Format、MetaFilePict、PNG+Office Art、JFIF+Office Art、GIF+Office Art、PNG、JFIF、GIF、ActiveClipboard、HTML Format形式に関連付けられています。このうち、HTML Format以外はMemoryStreamオブジェクトとしてデータを取得できますので、Microsoft Officeでコピーした図を、PNG形式等でデータを取得することが可能です。

次のサンプルでは、フォームにピクチャボックス"PictureBox1"があり、このPictureBox1にクリップボードにコピーされた図を表示しています。

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

Dim data As IDataObject = Clipboard.GetDataObject()
'クリップボードにデータがあるか調べる
If data IsNot Nothing Then
    'PNG形式でデータをMemoryStreamとして取得する
    Dim ms As System.IO.MemoryStream = _
        DirectCast(data.GetData("PNG"), System.IO.MemoryStream)
    If Not ms Is Nothing Then
        'Imageオブジェクトに変換する
        PictureBox1.Image = Image.FromStream(ms)
    End If
End If
C#
コードを隠すコードを選択
//using System.Drawing;
//using System.Windows.Forms;

IDataObject data = Clipboard.GetDataObject();
//クリップボードにデータがあるか調べる
if (data != null)
{
    //PNG形式でデータをMemoryStreamとして取得する
    System.IO.MemoryStream ms = (System.IO.MemoryStream)data.GetData("PNG");
    if (ms != null)
    {
        //Imageオブジェクトに変換する
        PictureBox1.Image = Image.FromStream(ms);
    }
}

"PNG"以外の形式を試してみたところ、上記のコードで"PNG"の部分を以下の文字列に変更した場合にのみ成功するようです。

"PNG+Office Art"
"JFIF+Office Art"
"GIF+Office Art"
"JFIF"
"GIF"

クリップボードのメタファイルを取得する

クリップボードのメタファイルデータをメタファイルとして取得するには、Win32 APIを使うしかないようです(.NET Framework 1.1現在)。この方法は、「Windows Forms FAQ - 37.5 How can I programmatically create a bitmap?」で紹介されています。

以下にWin32 APIを使用してクリップボードのメタファイルデータを取得するコードを紹介します。

VB.NET
コードを隠すコードを選択
'Imports System.Runtime.InteropServices

Const CF_ENHMETAFILE As Integer = 14

<DllImport("user32.dll")> _
Private Shared Function OpenClipboard( _
    ByVal hWndNewOwner As IntPtr) As Boolean
End Function
<DllImport("user32.dll")> _
Private Shared Function IsClipboardFormatAvailable( _
    ByVal wFormat As Integer) As Integer
End Function
<DllImport("user32.dll")> _
Private Shared Function GetClipboardData( _
    ByVal wFormat As Integer) As IntPtr
End Function
<DllImport("user32.dll")> _
Private Shared Function CloseClipboard() As Integer
End Function

''' <summary>
''' クリップボードのメタファイル形式のデータを取得する
''' </summary>
''' <param name="hWnd">ウィンドウのハンドル</param>
''' <returns>取得したデータ</returns>
Public Shared Function GetEnhMetafileOnClipboard( _
    ByVal hWnd As IntPtr) As System.Drawing.Imaging.Metafile
    Dim meta As System.Drawing.Imaging.Metafile = Nothing
    If OpenClipboard(hWnd) Then
        Try
            If IsClipboardFormatAvailable(CF_ENHMETAFILE) <> 0 Then
                Dim hmeta As IntPtr = GetClipboardData(CF_ENHMETAFILE)
                meta = New System.Drawing.Imaging.Metafile(hmeta, True)
            End If
        Finally
            CloseClipboard()
        End Try
    End If

    Return meta
End Function
C#
コードを隠すコードを選択
//using System.Runtime.InteropServices;

private const int CF_ENHMETAFILE = 14;

[DllImport("user32.dll")]
private static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll")]
private static extern int IsClipboardFormatAvailable(int wFormat);
[DllImport("user32.dll")]
private static extern IntPtr GetClipboardData(int wFormat);
[DllImport("user32.dll")]
private static extern int CloseClipboard();

/// <summary>
/// クリップボードのメタファイル形式のデータを取得する
/// </summary>
/// <param name="hWnd">ウィンドウのハンドル</param>
/// <returns>取得したデータ</returns>
public static System.Drawing.Imaging.Metafile
    GetEnhMetafileOnClipboard(IntPtr hWnd)
{
    System.Drawing.Imaging.Metafile meta = null;
    if (OpenClipboard(hWnd))
    {
        try
        {
            if (IsClipboardFormatAvailable(CF_ENHMETAFILE) != 0)
            {
                IntPtr hmeta = GetClipboardData(CF_ENHMETAFILE);
                meta = new System.Drawing.Imaging.Metafile(hmeta, true);
            }
        }
        finally
        {
            CloseClipboard();
        }
    }

    return meta;
}

このGetEnhMetafileOnClipboardメソッドを使うには、C#では

PictureBox1.Image = GetEnhMetafileOnClipboard(this.Handle);

VB.NETでは

PictureBox1.Image = GetEnhMetafileOnClipboard(Me.Handle)

のようにします。

  • 履歴:
  • 2010/3/29 Microsoft Office 2007に関する情報を追加など。

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

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