Search code examples
.netclipboardoffice-interop

Excel 2003 Windows Forms Clipboard DataObject


I'm trying to get access to Excel 2003 Chart copied into the clipboard.

The chart image pastes fine into mspaint or wordpad.

The problem is that I don't see the chart's data on my System.Windows.Forms.Clipboard object.

I've read the following post:

Pasting Image from Excel 2003 Clipboard

and in my particular scenario the only time the PNG, JFIF, or GIF formats appear as formats on the clipboard DataObject is when I go to the Excel clipboard manager (in the Excel application) and re-copy the chart again while it's open.

That is, if I clear my clipboard, open Excel 2003, create a chart, right click it, hit Copy, then check Clipboard.GetDataObject().GetFormats(), all I see is:

Clipboard.GetDataObject().GetFormats()
{string[6]}
    [0]: "EnhancedMetafile"  // is null
    [1]: "Embed Source"  // is a MemoryStream of about 10KB which seems to be an OLE representation for the whole workbook
    [2]: "Object Descriptor" // a very short (10 bytes) MemoryStream
    [3]: "Link Source" // a very short (10 bytes) MemoryStream
    [4]: "Link Source Descriptor"  // a very short (10 bytes) MemoryStream
    [5]: "Link"  // null 

If I open the Excel Clipboard Manager under the Edit > Office Clipboard then copy the same chart, even though Clipboard.ContainsImage() returns false, I see:

Clipboard.GetDataObject().GetFormats()
{string[10]}
    [0]: "Office Drawing Shape Format"
    [1]: "MetaFilePict"
    [2]: "EnhancedMetafile"
    [3]: "PNG+Office Art"  // can read with Image.FromStream
    [4]: "JFIF+Office Art"  // can read with Image.FromStream
    [5]: "GIF+Office Art"  // can read with Image.FromStream
    [6]: "PNG" // can read with Image.FromStream
    [7]: "JFIF" // can read with Image.FromStream
    [8]: "GIF" // can read with Image.FromStream
    [9]: "ActiveClipBoard"

and can get at any one of the image formats there as a MemoryStream without any problems.

I need this to work without having to open the Excel Clipboard Manager. It works fine on 2007 and 2010 (which also includes a regular Bitmap format for my convenience so that Clipboard.ContainsImage() returns true)...

I've verified this behavior on multiple workstations.

I'm thinking next steps may be to get at the native System.Runtime.InteropServices.ComTypes.IDataObject or worse yet get a handle on the COM object for the running instance of Excel......but I'd rather not have to.

Thanks for any help...


Solution

  • Wow....well I hope this helps someone else....

    I had the random idea to try the WPF clipboard object (System.Windows.Clipboard) before resorting to going straight to OLE32.dll....

    Lo and behold...

    System.Windows.Clipboard.GetDataObject().GetFormats()
    {string[7]}
        [0]: "EnhancedMetafile"
        [1]: "System.Drawing.Imaging.Metafile"
        [2]: "Embed Source"
        [3]: "Object Descriptor"
        [4]: "Link Source"
        [5]: "Link Source Descriptor"
        [6]: "Link"
    

    sure enough:

    System.Windows.Clipboard.GetData(System.Windows.Clipboard.GetDataObject().GetFormats()[0])
        {System.Drawing.Imaging.Metafile}
    

    and so...

    ((Image)System.Windows.Clipboard.GetData(System.Windows.Clipboard.GetDataObject().GetFormats()[0])).Save("C:\\test1.jpg")
        base {System.Drawing.Image}: {System.Drawing.Imaging.Metafile}
    

    works like magic...

    I suspect going straight for the OLE32.dll would have worked too, since both Windows Forms and WPF's Clipboard APIs go there anyway...