Is it possible to get shape ids after copy command called?

Started by snay, January 18, 2024, 01:47:57 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

snay

Hello guys!

I'm coding a VSTO addin which provide a special paste feature. That is when user copied a shape and call these special paste command, it will loop through the page's shape to get related shapes to paste together.

To implement it, the first step is to get the id of the shape user copied. I've noticed that after copy, the DataObject in Clipboard many formats. Among them, I think "Visio 15.0 Shapes", "Visio 15.0 Text" might be related. However, without knowing the data structure, I couldn't cast the memorystream back to the origin structure which I thought might contains information about shape id.

I hack way I'm considering is to repurpose the copy command and save the id to the VSTO's runtime memory. But this might lead to unexpected situation when people are copy from other source which should not support this feature.

I've also notices when calling the built in paste special command, the promot window has a source text displayed. So i wonder if there's an apporach to get this source text?



Yacine

Interesting feature indeed.
But wouldn't it be easier to replicate the function by yourself, instead of trying to hack an internally hard wired function?
Yacine

snay

Finally I got the important hint from ChatGPT.
If you cast the DataObject with format Visio 15.0 Shapes from the clipboard to MemoryStream, then you can find the magic number 50-4B-03-04-14-00-06-00. The first 4 bytes 50-4B-03-04 indicates this DataObject is indeed a zip file, which is most likely a OpenXML zip package.

Here is a sample c# code for getting the first shape's id.
        var clipboardData = Clipboard.GetDataObject();
        if (clipboardData != null)
        {
            var format = "Visio 15.0 Shapes";
            if (clipboardData.GetDataPresent(format))
            {
                var memoryStream = (MemoryStream)clipboardData.GetData(format);
                memoryStream.Seek(0, SeekOrigin.Begin);

                int shapeID;
                using (var package = Package.Open(memoryStream, FileMode.Open, FileAccess.Read))
                {
                    var uri = new Uri("/visio/pages/page1.xml", UriKind.Relative);
                    var page1Part = package.GetPart(uri);

                    // Open the packagePart as a stream and then `
                    // open the stream in an XDocument object.
                    using var partStream = page1Part.GetStream();
                    var partXml = XDocument.Load(partStream);
                    XNamespace MainNs = @"http://schemas.microsoft.com/office/visio/2012/main";

                    shapeID = int.Parse(partXml.Root.Element(MainNs + "Shapes").Element(MainNs + "Shape").Attribute("ID").Value);
                }
            }
        }

Hope this will help you.

Nikolay

Please note that after paste, the IDs of the shapes will change.
I.e. the pasted shapes will have different IDs than the copied ones.

Browser ID: smf (possibly_robot)
Templates: 4: index (default), Display (default), GenericControls (default), GenericControls (default).
Sub templates: 6: init, html_above, body_above, main, body_below, html_below.
Language files: 4: index+Modifications.english (default), Post.english (default), Editor.english (default), Drafts.english (default).
Style sheets: 4: index.css, attachments.css, jquery.sceditor.css, responsive.css.
Hooks called: 199 (show)
Files included: 34 - 1306KB. (show)
Memory used: 1064KB.
Tokens: post-login.
Cache hits: 14: 0.00186s for 26,593 bytes (show)
Cache misses: 3: (show)
Queries used: 16.

[Show Queries]