简体   繁体   中英

How do I access programmatically the address of the copied selection from the clipboard

Here's what I want to achieve:

The user copies a cell (or a range), say A3, and - when she hits a button - I need to get access to the address of the cell (to create a link) programmatically.

Accessing the clipboard in text format is easy:

string clip;

if (Clipboard.ContainsText()) clip = Clipboard.GetText();

I also found that it is possible to access the clipboard in different formats, like this

var dataObj = Clipboard.GetDataObject();
var format = DataFormats.CommaSeparatedValue;

if (dataObj != null && dataObj.GetDataPresent(format))
{
    var csvData = dataObj.GetData(format);
    //...
}

but I couldn't for the life of me find which format contains the link and how to get it. (I cycled through all formats offered by Clipboard.GetDataObject().GetFormats(), but some returned inscrutable streams I couldn't make sense of.

Background info:

A. The Link must be there, because I can use "paste link" which creates an absolute reference

B. I'm using Excel 2010 and VS2010 - C# under Win7

C. The code runs in a custom task pane

Any help appreciated!


So,

and thanks for everybody who managed to read till this point. I finally figured it out. My solution is still awkward, as I can't get my head around the actual structure of the stream from the clipboard, but I find what I am looking for:

        protected override void WndProc(ref Message m)
        {
            const int WM_PASTE = 0x0302;
            var enc = new System.Text.UTF7Encoding();
            string buffer, rangeAddress;

            if (m.Msg == WM_PASTE)
            {
                if (Clipboard.ContainsText())
                {
                    string clip = Clipboard.GetText();
                    var dataObject = Clipboard.GetDataObject();
                    var mstream = (MemoryStream)dataObject.GetData("Link Source", true);
                    if(mstream == null) return;
                    var rdr = new System.IO.StreamReader(mstream, enc, true);
                    buffer = rdr.ReadToEnd();
                    buffer = StripWeirdChars(buffer);
                    int IndexExcl = buffer.IndexOf("!");
                    if (IndexExcl >= 0)
                    {
                        rangeAddress = buffer.Substring(IndexExcl + 1, buffer.Length - IndexExcl - 4);
                        // do whatever you want to do with it, e.g.:Globals.ThisAddIn.Application.ActiveCell.Value = rangeAddress;
                        return;
                    }
                }
            }
            base.WndProc(ref m);
        }
    }

The key here is obviously the particular format for the GetData: "Link Source".

Reading the resulting stream produces a string with a lot of weird characters, but also the name of the sheet and coordinates of the copied range. I strip the weird chars using a straightforward

        public static string StripWeirdChars(string source)
        {
            string res = "";
            foreach (char c in source) if ((int)c >= 32) res += c;
            return res;
        }

There still are some odd chars I can't make sense of, but the good news is that after the first exclamation mark you'll find the address of the range (with some trailing rubbish of fixed length). This works even when the range was copied from another worksheet and even if this worksheet has odd chars (like German umlauts) in its name.

There certainly is a much neater solution out there

Getting the Excel Range object from the Clipboard through the IStream interface

but the code I found there is not complete (the "obvious" parts are left out) and I couldn't get the thing to work due to my incompetence and missing experience with IStream to begin with.

Any help in using this to get a neat solution is appreciated, but I am content with what I have for the time being. Thanks, guys.

This is just the answer from @drdhk, since this was requested in one of the comments to show this was answered:

So,

and thanks for everybody who managed to read till this point. I finally figured it out. My solution is still awkward, as I can't get my head around the actual structure of the stream from the clipboard, but I find what I am looking for:

    protected override void WndProc(ref Message m)
    {
        const int WM_PASTE = 0x0302;
        var enc = new System.Text.UTF7Encoding();
        string buffer, rangeAddress;

        if (m.Msg == WM_PASTE)
        {
            if (Clipboard.ContainsText())
            {
                string clip = Clipboard.GetText();
                var dataObject = Clipboard.GetDataObject();
                var mstream = (MemoryStream)dataObject.GetData("Link Source", true);
                if(mstream == null) return;
                var rdr = new System.IO.StreamReader(mstream, enc, true);
                buffer = rdr.ReadToEnd();
                buffer = StripWeirdChars(buffer);
                int IndexExcl = buffer.IndexOf("!");
                if (IndexExcl >= 0)
                {
                    rangeAddress = buffer.Substring(IndexExcl + 1, buffer.Length - IndexExcl - 4);
                    // do whatever you want to do with it, e.g.:Globals.ThisAddIn.Application.ActiveCell.Value = rangeAddress;
                    return;
                }
            }
        }
        base.WndProc(ref m);
    }
}

The key here is obviously the particular format for the GetData: "Link Source".

Reading the resulting stream produces a string with a lot of weird characters, but also the name of the sheet and coordinates of the copied range. I strip the weird chars using a straightforward

    public static string StripWeirdChars(string source)
    {
        string res = "";
        foreach (char c in source) if ((int)c >= 32) res += c;
        return res;
    }

There still are some odd chars I can't make sense of, but the good news is that after the first exclamation mark you'll find the address of the range (with some trailing rubbish of fixed length). This works even when the range was copied from another worksheet and even if this worksheet has odd chars (like German umlauts) in its name.

There certainly is a much neater solution out there

Getting the Excel Range object from the Clipboard through the IStream interface: ( http://www.codeproject.com/Articles/149009/Getting-the-Excel-Range-object-from-the-Clipboard )

but the code I found there is not complete (the "obvious" parts are left out) and I couldn't get the thing to work due to my incompetence and missing experience with IStream to begin with.

Any help in using this to get a neat solution is appreciated, but I am content with what I have for the time being. Thanks, guys.

There is one limitation with your approach: The result is always a rectangular range. If you have copied, let's say A1:B2 and A4:B5 into the clipboard, your approach would return A1:B5 , which means that row 3 is included in the result range, where in fact, it was not part of the range in the clipboard. There are more clipboard data types that contain less weird characters, like ObjectLink or Link , but they come with the same limitation for non-rectangular ranges.

Non-rectangular ranges can be selected by pressing Ctrl while selecting ranges.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM