我正在将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个问题,但这对我没什么帮助。我希望有人可以。
答案 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();
}
}