C# 使用C将Excel图表表复制到剪贴板#

C# 使用C将Excel图表表复制到剪贴板#,c#,excel,charts,com,C#,Excel,Charts,Com,我正在写一个C#应用程序 其中一项任务是打开一个Excel电子表格,并将其中的一张图表粘贴到C#app中。请注意,我指的是图表表…不是嵌入普通工作表中的图表对象 我之所以在这里力求精确是有原因的 我使用普通的COM从C#到Excel进行通信 using using Microsoft.Office.Interop.Excel; 在普通工作表中嵌入图表的情况下,API可以工作。我从工作簿中检索工作表,从工作表中获取chartObject,并按预期在chartObject上发布副本,即剪贴板的

我正在写一个C#应用程序

其中一项任务是打开一个Excel电子表格,并将其中的一张图表粘贴到C#app中。请注意,我指的是图表表…不是嵌入普通工作表中的图表对象

我之所以在这里力求精确是有原因的

我使用普通的COM从C#到Excel进行通信

using using Microsoft.Office.Interop.Excel;  
在普通工作表中嵌入图表的情况下,API可以工作。我从工作簿中检索工作表,从工作表中获取chartObject,并按预期在chartObject上发布副本,即剪贴板的内容就像是从Excel本身启动副本一样

处理图表时,情况就不同了。我从工作簿中获取图表,然后获取我感兴趣的图表实例。一切都好。但是,在此处对图表发出Copy()不会导致剪贴板看起来与从Excel启动操作时的样子类似。CopyPicture也帮不上忙,因为pic真的被放大了,剪贴板缺少了常用的PNG、GIFF、JPEG格式-剪贴板。当我看到图像在剪贴板中时,getImage()返回null。Copy()只在剪贴板上创建预览、数据对象和OLE私有数据格式,而不是更多

//this does not work - it is for chart sheets
Excel.Charts charts = wb.Charts;
Excel.Chart chart = charts["mychartname"];
chart.Copy(); or chart.CopyPicture();    <-- these do not work as expected...


// this works fine but only covers embedded charts
Excel.ChartObjects charts = ws.ChartObjects;
Excel.ChartObject chart = charts["mychartname"];
chart.Copy();
//这不起作用-它用于图表工作表
Excel.Charts=wb.Charts;
Excel.Chart Chart=图表[“mychartname”];

chart.Copy();或chart.CopyPicture() 经过一些尝试和错误,我找到了一个简单和非常可接受的解决方案

不要对图表实例调用Copy(),而是从图表中获取ChartArea并对其调用Copy

Excel.Charts charts = wb.Charts;
Excel.Chart chart = charts["mychartname"];
Excel.ChartArea chartArea = chart.ChartArea;
chartArea.Copy();

记住COM发布所有中间COM对象:)

在现实生活中,跟踪所有要发布的中间COM对象是非常困难的,甚至是不可能的,丢失一个会给您带来麻烦

这就是为什么Microsoft似乎建议在确定对任何COM对象的所有引用都超出范围后,只传递垃圾收集器:

// Instead of calling releaseComObject on every single COM object we use, we call the GC when they are all out of scope as suggested in
// https://msdn.microsoft.com/en-us/library/aa679807(v=office.11).aspx#officeinteroperabilitych2_part2_usingrco
GC.Collect();
GC.WaitForPendingFinalizers();
// https://web.archive.org/web/20150907193302/https://code.msdn.microsoft.com/office/VBAutomateExcel-b6ecaff3
// GC needs to be called twice in order to get the Finalizers called the first time in, it simply makes a list of what is to be  
// finalized, the second time in, it actually is finalizing. Only then will the object do its automatic ReleaseComObject. 
GC.Collect();
GC.WaitForPendingFinalizers();
参考资料: