{"id":9613,"date":"2011-09-19T07:00:00","date_gmt":"2011-09-19T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/09\/19\/the-clipboard-viewer-linked-list-is-no-longer-the-responsibility-of-applications-to-maintain-unless-they-want-to\/"},"modified":"2011-09-19T07:00:00","modified_gmt":"2011-09-19T07:00:00","slug":"the-clipboard-viewer-linked-list-is-no-longer-the-responsibility-of-applications-to-maintain-unless-they-want-to","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110919-00\/?p=9613","title":{"rendered":"The clipboard viewer linked list is no longer the responsibility of applications to maintain, unless they want to"},"content":{"rendered":"<p>\nCommenter\nNice Clipboard Manager (with drop-&gt;clipboard)\nwonders\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2010\/05\/10\/10009448.aspx#10010459\">\nwhy Windows still uses a linked list to inform programs about\nclipboard modifications<\/a>.\nIf any clipboard viewer fails to maintain the chain,\nthen some windows won&#8217;t get informed of the change,\nand if a clipboard viewer creates a loop in the chain,\nan infinite loop results.\n<\/p>\n<p>\nWell, sure, that&#8217;s what happens if you use the old clipboard viewer\nchain.\nSo don&#8217;t use it.\nThe old clipboard viewer chain remains for backward compatibility,\nbut it&#8217;s hardly the best way to monitor the clipboard.\n(This is another example of people\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2009\/01\/16\/9322645.aspx#9330873\">\nasking for a feature that already exists<\/a>.)\n<\/p>\n<p>\nInstead of using the clipboard viewer chain, just add yourself\nas a clipboard format listener via\n<code>AddClipboardFormatListener<\/code>.\nOnce you&#8217;ve done that, the system will post you a\n<code>WM_CLIPBOARDUPDATE<\/code> message when the contents of the\nclipboard have changed, and you can respond accordingly.\nWhen you&#8217;re done,\ncall <code>RemoveClipboardFormatListener<\/code>.\n<\/p>\n<p>\nBy using the clipboard format listener model, you\nlet Windows worry\nabout keeping track of all the people who are monitoring the clipboard,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/07\/20\/10040074.aspx#10040587\">\nas Clipboarder Gadget suggested<\/a>.\n(Mind you, Windows doesn&#8217;t go so far as making each clipboard viewer\nthink that it&#8217;s the only viewer in the chain,\nbecause there may be applications which break the chain on purpose.\nChanging the chain behavior will break compatibility with those\napplications.)\n<\/p>\n<p>\nLet&#8217;s turn our\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/07\/23\/54576.aspx\">\nscratch program<\/a> into a clipboard format listener.\n<\/p>\n<pre>\nvoid\nSniffClipboardContents(HWND hwnd)\n{\n SetWindowText(hwnd, IsClipboardFormatAvailable(CF_TEXT)\n             ? TEXT(\"Has text\") : TEXT(\"No text\"));\n}\nBOOL\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\n{\n <font COLOR=\"blue\">SniffClipboardContents(hwnd); \/\/ set initial title\n return AddClipboardFormatListener(hwnd);<\/font>\n}\nvoid\nOnDestroy(HWND hwnd)\n{\n <font COLOR=\"blue\">RemoveClipboardFormatListener(hwnd);<\/font>\n PostQuitMessage(0);\n}\n... add to window procedure ...\n <font COLOR=\"blue\">case WM_CLIPBOARDUPDATE: SniffClipboardContents(hwnd); break;<\/font>\n<\/pre>\n<p>\nAnd that&#8217;s it.\nMuch, much simpler than writing a clipboard viewer,\nand much more robust since you aren&#8217;t dependent on other\napplications not screwing up.\n<\/p>\n<p>\nThere&#8217;s another alternative to registering a clipboard listener\nand that&#8217;s using the clipboard sequence number.\nThe window manager increments the clipboard sequence number\neach time the contents of the clipboard change.\nYou can compare the sequence number from two points in time to\ndetermine whether the contents of the clipboard have changed while\nyou weren&#8217;t looking.\n<\/p>\n<p>\nNow you have a choice.\nDo you use the notification method (clipboard format listener)\nor the polling method (clipboard sequence number)?\nThe notification method is recommended if you want\nto do something as soon as the clipboard contents change.\nOn the other hand, the polling method is more suitable if you\nperform calculations based on the clipboard contents and cache\nthe results, and then later you want to verify that your\ncached results are still valid.\n<\/p>\n<p>\nFor example, suppose you have a program with a Paste function,\nand pasting from the clipboard involves creating a complex\ndata structure based on the clipboard contents.\nThe user clicks Paste, you create your complex data structure,\nand insert it into the document.\nYour research discovers that a common operation is pasting the same\ncontents several times.\nTo optimize this, you want to cache the complex data structure\nso that if the user clicks Paste five times in a row,\nyou only have to build the complex data structure the first time\nand you can just re-use it the other four times.\n<\/p>\n<pre>\nvoid DocumentWindow::OnPaste()\n{\n if (m_CachedClipboardData == NULL ||\n     GetClipboardSequenceNumber() != m_SequenceNumberInCache) {\n  delete m_CachedClipboardData;\n  m_SequenceNumberInCache = GetClipboardSequenceNumber();\n  m_CachedClipboardData = CreateComplexDataFromClipboard();\n }\n if (m_CachedClipboardData) Paste(m_CachedClipboardData);\n}\n<\/pre>\n<p>\nWhen the <code>OnPaste<\/code> method is called,\nwe see if we have clipboard data cached from last time.\nIf not, then clearly we need to create our complex data\nstructure from the clipboard.\nIf we do have clipboard data in our cache,\nwe see if the clipboard sequence number has changed.\nIf so, then the cached data is no longer valid and we have\nto throw it away and create it from scratch.\nBut if we have cached data and the sequence number hasn&#8217;t changed,\nthen the cache is still valid and we can avoid calling\n<code>CreateComplexDataFromClipboard<\/code>.\n<\/p>\n<p>\nThe old clipboard viewer is like DDE:\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2007\/02\/26\/1763683.aspx\">\nplease feel free to stop using it<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Commenter Nice Clipboard Manager (with drop-&gt;clipboard) wonders why Windows still uses a linked list to inform programs about clipboard modifications. If any clipboard viewer fails to maintain the chain, then some windows won&#8217;t get informed of the change, and if a clipboard viewer creates a loop in the chain, an infinite loop results. Well, sure, [&hellip;]<\/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-9613","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Commenter Nice Clipboard Manager (with drop-&gt;clipboard) wonders why Windows still uses a linked list to inform programs about clipboard modifications. If any clipboard viewer fails to maintain the chain, then some windows won&#8217;t get informed of the change, and if a clipboard viewer creates a loop in the chain, an infinite loop results. Well, sure, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/9613","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=9613"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/9613\/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=9613"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=9613"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=9613"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}