Clipboard.GetData()在不应该返回null时返回null

时间:2013-11-08 21:28:14

标签: c# .net clipboard

我正在将excel文档中的单元格复制到剪贴板,以便将它们作为图像插入其他位置。单元格可以很好地复制到剪贴板,因为我可以在代码运行后手动粘贴图像。但是我无法获得数据。这是我的代码:

tempWorkSheet.Range[tempWorkSheet.Cells[1, 1], tempWorkSheet.Cells[3, 3]].CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlPicture);

// returns true
var test = Clipboard.GetDataObject().GetDataPresent(DataFormats.EnhancedMetafile);

// returns true
var test2 = Clipboard.ContainsData(DataFormats.EnhancedMetafile);

// returns null
var test3 = Clipboard.GetData(DataFormats.EnhancedMetafile);

// returns null
var test4 = Clipboard.GetDataObject().GetData(DataFormats.EnhancedMetafile);

数据存储为EnhancedMetaFile,我可以看到那里的数据,但我无法将其拉出来。我最终试图弄清楚这一点。有人看到我遗失的东西吗?

我发布了this个问题,但这对我没什么帮助。我希望有人可以。

4 个答案:

答案 0 :(得分:4)

我找到了解决方案。 Clipboard.GetData(DataFormats.EnhancedMetafile)电话似乎被打破了。但我设法使用P / Invoke工作。

这不是最漂亮的代码,但是它有效,所以对于后代来说,这是它的全部荣耀:

[DllImport("user32.dll", SetLastError = true)]
static extern bool OpenClipboard(IntPtr hWndNewOwner);

[DllImport("user32.dll")]
static extern IntPtr GetClipboardData(uint uFormat);

[DllImport("user32.dll", SetLastError = true)]
static extern bool CloseClipboard();

[DllImport("user32.dll")]
static extern bool EmptyClipboard();

[DllImport("gdi32.dll")]
static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, string lpszFile);

[DllImport("gdi32.dll")]
static extern bool DeleteEnhMetaFile(IntPtr hemf);

public Image GetMetaImageFromClipboard()
{
    OpenClipboard(IntPtr.Zero);

    IntPtr pointer = GetClipboardData(14);

    string fileName = @"C:\Test\" + Guid.NewGuid().ToString() + ".emf";

    IntPtr handle = CopyEnhMetaFile(pointer, fileName);

    Image image;
    using (Metafile metafile = new Metafile(fileName))
    {
        image = new Bitmap(metafile.Width, metafile.Height);
        Graphics g = Graphics.FromImage(image);

        EmptyClipboard();
        CloseClipboard();

        g.DrawImage(metafile, 0, 0, image.Width, image.Height);
    }

    DeleteEnhMetaFile(handle);
    File.Delete(fileName);
    return image;
}

答案 1 :(得分:0)

问题是您尝试将数据粘贴到复制它的同一例程中。你需要有单独的处理程序。复制图像时Excel将使用Delayed Rendering,并且必须处理渲染请求,以便在请求时实际提供图像。同时,已注册为剪贴板查看器的其他应用程序也在处理剪贴板更新。在这里,你坚持立即为图像服务,而不给系统一个呼吸的机会。您需要将粘贴逻辑放入一个单独的例程中,以使它与复制不在同一个调用堆栈中。

答案 2 :(得分:0)

我使用此代码:

tempWorkSheet.Range[tempWorkSheet.Cells[1, 1], tempWorkSheet.Cells[3, 3]].CopyPicture(Excel.XlPictureAppearance.xlScreen, Excel.XlCopyPictureFormat.xlBitmap);

var data = System.Windows.Forms.Clipboard.GetDataObject();

using (var ms = data.GetData(System.Windows.Forms.DataFormats.Dib) as MemoryStream)
        {
            byte[] buff = new byte[ms.Capacity];
            if (ms.CanRead)
            {
                ms.Read(buff, 0, ms.Capacity);
            }
            MemoryStream ms2 = new MemoryStream();

            byte[] bmpHeader = new byte[] { 0x42, 0x4D, 0x96, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00 };

            ms2.Write(bmpHeader, 0, bmpHeader.Length);
            ms2.Write(buff, 0, buff.Length);   

            string local_filename = "E:\TEST.png";

            File.WriteAllBytes(local_filename, ms2.ToArray());
            ms2.Dispose();
        }    

答案 3 :(得分:0)

您是否从STA线程运行代码?例如:

class Program
{
    static void Main(string[] args)
    {
        RunInSta(() =>
        {
            var dataObject = Clipboard.GetDataObject();
            foreach (string format in dataObject.GetFormats())
            {
                Console.WriteLine(format);
            }
        });
    }

    internal static void RunInSta(Action action)
    {
        Thread thread = new Thread(() => action());
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        thread.Join();
    }
}