2

我正在将 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,我可以在其中看到数据,但我无法将其拉出。我束手无策,试图弄清楚这一点。有人看到我缺少的东西吗?

我看到了这个问题,但它对我没有多大帮助。我希望有人可以。

4

4 回答 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;
}
于 2013-11-14T15:03:56.890 回答
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();
    }
}
于 2018-08-14T19:01:09.700 回答
0

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

于 2013-11-11T18:07:24.527 回答
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();
        }    
于 2018-03-22T08:41:43.277 回答