2

I am using C# to add content into Windows Clipboard, for example:

System.Windows.Forms.Clipboard.SetData("Foo Format", "Hello World");

Since the data is a string, I was expecting it to simply paste the string data into the clipboard, but there were extra bits added at the beginning and at the end, i.e.:

00000000   96 A7 9E FD 13 3B 70 43 A6 79 56 10 6B B2 88 FB    –§žý.;pC¦yV.k²ˆû
00000010   00 01 00 00 00 FF FF FF FF 01 00 00 00 00 00 00    .....ÿÿÿÿ.......
00000020   00 06 01 00 00 00 0B 48 65 6C 6C 6F 20 57 6F 72    .......Hello Wor
00000030   6C 64 0B                                           ld.        

What does the first 39 and last bytes mean? Is there a way I can put a raw string into the Clipboard using C#?

kiewic
  • 15,852
  • 13
  • 78
  • 101
  • 1
    You said you wanted it to be pasted to the clipboard in "foo format", so that's probably where the problem lies. What is "foo format"? – Eric Lippert Aug 24 '18 at 23:15
  • You would not normally put a string onto the clipboard; you would put a DataObject containing a string onto the clipboard, which knows how to serialize and deserialize itself safely. Can you say why you want to put a raw string onto the clipboard? That seems incredibly dangerous. – Eric Lippert Aug 24 '18 at 23:18
  • If I use `System.Windows.Forms.DataObject` the result is the same. I want to use a custom format, that only a handful of applications understand. My question remains the same, what does the extra bits added by C# mean? Will there be always 39 bits before my content? – kiewic Aug 24 '18 at 23:20
  • Wait, you are *not* using one of the standard OLE clipboard formats? That is... not recommended. – Eric Lippert Aug 24 '18 at 23:25
  • @EricLippert That is correct, I am not using a standard clipboard format. The closest thing to a list of standard clipboard formats I found is this: https://learn.microsoft.com/en-us/windows/desktop/dataxchg/standard-clipboard-formats I can clearly see that many applications put their own formats into the clipboard, for example Excel, which puts *XML Spreadsheet*, *Link Source*, *Embed Source*, *Csv*, *Link*, *HTML Format*, *InShellDragLoop*, *JFIF*, etc. – kiewic Aug 24 '18 at 23:27
  • 1
    What are you displaying in your binary display? Using the Clipboard for standard formats like Text (with `SetText` and `GetText`) is easy - it just works. Using it with a custom format probably means your going to need to understand the Windows Clipboard, formats, how it works with COM, etc. The last time I used a custom format was in the 90s, and I think I used Brockschmidt's COM book to figure it out. I don't have happy memories of the `FORMATETC` struct and its friends – Flydog57 Aug 24 '18 at 23:29
  • My advice is: start using a standard format; your life will be much easier. If you are hell bent on writing a non-standard clipboard marshaller, you can do it, but you'll almost certainly have to do it yourself by writing to the windows APIs directly; I highly doubt that *WinForms* is going to help you do something so out of the mainstream. Clipboard formats have been standardized for decades. – Eric Lippert Aug 24 '18 at 23:30
  • If you want to see how DataObject writes to the standard OLE clipboard format, an old version of the code is here: https://referencesource.microsoft.com/#PresentationCore/Core/CSharp/system/windows/DataObject.cs – Eric Lippert Aug 24 '18 at 23:31
  • @Flydog57: I have no idea what happened to my copy of Brockschmidt, but yeah, that thing was indispensable for me back in the 1990s. "OLE Automation Programmer's Reference" by contrast was referred to by me and the OLEAut dev team, who had the offices next to me, as "the book of lies". :-) – Eric Lippert Aug 24 '18 at 23:35
  • Re: stuff Excel puts on the clipboard: By "standard OLE formats" I mean "Object Linking and Embedding" which was the technology invented in the 1990s to enable Excel to put complex objects on the clipboard and embedded in other Office file formats. I think we are speaking past each other here. OLE is the technology stack that justified the creation of COM and OLE Automation. Having a standard serialized format for copy-paste was one of its key value adds. – Eric Lippert Aug 24 '18 at 23:37
  • Thanks @EricLippert Looking at the source code, I couldn't find the code that serializes a string, but I saw that `MemoryStream` is the type that is used as the internal representation of the clipboard content, and I came up with the following line to serialize content into the clipboard without the extra bytes: `Clipboard.SetData("Foo Format", new MemoryStream(Encoding.UTF8.GetBytes("Hello world!")));` – kiewic Aug 25 '18 at 00:14
  • I am surprised that works! I would have thought that would put type information about the memory stream onto the clipboard. But, hey, if it works, go for it. – Eric Lippert Aug 25 '18 at 00:30
  • @EricLippert It's pretty standard. It's how a lot of modern apps [put images on the clipboard as PNG](https://stackoverflow.com/a/46424800/395685) to get around that pesky problem that the Windows clipboard doesn't support transparency. There's an extra parameter to make sure the data is _copied_ to the clipboard, though, which allows disposing the MemoryStream, and which ensures the data stays alive after closing your program. – Nyerguds Oct 11 '18 at 18:50
  • Incidentally, I believe MS Office (which is used in OP's answer example) actually started off the trend of putting png in the clipboard that way ;) – Nyerguds Oct 11 '18 at 19:04

1 Answers1

3

Using a System.IO.MemoryStream adds strings to the clipboard without the extra bytes at the beginning and at the end of string values.

For example, the following string represents a fragment of a Microsoft Excel Spreadsheet:

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        string content = @"<?xml version=""1.0""?>
<?mso-application progid=""Excel.Sheet""?>
<Workbook xmlns=""urn:schemas-microsoft-com:office:spreadsheet""
 xmlns:o=""urn:schemas-microsoft-com:office:office""
 xmlns:x=""urn:schemas-microsoft-com:office:excel""
 xmlns:ss=""urn:schemas-microsoft-com:office:spreadsheet""
 xmlns:html=""http://www.w3.org/TR/REC-html40"">
 <Styles>
  <Style ss:ID=""Default"" ss:Name=""Normal"">
   <Alignment ss:Vertical=""Bottom""/>
   <Borders/>
   <Font ss:FontName=""Calibri"" x:Family=""Swiss"" ss:Size=""11"" ss:Color=""#000000""/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
  <Style ss:ID=""s18"" ss:Name=""Currency"">
   <NumberFormat
    ss:Format=""_(&quot;$&quot;* #,##0.00_);_(&quot;$&quot;* \(#,##0.00\);_(&quot;$&quot;* &quot;-&quot;??_);_(@_)""/>
  </Style>
  <Style ss:ID=""s64"">
   <Font ss:FontName=""Calibri"" x:Family=""Swiss"" ss:Size=""11"" ss:Color=""#000000""
    ss:Bold=""1""/>
  </Style>
  <Style ss:ID=""s65"" ss:Parent=""s18"">
   <Font ss:FontName=""Calibri"" x:Family=""Swiss"" ss:Size=""11"" ss:Color=""#000000""/>
  </Style>
 </Styles>
 <Worksheet ss:Name=""Sheet1"">
  <Table ss:ExpandedColumnCount=""2"" ss:ExpandedRowCount=""2""
   ss:DefaultRowHeight=""15"">
   <Row>
    <Cell><Data ss:Type=""String"">Month</Data></Cell>
    <Cell><Data ss:Type=""String"">Year</Data></Cell>
   </Row>
   <Row>
    <Cell ss:StyleID=""s64""><Data ss:Type=""String"">August</Data></Cell>
    <Cell ss:StyleID=""s65""><Data ss:Type=""Number"">999.99</Data></Cell>
   </Row>
  </Table>
 </Worksheet>
</Workbook>";

Passing it to the Clipboard class as a string:

Clipboard.SetData("XML Spreadsheet", content);

Creates an incompatible format with Excel, and Excel shows the following error when trying to paste that content:

enter image description here

However, serializing it into bytes and then passing it as a MemoryStream:

Clipboard.SetData("XML Spreadsheet", new MemoryStream(Encoding.UTF8.GetBytes(content)));

Creates a clipboard content compatible with Excel:

enter image description here

kiewic
  • 15,852
  • 13
  • 78
  • 101