{"id":100365,"date":"2018-11-30T07:00:00","date_gmt":"2018-11-30T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=100365"},"modified":"2019-03-13T00:14:51","modified_gmt":"2019-03-13T07:14:51","slug":"20181130-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20181130-00\/?p=100365","title":{"rendered":"Why does Clipboard.SetData put extra junk in the clipboard data? And how can I get it to stop?"},"content":{"rendered":"<p>One of the ways of putting data on the clipboard is with the <code>System.<code><\/code>Windows.<code><\/code>Forms.<code><\/code>Clipboard<\/code> object. There are methods for putting text on the clipboard in one of a few <a HREF=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.windows.textdataformat\">the standard text formats<\/a>. And if you use the <a HREF=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.clipboard.setdata(v=vs.110).aspx\"><code>Clipboard.<code><\/code>Set&shy;Data<\/code> method<\/a>, you can place data on the clipboard with a custom format name. But when you use <code>Clipboard.<code><\/code>Set&shy;Data<\/code> to put text on the clipboard, the actual raw data on the clipboard contains extra stuff. <\/p>\n<pre>\nClipboard.SetData(\"customText\", \"Hello, world!\");\n<\/pre>\n<p>The actual raw bytes on the clipboard are <\/p>\n<pre>\n96 A7 9E FD 13 3B 70 43 A6 79 56 10 6B B2 88 FB\n00 01 00 00 00 FF FF FF FF 01 00 00 00 00 00 00\n00 06 01 00 00 00 0D <u>48 65 6C 6C 6F 2C 20 77 6F\n72 6C 64 21<\/u> 0B\n<\/pre>\n<p>The underlined bytes are the ASCII string <tt>Hello, world!<\/tt>, but what&#8217;s the other junk? <\/p>\n<p>The <code>Clipboard.<code><\/code>Set&shy;Data<\/code> method must serve two masters. One master is the Windows clipboard. Custom formats on the Windows clipboard are just binary blobs of data with no externally-imposed format. Any format for the data is by mutual agreement of the two parties using that custom format. <\/p>\n<p>The other master is the CLR. If a C# program puts a serializable object on the clipboard, then it should be able to read it back as an object. <\/p>\n<p>The <code>Clipboard.<code><\/code>Set&shy;Data<\/code> method takes two parameters. The first, a string, is the custom clipboard format name. The second, an object, is the object to put on the clipboard. <\/p>\n<p>When putting an object on the clipboard, the CLR uses a <code>Binary&shy;Formatter<\/code> to <a HREF=\"https:\/\/referencesource.microsoft.com\/#System.Windows.Forms\/winforms\/Managed\/System\/WinForms\/DataObject.cs#97ce7cbce10929cb\">serialize the object to a binary blob<\/a>, and puts that binary blob on the clipboard. When reading an object from the clipboard, takes the binary blob from the clipboard and uses a <code>Binary&shy;Formatter<\/code> to <a HREF=\"https:\/\/referencesource.microsoft.com\/#System.Windows.Forms\/winforms\/Managed\/System\/WinForms\/DataObject.cs#e947b692ecde8c3b\">deserialize the object back into a CLR object<\/a>. <\/p>\n<p>Okay, so that keeps the second master happy. But what about the first master? Suppose the native clipboard has some arbitrary binary blob. How do we recognize that it is an arbitrary binary blob, rather than a serialized CLR object? Because if we try to deserialize it as a CLR object, we&#8217;ll get garbage. <\/p>\n<p>The answer is that the clipboard puts <a HREF=\"https:\/\/referencesource.microsoft.com\/#System.Windows.Forms\/winforms\/Managed\/System\/WinForms\/DataObject.cs#8c51bc95917bf024\">a secret signal<\/a> <a HREF=\"https:\/\/referencesource.microsoft.com\/#System.Windows.Forms\/winforms\/Managed\/System\/WinForms\/DataObject.cs#f13ace5762df124c\">at the start of the binary blob<\/a>. <a HREF=\"https:\/\/referencesource.microsoft.com\/#System.Windows.Forms\/winforms\/Managed\/System\/WinForms\/DataObject.cs#8788128edebb76a9\">If the secret signal is present<\/a>, then it assumes that the data represents a binary-formatted serialized CLR object. Otherwise, it assumes the data represents an arbitrary binary blob. <\/p>\n<p>When you read data from the clipboard, and it turns out to be an arbitrary binary blob, the <code>Clipboard.<code><\/code>Get&shy;Data<\/code> method returns a <code>Stream<\/code> containing the raw binary blob. <\/p>\n<p>Conversely, if you want to write a raw binary blob, you can <a HREF=\"https:\/\/referencesource.microsoft.com\/#System.Windows.Forms\/winforms\/Managed\/System\/WinForms\/DataObject.cs#aaeb640db20235c3\">pass a <code>Stream<\/code><\/a> to the the <code>Clipboard.<code><\/code>Set&shy;Data<\/code> method. <\/p>\n<p>Okay, so now with some help from <a HREF=\"https:\/\/msdn.microsoft.com\/en-us\/library\/cc236844.aspx\">[MS-NRBF]: .NET Remoting: Binary Format Data Structure<\/a>. we can parse the raw bytes: <\/p>\n<pre>\nmagic prefix:\n    96 A7 9E FD 13 3B 70 43 A6 79 56 10 6B B2 88 FB\n\nSerializationHeaderRecord\n    RecordTypeEnum: 00\n    RootId: 01 00 00 00\n    HeaderId: FF FF FF FF\n    MajorVersion: 01 00 00 00\n    MinorVersion: 00 00 00 00\n\nRecordTypeEnum: 06 (<a HREF=\"https:\/\/referencesource.microsoft.com\/#mscorlib\/system\/runtime\/serialization\/formatters\/binary\/binaryenums.cs#ed6b5341ded111db\">BinaryObjectString<\/a>)\nObjectId: 01 00 00 00\nLength: 0D\nUTF-8 data: 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21\n\nEnd of serialization: 0B\n<\/pre>\n<p>And to wrap things up, a table, because people like tables. <\/p>\n<table BORDER=\"1\" CLASS=\"cp3\" CELLPADDING=\"3\" CELLSPACING=\"0\" STYLE=\"border-collapse: collapse\">\n<tr>\n<th ROWSPAN=\"2\">Operation with<br>custom format<\/th>\n<th COLSPAN=\"2\">Format<\/th>\n<\/tr>\n<tr>\n<th>Raw binary data<\/th>\n<th>CLR binary serialized data<\/th>\n<\/tr>\n<tr>\n<td><code>SetData<\/code><\/td>\n<td>Pass <code>Stream<\/code><\/td>\n<td>Pass anything except <code>Stream<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>GetData<\/code><\/td>\n<td>Returns <code>Stream<\/code><\/td>\n<td>Returns anything except <code>Stream<\/code><\/td>\n<\/tr>\n<\/table>\n<p>That wraps up CLR week for this year. The good news is that you made it almost all the way to the end of the year before I inflicted it upon you. The bad news is that the new year is coming up soon, so the threat of another CLR week returns more quickly. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Strings and things, but you need the things.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-100365","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Strings and things, but you need the things.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100365","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=100365"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/100365\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=100365"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=100365"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=100365"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}