Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clipboard.GetData() returns null when it should not

Tags:

c#

.net

clipboard

I am copying cells from an excel document to the clipboard so they can be inserted as an image elsewhere. The cells get copied to the clipboard fine, as I can paste the image manually after the code is run. However I cannot get ahold of the data. Here is my code:

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

The data is stored as an EnhancedMetaFile and I can see the data in there but I cannot pull it out. I am at my wits end trying to figure this out. Does anybody see something I am missing?

I saw this question posted but it did not help me much. I'm hoping somebody can.

like image 426
Nick Avatar asked Oct 16 '25 04:10

Nick


2 Answers

I found a solution. The Clipboard.GetData(DataFormats.EnhancedMetafile) call seems to be broken. But I managed to get it working using P/Invoke.

It's not the prettiest code, but it works, so for posterity here it is in all it's glory:

[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;
}
like image 103
Nick Avatar answered Oct 17 '25 19:10

Nick


Did you run the code from an STA thread? For example:

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();
    }
}
like image 23
kiewic Avatar answered Oct 17 '25 19:10

kiewic



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!