当它不应该返回空值时,Clipboard.GetData() 返回了null。

4

我正在将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 形式存储,我能够看到数据,但无法提取。我已经尽力想弄清楚问题的所在了,不知道是否有所遗漏?我看到了这个问题的参考链接,但它对我的帮助并不大。我希望有人能帮助我。

你试过使用Clipboard.ContainsImage()和Clipboard.GetImage()吗?或者尝试在Excel中使用其他格式。我还找到了这个MSDN回答-它看起来很像你的代码。也许它能帮到你。 - keenthinker
@pasty 是的。不幸的是它没有保存为图像。它们分别返回 false 和 null。 - Nick
4个回答

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

你是否在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();
    }
}

抱歉,这已经是半个十年前的事了。我不再能够访问这段代码了。 - Nick

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();
        }    

1
请考虑为您的答案添加解释。 - user585968
虽然这段代码片段可能解决了问题,但包括解释真的有助于提高您的帖子质量。请记住,您正在为未来的读者回答问题,而这些人可能不知道您的代码建议原因。 - Isma

0
问题在于您试图在复制数据的同一程序中粘贴数据。您需要有单独的处理程序。当您复制图像时,Excel将使用延迟渲染,并且必须处理呈现请求才能在请求时提供图像。同时,已注册为剪贴板查看器的其他应用程序也正在处理剪贴板更新。而您却坚持要立即获取图像服务,而不给系统喘息的机会。您需要将粘贴逻辑放入单独的程序中,以便它不在与复制相同的调用堆栈中。

为什么Clipboard.GetDataObject().GetDataPresent()的结果立即显示数据存在呢? - Nick
1
这就是延迟渲染的工作原理。如果你从Excel复制,它会显示大约25种不同的格式。即使你复制了10万个单元格,也是如此。想想看,其中大约三分之一是图片类型。延迟渲染是一个幻术,它使所有这些成为可能。否则,复制这些单元格将消耗CPU和RAM,直到RAM用尽,然后它将崩溃Excel,可能还会崩溃Windows(如果你编写了一个剪贴板监视器,强制粘贴每种格式,可以杀死Windows95)。 - Chris Thornton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接