<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>The Great Flying Tortoise : Property System</title><link>http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx</link><description>Tags: Property System</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Code for Previous Blog Posts</title><link>http://blogs.msdn.com/benkaras/archive/2007/01/09/code-for-previous-blog-posts.aspx</link><pubDate>Wed, 10 Jan 2007 08:55:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1442530</guid><dc:creator>benkaras</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/1442530.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=1442530</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=1442530</wfw:comment><description>&lt;P&gt;Someone asked if I had a copy of the code I've been using in my blog so far.&amp;nbsp; Well, I didn't as of 5pm today, so I&amp;nbsp;went back and collected the code into 3 projects:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;propreader.exe &amp;lt;file&amp;gt;&lt;BR&gt;&amp;nbsp;- &lt;A href="http://blogs.msdn.com/benkaras/archive/2006/10/12/Property-coding-expedition-_2300_7-_2D00_-The-final-output.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/12/Property-coding-expedition-_2300_7-_2D00_-The-final-output.aspx"&gt;Prints a list of all properties we know about the file&lt;/A&gt;&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;propwriter.exe &amp;lt;file&amp;gt; &amp;lt;property&amp;gt; &amp;lt;value&amp;gt;&lt;BR&gt;&amp;nbsp;- &lt;A href="http://blogs.msdn.com/benkaras/archive/2006/10/16/writing-a-property-1.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/16/writing-a-property-1.aspx"&gt;Writes a single value&lt;/A&gt;&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;proplister.exe &amp;lt;file&amp;gt; &amp;lt;proplist&amp;gt;&lt;BR&gt;&amp;nbsp;- &lt;A href="http://blogs.msdn.com/benkaras/archive/2006/11/07/writing-properties-5-property-lists.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/11/07/writing-properties-5-property-lists.aspx"&gt;Prints all the properties included in a proplist&lt;/A&gt; (e.g. System.PropList.PreviewDetails)&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/attachment/1442530.ashx" mce_href="http://blogs.msdn.com/benkaras/attachment/1442530.ashx"&gt;I've attached the code here (code.zip)&lt;/A&gt;.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Enjoy!&lt;/P&gt;
&lt;P&gt;-Ben Karas&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1442530" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/benkaras/attachment/1442530.ashx" length="12482" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/writing+properties/default.aspx">writing properties</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/reading+properties/default.aspx">reading properties</category></item><item><title>Choosing your property API</title><link>http://blogs.msdn.com/benkaras/archive/2007/01/05/choosing-your-property-api.aspx</link><pubDate>Fri, 05 Jan 2007 23:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1388350</guid><dc:creator>benkaras</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/1388350.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=1388350</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=1388350</wfw:comment><description>&lt;P&gt;&lt;FONT face=georgia,palatino&gt;It is time that I talk a little about what to do if you want your application to run on XP.&amp;nbsp; There are three sets of APIs, each with subtle differences and caveats, and ultimately your choice requires deciding what platform your application must run on:&lt;/FONT&gt;&lt;/P&gt;&lt;FONT face=georgia,palatino&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;&lt;STRONG&gt;Windows Vista:&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Call &lt;A class="" href="http://msdn2.microsoft.com/en-us/library/ms632794.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms632794.aspx"&gt;&lt;FONT face="courier new,courier"&gt;IShellItem2&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face="courier new,courier"&gt;::&lt;/FONT&gt;&lt;A class="" href="http://msdn2.microsoft.com/en-us/library/ms632784.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms632784.aspx"&gt;&lt;FONT face="courier new,courier"&gt;GetPropertyStore&lt;/FONT&gt;&lt;/A&gt; to get an &lt;A class="" href="http://msdn2.microsoft.com/en-us/library/ms633762.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms633762.aspx"&gt;&lt;FONT face="courier new,courier"&gt;IPropertyStore&lt;/FONT&gt;&lt;/A&gt; interface.&amp;nbsp;&amp;nbsp; The output property store includes property handler properties (e.g. Photo dimensions) and i&lt;/FONT&gt;&lt;FONT face=Georgia&gt;nnate properties (e.g. Size, Name).&amp;nbsp; This is your one-stop-shop for properties.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Caveat: This technique only works on Vista and later OSes.&amp;nbsp;&amp;nbsp;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;&lt;STRONG&gt;Windows XP with Windows Desktop Search 3.x:&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;You can pass an &lt;A class="" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/IShellItem/IShellItem.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/IShellItem/IShellItem.asp"&gt;&lt;FONT face="courier new,courier"&gt;IShellItem&lt;/FONT&gt;&lt;/A&gt;&amp;nbsp;interface to &lt;/FONT&gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetitempropertyhandler.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetitempropertyhandler.asp"&gt;&lt;FONT face="courier new,courier"&gt;PSGetItemPropertyHandler&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt;&amp;nbsp;to get an &lt;FONT face="courier new,courier"&gt;&lt;A class="" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/ipropertystore.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/ipropertystore.asp"&gt;IPropertyStore&lt;/A&gt;&lt;/FONT&gt; interface.&amp;nbsp; Much of the property system works with Windows Desktop Search 3.x, so you can ask for property descriptions and everything.&amp;nbsp; One upshot is that this API works identically on Vista so if you are able to choose to use it, you don't have to detect versions or anything.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Georgia&gt;Unfortunately, innate properties are only available through methods on &lt;FONT face="Courier New"&gt;IShellFolder&lt;/FONT&gt; and &lt;FONT face="courier new,courier"&gt;IShellFolder2&lt;/FONT&gt;.&amp;nbsp; So you're on your own for those.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Caveat: Properties written to this API may or may not readable on Vista. [Aside: The full story is more complicated, but I'd like to move on for now]&amp;nbsp; Innate properties like &lt;FONT face="courier new,courier"&gt;PKEY_Size &lt;/FONT&gt;&lt;FONT face=georgia,palatino&gt;are not exposed&lt;/FONT&gt;.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Windows XP; Windows XP with Windows Desktop Search 2.x:&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Properties on XP are exposed through &lt;A class="" href="http://msdn2.microsoft.com/en-gb/library/aa379840.aspx" mce_href="http://msdn2.microsoft.com/en-gb/library/aa379840.aspx"&gt;&lt;FONT face="courier new,courier"&gt;IPropertySetStorage&lt;/FONT&gt;&lt;/A&gt;.&amp;nbsp; The supported technique is to call &lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/ishellfolder.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/ishellfolder.asp"&gt;&lt;FONT face="courier new,courier"&gt;IShellFolder&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face="courier new,courier"&gt;::&lt;/FONT&gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/bindtostorage.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellfolder/bindtostorage.asp"&gt;&lt;FONT face="courier new,courier"&gt;BindToStorage&lt;/FONT&gt;&lt;/A&gt;&lt;/FONT&gt;&lt;FONT face="courier new,courier"&gt;(&lt;/FONT&gt;&lt;A class="" href="http://msdn2.microsoft.com/en-gb/library/aa379840.aspx" mce_href="http://msdn2.microsoft.com/en-gb/library/aa379840.aspx"&gt;&lt;FONT face="courier new,courier"&gt;IPropertySetStorage&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt;&lt;FONT face="courier new,courier"&gt;)&lt;/FONT&gt; for the item.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Georgia&gt;Innate properties such as size and name are exposed through various methods on &lt;FONT face="courier new,courier"&gt;IShellFolder&lt;/FONT&gt; and &lt;FONT face="courier new,courier"&gt;IShellFolder2&lt;/FONT&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Caveats: Properties written with this API may or may not be readable on Vista.&amp;nbsp; Furthermore, on Vista, this technique only works for some namespaces and not others.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Georgia&gt;Gotcha:&amp;nbsp; Many people mistakenly call &lt;A class="" href="http://msdn2.microsoft.com/en-us/library/aa380342.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa380342.aspx"&gt;&lt;FONT face="courier new,courier"&gt;StgOpenStorageEx&lt;/FONT&gt;&lt;/A&gt;.&amp;nbsp; Don't do that!&amp;nbsp; &lt;FONT face="courier new,courier"&gt;StgOpenStorageEx&lt;/FONT&gt; is &lt;EM&gt;only&lt;/EM&gt; supported for specific formats like&amp;nbsp;OLE Compound Documents or NTFS secondary stream storage.&amp;nbsp; &lt;FONT face="courier new,courier"&gt;StgOpenStorageEx&lt;/FONT&gt; doesn't know how to read the EXIF header from a .JPG image.&amp;nbsp; &lt;FONT face="courier new,courier"&gt;IShellFolder::BindToStorage&lt;/FONT&gt; knows how to do such things. &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;&lt;STRONG&gt;Best of&amp;nbsp;all worlds:&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;If you really enjoy coding, you can detect if&amp;nbsp;a given API is present&amp;nbsp;by calling GetProcAddress or QueryInterface [Aside: please don't detect versions... just&amp;nbsp;directly test if the API is present or not], select the best available&amp;nbsp;API,&amp;nbsp;and deliver an application that works better on Vista.&amp;nbsp; &lt;SPAN lang=EN style="FONT-FAMILY: 'Georgia','serif'; mso-ansi-language: EN"&gt;Hey, "Works better on Vista" sounds like a marketing slogan --&amp;nbsp;you could have fun coding and sell more software too!&lt;/SPAN&gt;&lt;SPAN lang=EN style="mso-ansi-language: EN"&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;-Ben Karas&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1388350" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category></item><item><title>Writing properties #9 - Summary</title><link>http://blogs.msdn.com/benkaras/archive/2006/11/21/writing-properties-9-summary.aspx</link><pubDate>Tue, 21 Nov 2006 23:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1113128</guid><dc:creator>benkaras</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/1113128.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=1113128</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=1113128</wfw:comment><description>&lt;P&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl06_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/10/02/Coding-to-the-Windows-SDK.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Coding to the Windows SDK&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt;&amp;nbsp;&lt;BR&gt;&lt;/FONT&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl13_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/10/12/Property-coding-expedition-_2300_7-_2D00_-The-final-output.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Reading&amp;nbsp;properties&amp;nbsp;#7 - Summary&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl11_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/10/16/writing-a-property-1.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Writing properties #1 - Simple beginnings&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl10_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/10/17/writing-properties-2-filetype-support.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Writing properties #2 - Filetype support?&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl09_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/10/19/writing-properties-3-which-properties-are-writable.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Writing properties #3 - Which properties are writable?&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl07_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/11/06/writing-properties-4-which-properties-are-writeable.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Writing properties #4 - Which properties are writable?&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl06_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/11/07/writing-properties-5-property-lists.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Writing properties #5 - Property lists&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl04_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/11/09/writing-properties-6-gps-readwrite-omits-read-only-data-sources.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Writing properties #6 - GPS_READWRITE omits read-only data sources&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl02_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/11/14/the-deal-with-ipropertystorecapabilities.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;The deal with IPropertyStoreCapabilities&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl01_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/11/15/writing-properties-7-canonical-values.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Writing properties #8 - Canonical Values&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;BR&gt;&lt;/FONT&gt;&lt;A id=bp___v___r___postlist___EntryItems_ctl12_PostTitle href="http://blogs.msdn.com/benkaras/archive/2006/10/13/gotcha-you-must-release-property-stores-quickly.aspx"&gt;&lt;FONT face=georgia,palatino color=#0000cc&gt;Gotcha: You must release property stores quickly&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;----&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Writing properties is very simple at the core: you just call SetValue() and then Commit().&amp;nbsp; But then there are a bunch of details surrounding this task that make it a little more complicated.&amp;nbsp; To close this topic, I want to give one more tip:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;The best way to determine if the file/filesystem/filetype itself is writable is to simply call IShellItem2::GetPropertyStore(GPS_READWRITE).&amp;nbsp; This performs the necessary ACL checks, attribute checks, etc.&amp;nbsp;&amp;nbsp;The only downside is that the return value is non-actionable.&amp;nbsp; If you want to display a more specifical error message or offer corrective options, you'll have to program those yourself.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Thus, a property editing user interface will typically do the following:&lt;/FONT&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Test writability by opening the file with GPS_READWRITE and then release that interface&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Reopen the file with GPS_DEFAULT&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Use a property list to populate the UI&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Test writability using IPropertyDescription::GetTypeFlags&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Test writability using IPropertyStoreCapabilities::IsPropertyWritable&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Release the read-only property store&lt;/FONT&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Then to save changes, it...&lt;/FONT&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Opens the file with GPS_READWRITE&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Calls IPropertyStore::SetValue for each change&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Calls IPropertyStore::Commit to save the changes&lt;/FONT&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;Releases the read-write store&lt;/FONT&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;-Ben Karas&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;ps. There is an even simpler way to write properties using IFileOperation. I'll have to revisit that another time.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1113128" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/writing+properties/default.aspx">writing properties</category></item><item><title>Writing properties #8 - Canonical Values</title><link>http://blogs.msdn.com/benkaras/archive/2006/11/15/writing-properties-7-canonical-values.aspx</link><pubDate>Wed, 15 Nov 2006 23:38:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1082543</guid><dc:creator>benkaras</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/1082543.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=1082543</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=1082543</wfw:comment><description>&lt;P&gt;There's one last topic I want to touch on before I close this series:&amp;nbsp; Canonical values.&amp;nbsp; So far I've talked about how to determine when the property itself is writable.&amp;nbsp; But once you decide to write a property, how do you figure out what type the value should be?&amp;nbsp; What if you get it wrong?&lt;/P&gt;
&lt;P&gt;The first edition of the property system didn't enforce the type of values.&amp;nbsp; As a result, some people used VT_UI4, others VT_I2, and some just used strings for the same property.&amp;nbsp; This led to complicated error-prone code.&amp;nbsp; So we decided to add an enforcement layer that makes sure the value complies with the type specified by the property description and performs some minor cleanup when possible.&amp;nbsp; We dubbed this &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/09/05/740476.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/09/05/740476.aspx"&gt;the "coercion" layer&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;To cut to the chase, this layer uses &lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/isvaluecanonical.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/isvaluecanonical.asp"&gt;IPropertyDescription::IsCanonicalValue&lt;/A&gt; and &lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/coercetocanonicalvalue.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/coercetocanonicalvalue.asp"&gt;IPropertyDescription::CoerceToCanonicalValue&lt;/A&gt; to enforce the type requirements.&amp;nbsp; So if you are creating a program that writes properties, you might want to add some debug code to see if your values pass the test and to see how they get interpreted by the coercion layer.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Here's a&amp;nbsp;quick&amp;nbsp;summary of what happens in IPropertyDescription::CoerceToCanonicalValue:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Convert "empty" values to VT_EMPTY.&amp;nbsp; This includes VT_NULL, null pointers, and strings with just spaces.&lt;/LI&gt;
&lt;LI&gt;Convert the value to the type given by &lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/getpropertytype.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/getpropertytype.asp"&gt;IPropertyDescription::GetPropertyType&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;Convert the result to a canonical form (remove leading/trailing spaces, removing duplicates from vectors, etc)&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;MSDN will eventually get&amp;nbsp;expanded documentation on this function, but you should be able to figure out what's happening through experimentation too.&lt;/P&gt;
&lt;P&gt;As a final note, a property handler can decide it doesn't like a value and either reject or truncate it.&amp;nbsp; Unfortunately, it won't tell you why -- it just returns and error or &lt;A class="" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/coercetocanonicalvalue.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/coercetocanonicalvalue.asp"&gt;INPLACE_S_TRUNCATED&lt;/A&gt; to indicate when this happened.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;-Ben Karas&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1082543" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/writing+properties/default.aspx">writing properties</category></item><item><title>The deal with IPropertyStoreCapabilities</title><link>http://blogs.msdn.com/benkaras/archive/2006/11/14/the-deal-with-ipropertystorecapabilities.aspx</link><pubDate>Tue, 14 Nov 2006 22:47:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1077083</guid><dc:creator>benkaras</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/1077083.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=1077083</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=1077083</wfw:comment><description>&lt;P&gt;Have you ever felt this before?&amp;nbsp; It's the day after &lt;A class="" href="http://www.microsoft.com/presspass/features/2006/nov06/11-08VistaRTM.mspx" mce_href="http://www.microsoft.com/presspass/features/2006/nov06/11-08VistaRTM.mspx"&gt;you send your product to manufacturing&lt;/A&gt;.&amp;nbsp; You step back, look at the big picture, and start to see minor flaws.&amp;nbsp; A dread sinks in when you realize you &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/11/10/writing-properties-7-ipropertystorecapabilities-doesn-t-like-gps-readwrite.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/11/10/writing-properties-7-ipropertystorecapabilities-doesn-t-like-gps-readwrite.aspx"&gt;just blogged about it&lt;/A&gt; too!&amp;nbsp; That was Monday morning.&amp;nbsp; :-)&amp;nbsp; The good news is that our analysis shows that the flaws are minor.&amp;nbsp; They are unlikely to affect people in real practice, don't affect the code we wrote, and there are workarounds if you're trying something complicated.&amp;nbsp; So... here's the whirlwind tour of &lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystorecapabilities/ipropertystorecapabilities.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystorecapabilities/ipropertystorecapabilities.asp"&gt;IPropertyStoreCapabilities&lt;/A&gt; (IPSC):&lt;/P&gt;
&lt;P&gt;We needed a way to mark which properties are writable and which aren't.&amp;nbsp; We looked at a few models and decided we wanted a runtime check for writability.&amp;nbsp; So we invented IPSC to let a property handler declare what properties it supports and those it doesn't.&amp;nbsp; For example, the PNG property handler uses IPSC to tell explorer that it supports writing System.Photo.DateTaken, but nothing else.&lt;/P&gt;
&lt;P&gt;Enter the &lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/pscreatemultiplexpropertystore.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/pscreatemultiplexpropertystore.asp"&gt;multiplex property store&lt;/A&gt;.&amp;nbsp; This is a building block object we wrote to help shell namespaces and property handlers to build their property stores.&amp;nbsp; Like the name suggests, it selects from various inputs.&amp;nbsp; From the start, we found this object hard to design and work with.&amp;nbsp; We had to figure out reasonable ways to select &lt;EM&gt;which&lt;/EM&gt; input to select.&amp;nbsp; We had to decide how to handle writing.&amp;nbsp; How to handle IPSC.&amp;nbsp; To keep things simple, we decided&amp;nbsp;to&amp;nbsp;&lt;EM&gt;not&lt;/EM&gt; have an interface to let the MUX know which store handles what property.&amp;nbsp; Instead...&amp;nbsp;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;The MUX is read-only (i.e. IPropertyStore::SetValue returns STG_E_ACCESSDENIED).&lt;/LI&gt;
&lt;LI&gt;IPropertyStore::GetValue would select the &lt;EM&gt;first&lt;/EM&gt; value it finds.&lt;/LI&gt;
&lt;LI&gt;&lt;A class="" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystorecapabilities/ispropertywritable.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystorecapabilities/ispropertywritable.asp"&gt;IPSC::IsPropertyWritable&lt;/A&gt; queries the &lt;EM&gt;first&lt;/EM&gt; store that implements this interface.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;#1 means the store returned by &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/11/09/writing-properties-6-gps-readwrite-omits-read-only-data-sources.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/11/09/writing-properties-6-gps-readwrite-omits-read-only-data-sources.aspx"&gt;GPS_READWRITE cannot use the MUX&lt;/A&gt;.&amp;nbsp; This means if you use IPSC on a GPS_READWRITE store, you don't get the full picture since we're ignoring the read-only data sources.&lt;/P&gt;
&lt;P&gt;#2 is interesting, but doesn't affect us much today.&lt;/P&gt;
&lt;P&gt;#3 is what made me panic yesterday.&amp;nbsp; Imagine if two stores implemented IPSC and were joined by a MUX.&amp;nbsp; The calling application would only be able to query the first store!&amp;nbsp; So here are the mitigating circumstances:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;The filesystem shell namespace extension uses MUX's, but the only implementation of IPropertyStoreCapabilities is the property handler.&amp;nbsp; So this is OK.&lt;/LI&gt;
&lt;LI&gt;None of the filetype property handlers that ship with Windows Vista use MUX's internally.&amp;nbsp; So this is OK.&lt;/LI&gt;
&lt;LI&gt;All other places in Windows Vista that would get in trouble from this are read-only to begin with.&amp;nbsp; So this is OK.&lt;/LI&gt;
&lt;LI&gt;The only time you'd need&amp;nbsp;two stores to implement IPSC is if&amp;nbsp;the filetype is writable and&amp;nbsp;&lt;EM&gt;both&lt;/EM&gt; stores deal with &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/19/writing-properties-3-which-properties-are-writable.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/19/writing-properties-3-which-properties-are-writable.aspx"&gt;non-innate&lt;/A&gt; properties (because this is in the only time you need to&amp;nbsp;provide the distinction).&amp;nbsp; This is&amp;nbsp;less common than other scenarios.&lt;/LI&gt;
&lt;LI&gt;Even if a namespace extension (or property handler) needs to have two stores implement IPSC, they could work around this by having the read-only implementation delegate to the read-write implementation.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;So in the end, I&amp;nbsp;am going&amp;nbsp;back to my original recommendation: Use IPropertyStoreCapabilities with GPS_DEFAULT.&amp;nbsp; This is what explorer does, the shipping proprety stores&amp;nbsp;are fine, and other hopefully other developers&amp;nbsp;will find and understand my blog.&lt;/P&gt;
&lt;P&gt;-Ben&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1077083" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/writing+properties/default.aspx">writing properties</category></item><item><title>Writing properties #7 - IPropertyStoreCapabilities requires GPS_READWRITE</title><link>http://blogs.msdn.com/benkaras/archive/2006/11/10/writing-properties-7-ipropertystorecapabilities-doesn-t-like-gps-readwrite.aspx</link><pubDate>Fri, 10 Nov 2006 23:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1053194</guid><dc:creator>benkaras</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/1053194.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=1053194</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=1053194</wfw:comment><description>&lt;P class=MsoNormal style="MARGIN: 5pt 0in; mso-pagination: none; mso-layout-grid-align: none"&gt;&lt;SPAN style="COLOR: blue"&gt;&lt;FONT color=#000000&gt;&lt;FONT face=georgia,palatino&gt;[Edit: 2006/11/13 - My original post got this topic entirely backwards.&amp;nbsp; I've fixed the title and will provide details about this tomorrow.&amp;nbsp;]&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 5pt 0in; mso-pagination: none; mso-layout-grid-align: none"&gt;&lt;SPAN style="COLOR: blue"&gt;&lt;FONT color=#000000&gt;&lt;FONT face=georgia,palatino&gt;-Ben Karas&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Arial"&gt;&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;FONT face=georgia,palatino color=#000000&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1053194" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/writing+properties/default.aspx">writing properties</category></item><item><title>Writing properties #6 - GPS_READWRITE omits read-only data sources</title><link>http://blogs.msdn.com/benkaras/archive/2006/11/09/writing-properties-6-gps-readwrite-omits-read-only-data-sources.aspx</link><pubDate>Thu, 09 Nov 2006 23:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1042922</guid><dc:creator>benkaras</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/1042922.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=1042922</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=1042922</wfw:comment><description>&lt;P&gt;&lt;FONT face=georgia,palatino&gt;You'll recall that there are &lt;/FONT&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/09/05/740476.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/09/05/740476.aspx"&gt;&lt;FONT face=georgia,palatino&gt;multiple layers in the property system&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt;.&amp;nbsp; In particular, the GPS_DEFAULT property system stack for files in the filesystem namespace looks like this:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;[ Application using GPS_DEFAULT ]&lt;BR&gt;[ Coercion Layer ]&lt;BR&gt;[ Shell Item Layer ]*&lt;BR&gt;[ File System Namespace ]*&lt;BR&gt;[ Property Handler ]*&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;I've starred the layers that provide properties.&amp;nbsp; The thing to notice is that there are multiple sources of properties when you use GPS_DEFAULT.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;The non-obvious datum is that&amp;nbsp;GPS_READWRITE contains only&amp;nbsp;a portion of this stack.&amp;nbsp; Notice how the application is talking to just the property handler:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;[ Application using GPS_READWRITE ]&lt;BR&gt;[ Coercion Layer ]&lt;BR&gt;[ Property Handler ]*&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;The repurcussion for applications is that they cannot see data provided by the other data sources when using GPS_READWRITE.&amp;nbsp;&amp;nbsp;They cannot read all the properties like they could using GPS_DEFAULT.&amp;nbsp;So if you are building a details pane like the one in explorer, you'll have to read properties using GPS_DEFAULT, close the store, and then use GPS_READWRITE for writing.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;The propsys.idl file concisely mentions this tidbit:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;GPS_READWRITE = 0x00000002, &lt;FONT color=#008000&gt;// Writable stores will only include handler properties&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;/FONT&gt;&lt;/FONT&gt;
&lt;P mce_keep="true"&gt;&lt;FONT face=georgia,palatino&gt;-Ben Karas&lt;/FONT&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;FONT face=georgia,palatino&gt;p.s. propsys.idl contains a lot of comments that apparently got stripped out from propsys.h.&amp;nbsp; &lt;EM&gt;Ouch&lt;/EM&gt;.&amp;nbsp; I highly suggest peeking at the IDL files to see if some developer posted a comment there for the&amp;nbsp;interface or structure you are using.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1042922" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/writing+properties/default.aspx">writing properties</category></item><item><title>Writing properties #5 - Property lists</title><link>http://blogs.msdn.com/benkaras/archive/2006/11/07/writing-properties-5-property-lists.aspx</link><pubDate>Tue, 07 Nov 2006 23:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1012508</guid><dc:creator>benkaras</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/1012508.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=1012508</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=1012508</wfw:comment><description>&lt;P&gt;&lt;FONT face=georgia,palatino&gt;So if a property handler &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/11/06/writing-properties-4-which-properties-are-writeable.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/11/06/writing-properties-4-which-properties-are-writeable.aspx"&gt;doesn't enumerate which properties it supports writing&lt;/A&gt;, then how does the explorer pick which properties to show?&amp;nbsp; Well, the shell namespace extension containing the item specifies the list of properties it wants to show in a particular piece of UI.&amp;nbsp; To query this property list, call &lt;/FONT&gt;&lt;A class="" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/getvalue.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/getvalue.asp"&gt;&lt;FONT face="courier new,courier"&gt;IPropertyStore::GetValue&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt;&lt;FONT face="courier new,courier"&gt;(PKEY_PropList_XXX)&lt;/FONT&gt; on the read-only property store.&amp;nbsp; The shell namespace extension returns a property list similar to &lt;FONT face="courier new,courier"&gt;L"prop:System.Title;System.Size;System.Keywords"&lt;/FONT&gt; in a &lt;FONT face="courier new,courier"&gt;VT_LPWSTR&lt;/FONT&gt; propvariant.&amp;nbsp; There are prefixes for each property name which I won't mention yet.&amp;nbsp; For now, just know that you can let the system parse this string by calling &lt;/FONT&gt;&lt;A class="" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertydescriptionlistfromstring.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertydescriptionlistfromstring.asp"&gt;&lt;FONT face="courier new,courier"&gt;PSGetPropertyDescriptionListFromString&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Let's try this out.&amp;nbsp; I am going to modify parts from past programs to write a quick loop through the property list on my goat picture.&amp;nbsp; First, I modified my wmain function to let me specify the &lt;FONT face="courier new,courier"&gt;PKEY_PropList_XXX&lt;/FONT&gt; from the command line using its canonical name:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;int &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/03/Properties-coding-expedition-_2300_1-_2D00_-Binding-to-an-item.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/03/Properties-coding-expedition-_2300_1-_2D00_-Binding-to-an-item.aspx"&gt;wmain&lt;/A&gt;(int argc, WCHAR **argv)
...
                    PCWSTR pszList = argv[2];
                    PROPERTYKEY keyList;
                    hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetPropertyKeyFromName+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertykeyfromname.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetPropertyKeyFromName+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertykeyfromname.asp"&gt;PSGetPropertyKeyFromName&lt;/A&gt;(pszList, &amp;amp;keyList);
                    if (SUCCEEDED(hr))
                    {
                        hr = _PrintPropertyStore(keyList, pps);
                    }&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;You've seen that kind of stuff before.&amp;nbsp; Next, _&lt;FONT face="courier new,courier"&gt;PrintPropertyStore&lt;/FONT&gt; is rewritten to obtain the list and loop over it:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;HRESULT _PrintPropertyStore(__in REFPROPERTYKEY keyList, __in IPropertyStore *pps)
{
    // Get the property list ...
    PROPVARIANT propvarList = {0};
    HRESULT hr = pps-&amp;gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyStore%3a%3aGetValue+Method&amp;amp;url=https://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/getvalue.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyStore%3a%3aGetValue+Method&amp;amp;url=https://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/getvalue.asp"&gt;GetValue&lt;/A&gt;(keyList, &amp;amp;propvarList);
    if (SUCCEEDED(hr))
    {
        // ... in string form
        PCWSTR pszList = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PropVariantToStringWithDefault+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/propvarconversionfunctions/propvarianttostringwithdefault.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PropVariantToStringWithDefault+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/propvarconversionfunctions/propvarianttostringwithdefault.asp"&gt;PropVariantToStringWithDefault&lt;/A&gt;(propvarList, NULL);
        if (pszList)
        {
            // parse the property list string to get an interface
            IPropertyDescriptionList *plist;
            hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetPropertyDescriptionListFromString+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertydescriptionlistfromstring.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetPropertyDescriptionListFromString+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertydescriptionlistfromstring.asp"&gt;PSGetPropertyDescriptionListFromString&lt;/A&gt;(pszList, IID_PPV_ARGS(&amp;amp;plist));
            if (SUCCEEDED(hr))
            {
                // loop through the entries ...
                UINT cProps;
                hr = plist-&amp;gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyDescriptionList%3a%3aGetCount+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescriptionlist/getcount.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyDescriptionList%3a%3aGetCount+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescriptionlist/getcount.asp"&gt;GetCount&lt;/A&gt;(&amp;amp;cProps);
                for (UINT i = 0; SUCCEEDED(hr) &amp;amp;&amp;amp; i &amp;lt; cProps; i++)
                {
                    IPropertyDescription *ppropdesc;
                    hr = plist-&amp;gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyDescriptionList%3a%3aGetAt+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescriptionlist/getat.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyDescriptionList%3a%3aGetAt+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescriptionlist/getat.asp"&gt;GetAt&lt;/A&gt;(i, IID_PPV_ARGS(&amp;amp;ppropdesc));
                    if (SUCCEEDED(hr))
                    {
                        // ... getting values ...
                        PROPVARIANT propvar = {0};
                        hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetPropertyValue+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertyvalue.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetPropertyValue+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertyvalue.asp"&gt;PSGetPropertyValue&lt;/A&gt;(pps, ppropdesc, &amp;amp;propvar);
                        if (SUCCEEDED(hr))
                        {
                            PROPERTYKEY key;
                            hr = ppropdesc-&amp;gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyDescription%3a%3aGetPropertyKey+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/getpropertykey.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyDescription%3a%3aGetPropertyKey+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/getpropertykey.asp"&gt;GetPropertyKey&lt;/A&gt;(&amp;amp;key);
                            if (SUCCEEDED(hr))
                            {
                                // ... checking if it is writable ...
                                if (&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/19/writing-properties-3-which-properties-are-writable.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/19/writing-properties-3-which-properties-are-writable.aspx"&gt;_IsPropertyValueWritable&lt;/A&gt;(pps, key))
                                {
                                    wprintf(L"WRITABLE: ");
                                }
                                // ... and printing the value
                                hr = &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/11/Properties-coding-expedition-_2300_6-_2D00_-Developer-friendly-output.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/11/Properties-coding-expedition-_2300_6-_2D00_-Developer-friendly-output.aspx"&gt;_PrintPropertyValue&lt;/A&gt;(key, propvar);
                            }
                            PropVariantClear(&amp;amp;propvar);
                        }
                        ppropdesc-&amp;gt;Release();
                    }
                }
                plist-&amp;gt;Release();
            }
        }
        PropVariantClear(&amp;amp;propvarList);
    }
    return hr;
}&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;This code is pretty straight forward.&amp;nbsp; I get the list in string form, convert it to an interface, and then loop through its entries.&amp;nbsp; Since the list enumerates IPropertyDescription interfaces, I snuck a call in to PSGetPropertyValue which wraps a call to IPropertyStore::GetValue for me.&amp;nbsp; Next, I grab the property key so to pass to _IsPropertyValueWritable() and _PrintPropertyValue().&amp;nbsp; I thought about modifying these to take an IPropertyDescriptionList, but this seemed simpler.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Anyway, this program shows a more complete picture about what values are present and writable on my test goat:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;&amp;gt; propshow4.exe scan0010.jpg System.PropList.PreviewDetails
System.PropList.PreviewDetails properties for 'scan0010.jpg'
WRITABLE: System.Photo.DateTaken: VT_FILETIME: 2006/07/30:00:33:34.000 --&amp;gt; 7/29/2006 4:33 PM
WRITABLE: System.Keywords: VT_VECTOR|VT_LPWSTR == Sol Duc Valley; Wildlife
WRITABLE: System.Rating: VT_UI4: 99 --&amp;gt; 5 Stars
System.Image.Dimensions: VT_LPWSTR == 1139 x 769
System.Size: VT_UI8: 653729 --&amp;gt; 638 KB
WRITABLE: System.Title: VT_LPWSTR == Mountain goat
WRITABLE: System.Author: VT_VECTOR|VT_LPWSTR == Ben Karas
WRITABLE: System.Comment: VT_EMPTY ==
System.OfflineAvailability: VT_EMPTY ==
System.OfflineStatus: VT_EMPTY ==
WRITABLE: System.Photo.CameraManufacturer: VT_LPWSTR == HP
WRITABLE: System.Photo.CameraModel: VT_LPWSTR == HP Scanjet 4370
WRITABLE: System.Subject: VT_EMPTY ==
System.Photo.FNumber: VT_EMPTY ==
System.Photo.ExposureTime: VT_EMPTY ==
WRITABLE: System.Photo.ISOSpeed: VT_EMPTY ==
...[snip]...&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;&lt;FONT face="courier new,courier"&gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=System.PropList.PreviewDetails+&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_proplist_previewdetails.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=System.PropList.PreviewDetails+&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_proplist_previewdetails.asp"&gt;System.PropList.PreviewDetails&lt;/A&gt;&lt;/FONT&gt; (&lt;FONT face="courier new,courier"&gt;PKEY_PropList_PreviewDetails&lt;/FONT&gt;) property list controls which properties appear in the details pane of explorer so it's a nice start to listing out the useful writable properties on an item.&amp;nbsp; As you can see, there is a mixture of read-only and editable properties. That's pretty common for property lists. They are UI oriented and not the easiest to work with. But if you have the right building blocks you can figure out what to do.&lt;/FONT&gt; 
&lt;P align=center&gt;&lt;FONT face=georgia,palatino&gt;&lt;IMG title="Details Pane" style="WIDTH: 649px; HEIGHT: 100px" height=100 alt="Details Pane" hspace=5 src="http://blogs.msdn.com/photos/benkaras/images/1012483/original.aspx" width=649 vspace=5 mce_src="http://blogs.msdn.com/photos/benkaras/images/1012483/original.aspx"&gt;&lt;BR&gt;The details pane from explorer.&amp;nbsp; Notice how the properties are ordered the same as my output.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;The other important property lists are:&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;&lt;FONT face="courier new,courier"&gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=System.PropList.PreviewTitle+&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_proplist_previewtitle.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=System.PropList.PreviewTitle+&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_proplist_previewtitle.asp"&gt;System.PropList.PreviewTitle&lt;/A&gt;&lt;/FONT&gt; - The 2 properties used as a title in the details pane&lt;/FONT&gt; 
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;&lt;FONT face="courier new,courier"&gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=System.PropList.FullDetails+&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_proplist_fulldetails.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=System.PropList.FullDetails+&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_proplist_fulldetails.asp"&gt;System.PropList.FullDetails&lt;/A&gt;&lt;/FONT&gt; - The list of properties found in the details dialog &lt;/FONT&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;&lt;FONT face="courier new,courier"&gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=System.PropList.InfoTip+&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_proplist_infotip.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=System.PropList.InfoTip+&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_proplist_infotip.asp"&gt;System.PropList.InfoTip&lt;/A&gt;&lt;/FONT&gt; - The list of properties found in the infotip of the item &lt;/FONT&gt;
&lt;LI&gt;&lt;FONT face=georgia,palatino&gt;See &lt;FONT face="courier new,courier"&gt;propkey.h&lt;/FONT&gt; for less common property lists&lt;/FONT&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Ok, this was much much longer than I intended.&amp;nbsp; I'll talk about how to register property lists another&amp;nbsp;day.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;-Ben Karas&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1012508" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/writing+properties/default.aspx">writing properties</category></item><item><title>Writing properties #4 - Which properties are writeable?</title><link>http://blogs.msdn.com/benkaras/archive/2006/11/06/writing-properties-4-which-properties-are-writeable.aspx</link><pubDate>Mon, 06 Nov 2006 23:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:992016</guid><dc:creator>benkaras</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/992016.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=992016</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=992016</wfw:comment><description>&lt;P&gt;&lt;FONT face=georgia,palatino&gt;I'm going to make a first stab at printing out a list of properties that are writable for a given file.&amp;nbsp; I'll spoil the fun and let you know that my attempt today will not fully succeed.&amp;nbsp; I'll explain later.&amp;nbsp; For now, let's see some code!&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;You'll recall I wrote a &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/12/Property-coding-expedition-_2300_7-_2D00_-The-final-output.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/12/Property-coding-expedition-_2300_7-_2D00_-The-final-output.aspx"&gt;program to loop through the properties in a file and dump them out&lt;/A&gt;.&amp;nbsp; I am going to simply modify that program to only print out those properties that pass my &lt;FONT face="courier new,courier"&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/19/writing-properties-3-which-properties-are-writable.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/19/writing-properties-3-which-properties-are-writable.aspx"&gt;_IsPropertyValueWritable()&lt;/A&gt;&lt;/FONT&gt; test from last time.&amp;nbsp; Here's the new function for printing a property store:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;HRESULT _PrintPropertyStore(IPropertyStore *pps)
{
    DWORD cProps;
    HRESULT hr = pps-&amp;gt;GetCount(&amp;amp;cProps);
    for (DWORD i = 0; SUCCEEDED(hr) &amp;amp;&amp;amp; i &amp;lt; cProps; i++)
    {
        PROPERTYKEY key;
        hr = pps-&amp;gt;GetAt(i, &amp;amp;key);
        if (SUCCEEDED(hr))
        {
            if (_IsPropertyValueWritable(pps, key))
            {
                PROPVARIANT propvar = {0};
                hr = pps-&amp;gt;GetValue(key, &amp;amp;propvar);
                if (SUCCEEDED(hr))
                {
                    hr = _PrintPropertyValue(key, propvar);
                    PropVariantClear(&amp;amp;propvar);
                }
            }
        }
    }
    return hr;
}&lt;/FONT&gt;
&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Now let's run this on my favorite goat picture:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;Writeable Properties for 'scan0010.jpg'
System.Photo.Saturation: VT_UI4: 0 --&amp;gt; Normal
System.Photo.EXIFVersion: VT_LPWSTR == 0220
System.Rating: VT_UI4: 99 --&amp;gt; 5 Stars
System.Photo.DateTaken: VT_FILETIME: 2006/07/30:00:33:34.000 --&amp;gt; 7/29/2006 4:33 PM
System.Photo.CameraManufacturer: VT_LPWSTR == HP
System.Photo.CameraModel: VT_LPWSTR == HP Scanjet 4370
System.Photo.Sharpness: VT_UI4: 0 --&amp;gt; Normal
System.Title: VT_LPWSTR == Mountain goat
System.Author: VT_VECTOR|VT_LPWSTR == Ben Karas
System.Keywords: VT_VECTOR|VT_LPWSTR == Sol Duc Valley; Wildlife&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;What, that's it?&amp;nbsp; Just&amp;nbsp;ten (10)&amp;nbsp;properties are writable to JPGs?&amp;nbsp; Why, the properties&amp;nbsp;details dialog shows more than that!&amp;nbsp; Obviously something is missing.&amp;nbsp; I'll get into that next time.&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=992016" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/writing+properties/default.aspx">writing properties</category></item><item><title>Writing properties #1 - Simple beginnings</title><link>http://blogs.msdn.com/benkaras/archive/2006/10/16/writing-a-property-1.aspx</link><pubDate>Mon, 16 Oct 2006 22:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:824459</guid><dc:creator>benkaras</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/824459.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=824459</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=824459</wfw:comment><description>&lt;P&gt;&lt;FONT face=georgia,palatino&gt;I'm going to be talking about writable properties over the next few days.&amp;nbsp; I know that some of you are itching to try this out yourselves, so here is an overly simplistic program that will write a single property to a file.&amp;nbsp; I have omitted a lot of diagnostic code, so this will not work for all files, all strings, or all properties.&amp;nbsp; I plan to go through those details another day.&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;int wmain(__in int argc, __in_ecount(argc+1) WCHAR **argv)
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (SUCCEEDED(hr))
    {
        if (argc &amp;lt; 3)
        {
            wprintf(L"Usage: %s &amp;lt;filename&amp;gt; &amp;lt;property&amp;gt; &amp;lt;value&amp;gt;\n", argv[0]);
        }
        else
        {
            PCWSTR pszFile = argv[1];
            PCWSTR pszProperty = argv[2];
            PCWSTR pszValue = argv[3];

            PROPERTYKEY key;
            hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetPropertyKeyFromName+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertykeyfromname.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetPropertyKeyFromName+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetpropertykeyfromname.asp"&gt;PSGetPropertyKeyFromName&lt;/A&gt;(pszProperty, &amp;amp;key);
            if (SUCCEEDED(hr))
            {
                IShellItem2 *psi;
                hr = _GetShellItemFromRelativePath(pszFile, IID_PPV_ARGS(&amp;amp;psi));
                if (SUCCEEDED(hr))
                {
                    IPropertyStore *pps;
                    hr = psi-&amp;gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IShellItem2%3a%3aGetPropertyStore+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellitem2/getpropertystore.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IShellItem2%3a%3aGetPropertyStore+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellitem2/getpropertystore.asp"&gt;GetPropertyStore&lt;/A&gt;(GPS_READWRITE, IID_PPV_ARGS(&amp;amp;pps));
                    if (SUCCEEDED(hr))
                    {
                        PROPVARIANT propvar = {0};
                        hr = _GetValueFromString(key, pszValue, &amp;amp;propvar);
                        if (SUCCEEDED(hr))
                        {
                            hr = pps-&amp;gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyStore%3a%3aSetValue+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/setvalue.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyStore%3a%3aSetValue+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/setvalue.asp"&gt;SetValue&lt;/A&gt;(key, propvar);
                            if (SUCCEEDED(hr))
                            {
                                hr = pps-&amp;gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyStore%3a%3aCommit+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/commit.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=IPropertyStore%3a%3aCommit+Method&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertystore/commit.asp"&gt;Commit&lt;/A&gt;();
                            }
                            PropVariantClear(&amp;amp;propvar);
                        }
                        pps-&amp;gt;Release();
                    }
                    psi-&amp;gt;Release();
                }
            }
            wprintf(L"Wrote %s:%s to %s; hr = 0x%08x\n", pszProperty, pszValue, pszFile, hr);
        }

        CoUninitialize();
    }
}&lt;/FONT&gt;
&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;This code&amp;nbsp;figures out which property to set, opens the store for writing, figures out the value&amp;nbsp;to set, sets it, and commits the changes.&amp;nbsp; Here are the helper functions&amp;nbsp;I'm using:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;HRESULT _GetValueFromString(__in REFPROPERTYKEY key, __in PCWSTR pszValue, __out PROPVARIANT *ppropvar)
{
  &lt;/FONT&gt;&lt;FONT face="courier new,courier"&gt;  return &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=InitPropVariantFromString+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/propvarconversionfunctions/initpropvariantfromstring.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=InitPropVariantFromString+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/propvarconversionfunctions/initpropvariantfromstring.asp"&gt;InitPropVariantFromString&lt;/A&gt;(pszValue, ppropvar); 
}

HRESULT _GetShellItemFromRelativePath(&lt;BR&gt;    __in &lt;/FONT&gt;&lt;FONT face="courier new,courier"&gt;PCWSTR pszRelative, &lt;BR&gt;    __in REFIID riid, &lt;BR&gt;    __deref_out void **ppv)
{
    WCHAR szFile[MAX_PATH];
    HRESULT hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=StringCchCopy+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/resources/strings/stringreference/stringfunctions/stringcchcopy.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=StringCchCopy+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/resources/strings/stringreference/stringfunctions/stringcchcopy.asp"&gt;StringCchCopyW&lt;/A&gt;(szFile, ARRAYSIZE(szFile), pszRelative);
    if (SUCCEEDED(hr))
    {
        &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PathUnquoteSpaces+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/path/pathunquotespaces.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PathUnquoteSpaces+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/path/pathunquotespaces.asp"&gt;PathUnquoteSpacesW&lt;/A&gt;(szFile);

        WCHAR szDir[MAX_PATH];
        hr = &lt;A class="" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/getcurrentdirectory.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/getcurrentdirectory.asp"&gt;GetCurrentDirectory&lt;/A&gt;(ARRAYSIZE(szDir), szDir) ? S_OK : E_FAIL;
        if (SUCCEEDED(hr))
        {
            WCHAR szPath[MAX_PATH];
            hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PathCombine+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/path/pathcombine.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PathCombine+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/path/pathcombine.asp"&gt;PathCombineW&lt;/A&gt;(szPath, szDir, szFile) ? S_OK : E_FAIL;
            if (SUCCEEDED(hr))
            {
                hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=SHCreateItemFromParsingName+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/shcreateitemfromparsingname.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=SHCreateItemFromParsingName+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/shcreateitemfromparsingname.asp"&gt;SHCreateItemFromParsingName&lt;/A&gt;(szPath, NULL, riid, ppv);
            }
        }
    }
    return hr;
}&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face=georgia,palatino&gt;And here's my output:&lt;/FONT&gt;&lt;/PRE&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;C:\&amp;gt; propset.exe scan0010.jpg System.Keywords abc&lt;BR&gt;Wrote System.Keywords:abc to scan0010.jpg; hr = 0x00000000&amp;nbsp;&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face=georgia,palatino&gt;-Ben Karas&lt;/FONT&gt;&lt;/PRE&gt;&lt;PRE&gt;see also: &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/12/Property-coding-expedition-_2300_7-_2D00_-The-final-output.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/12/Property-coding-expedition-_2300_7-_2D00_-The-final-output.aspx"&gt;Reading properties&lt;/A&gt;&lt;/PRE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=824459" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category><category domain="http://blogs.msdn.com/benkaras/archive/tags/writing+properties/default.aspx">writing properties</category></item><item><title>Gotcha: You must release property stores quickly</title><link>http://blogs.msdn.com/benkaras/archive/2006/10/13/gotcha-you-must-release-property-stores-quickly.aspx</link><pubDate>Fri, 13 Oct 2006 22:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:821014</guid><dc:creator>benkaras</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/821014.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=821014</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=821014</wfw:comment><description>&lt;P&gt;The general rule is that you should minimize the length of time you have a property store open.&amp;nbsp; It is best to acquire the data you need and then release the store.&lt;/P&gt;
&lt;P&gt;Read-only&amp;nbsp;property stores lock files for reading using a filesystem&amp;nbsp;&lt;STRONG&gt;oplock&lt;/STRONG&gt;.&amp;nbsp; An oplock does more than just lock a file -- it blocks writers until the reader releases the lock.&amp;nbsp; This way a short-lived read operation simply delays a write instead of causing it to fail outright.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Now the gotcha is that the following code will deadlock:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;IShellItem2 *psi = ...&lt;BR&gt;IPropertyStore *ppsReadOnly;&lt;BR&gt;psi-&amp;gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellitem2/getpropertystore.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ishellitem2/getpropertystore.asp"&gt;GetPropertyStore&lt;/A&gt;(&lt;A class="" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/constants/getpropertystoreflags_constants.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/constants/getpropertystoreflags_constants.asp"&gt;GPS_DEFAULT&lt;/A&gt;, IID_PPV_ARGS(&amp;amp;ppsReadOnly));&lt;BR&gt;&lt;BR&gt;IPropertyStore *ppsReadWrite;&lt;BR&gt;psi-&amp;gt;GetPropertyStore(GPS_READWRITE, IID_PPV_ARGS(&amp;amp;ppsReadWrite));&lt;BR&gt;&lt;BR&gt;ppsReadWrite-&amp;gt;Release();&lt;BR&gt;ppsReadOnly-&amp;gt;Release();&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The first call to GetPropertyStore creates the oplock.&amp;nbsp; Any writers will block until it is released.&amp;nbsp; Thus the second call to GetPropertyStore blocks.&amp;nbsp; But the reader won't get released until the call completes.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;You might ask why was this feature added if it has such a big gotcha?&amp;nbsp; There are several reasons.&amp;nbsp; First, locking a file for reading is an important feature for the code reading the file.&amp;nbsp; We have to lock the file to prevent the data from changing while someone is reading it.&amp;nbsp; Second, since we lock the file anyway, callers should never have the file open long-term anyway.&amp;nbsp; Third, we discovered in testing that Windows often tried to read from a file just around the same time as it wanted to write to a file.&amp;nbsp; This led to error dialogs.&amp;nbsp; Using an oplock eliminates these error dialogs by waiting until the short-lived reader is finished.&lt;/P&gt;
&lt;P&gt;-Ben Karas&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=821014" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category></item><item><title>Properties coding expedition #7 - The final output</title><link>http://blogs.msdn.com/benkaras/archive/2006/10/12/Property-coding-expedition-_2300_7-_2D00_-The-final-output.aspx</link><pubDate>Thu, 12 Oct 2006 22:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:811318</guid><dc:creator>benkaras</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/811318.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=811318</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=811318</wfw:comment><description>&lt;P&gt;&lt;FONT face=georgia,palatino&gt;&lt;A class="" href="http://blogs.msdn.com/photos/benkaras/images/811298/original.aspx" mce_href="http://blogs.msdn.com/photos/benkaras/images/811298/original.aspx"&gt;&lt;IMG style="WIDTH: 160px; HEIGHT: 108px" height=108 hspace=5 src="http://blogs.msdn.com/photos/benkaras/images/811298/secondarythumb.aspx" width=160 align=right vspace=5 mce_src="http://blogs.msdn.com/photos/benkaras/images/811298/secondarythumb.aspx"&gt;&lt;/A&gt;This coding expedition has developed a tool that can dump out all the properties on a file.&amp;nbsp;If you are curious about the property system, I highly recommend you build this tool and run it on various file types.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;&lt;FONT face=georgia,palatino&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=Georgia&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/02/Coding-to-the-Windows-SDK.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/02/Coding-to-the-Windows-SDK.aspx"&gt;Coding to the Windows SDK&lt;/A&gt;&lt;BR&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/03/Properties-coding-expedition-_2300_1-_2D00_-Binding-to-an-item.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/03/Properties-coding-expedition-_2300_1-_2D00_-Binding-to-an-item.aspx"&gt;Part 1 - Binding to an item&lt;/A&gt;&lt;BR&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/04/777895.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/04/777895.aspx"&gt;Part 2 - Printing the IPropertyStore&lt;/A&gt;&lt;BR&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/05/778241.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/05/778241.aspx"&gt;Part 3 - Printing a value&lt;/A&gt;&lt;BR&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/06/Properties-coding-expedition-_2300_4-_2D00_-The-output.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/06/Properties-coding-expedition-_2300_4-_2D00_-The-output.aspx"&gt;Part 4 - The output&lt;/A&gt;&lt;BR&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/10/Properties-coding-expedition-_2D00_-Stripping-characters.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/10/Properties-coding-expedition-_2D00_-Stripping-characters.aspx"&gt;Part 5 - Stripping characters&lt;/A&gt;&lt;/FONT&gt;&amp;nbsp;&lt;BR&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/11/Properties-coding-expedition-_2300_6-_2D00_-Developer-friendly-output.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/11/Properties-coding-expedition-_2300_6-_2D00_-Developer-friendly-output.aspx"&gt;Part 6 - Developer friendly output&lt;/A&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;For your pleasure, I ran this tool on a JPG on my system (at right).&amp;nbsp; Here are some highlights:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;String properties can be vectors, or single valued.&amp;nbsp; Vectors can have 0, 1 or more values and are formatted with semicolons (;):&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="courier new,courier"&gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_author.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_author.asp"&gt;System.Author&lt;/A&gt;: VT_VECTOR|VT_LPWSTR&amp;nbsp;== Ben Karas&lt;BR&gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_keywords.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_keywords.asp"&gt;System.Keywords&lt;/A&gt;: VT_VECTOR|VT_LPWSTR&amp;nbsp;== Sol Duc Valley; Wildlife&lt;BR&gt;System.ItemNameDisplay: VT_LPWSTR&amp;nbsp;== scan0010.jpg&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;FONT face="courier new,courier"&gt;&lt;FONT face=georgia,palatino&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Numbers are stored in a variety of formats and are sometimes formatted or not.&amp;nbsp; It turns out 5 stars corresponds to a raw value of 99:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_image_bitdepth.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_image_bitdepth.asp"&gt;System.Image.BitDepth&lt;/A&gt;: VT_UI4&amp;nbsp;== 24&lt;BR&gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_size.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_size.asp"&gt;System.Size&lt;/A&gt;: VT_UI8: 653729 --&amp;gt; 638 KB&lt;BR&gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_rating.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_rating.asp"&gt;System.Rating&lt;/A&gt;: VT_UI4: 99 --&amp;gt; 5 Stars&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Raw dates look different than formatted dates.&amp;nbsp; Actually, the raw value is stored in 8 bytes, but &lt;FONT face="courier new,courier"&gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PropVariantToString+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/propvarconversionfunctions/propvarianttostring.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PropVariantToString+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/propvarconversionfunctions/propvarianttostring.asp"&gt;PropVariantToString&lt;/A&gt;&lt;/FONT&gt; gave us a &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/09/27/773315.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/09/27/773315.aspx"&gt;locale-invariant format&lt;/A&gt;:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_dateimported.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_dateimported.asp"&gt;System.DateImported&lt;/A&gt;: VT_FILETIME: 2006/09/30:05:12:06.000 --&amp;gt; 9/29/2006 10:12 PM&amp;nbsp;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Some properties are not meant for display:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;System.ParsingBindContext: VT_UNKNOWN: &amp;lt;unprintable raw value&amp;gt; --&amp;gt; &amp;lt;formatfordisplay failed&amp;gt;&lt;BR&gt;&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_finddata.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/schemas/properties/system_finddata.asp"&gt;System.FindData&lt;/A&gt;: VT_VECTOR|VT_UI1: 32; 0; 0; 0; 0; 71; 228; 38; 161; 228; 198; ...&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;And there is even a property the system doesn't know about!&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;{9E5E05AC-1936-4A75-94F7-4704B8B01923} 0: VT_BSTR&amp;nbsp;== scan0010.jpg&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;What I want to impress on you is that the property system supports a rich set of storage formats for values.&amp;nbsp; Property handlers, such as the one for JPGs, are capable of exposing a large amount of information about a file.&amp;nbsp;&amp;nbsp; Finally, the rules about when to display and how to format values are data driven by &lt;A class="" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/schemas/propdesc_schema/propdescentry.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/schemas/propdesc_schema/propdescentry.asp"&gt;property schemas&lt;/A&gt;.&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Georgia&gt;-Ben Karas&lt;/FONT&gt;&lt;/P&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=811318" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category></item><item><title>Properties coding expedition #6 - Developer friendly output</title><link>http://blogs.msdn.com/benkaras/archive/2006/10/11/Properties-coding-expedition-_2300_6-_2D00_-Developer-friendly-output.aspx</link><pubDate>Thu, 12 Oct 2006 03:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:811227</guid><dc:creator>benkaras</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/811227.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=811227</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=811227</wfw:comment><description>&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Using the tool I developed in this series, I know that my test photo has "&lt;A class="" href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;amp;sectionid=7053&amp;amp;postid=811189" mce_href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;amp;sectionid=7053&amp;amp;postid=811189"&gt;Rating:&amp;nbsp;5 Stars&lt;/A&gt;".&amp;nbsp; But how is this value actually represented in the JPG itself?&amp;nbsp; Let's answer that by adding some developer friendly output.&amp;nbsp; Here's what I did:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;First, I need a developer-friendly label. I can get the canonical name using &lt;FONT face="courier new,courier"&gt;&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetNameFromPropertyKey+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetnamefrompropertykey.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetNameFromPropertyKey+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetnamefrompropertykey.asp"&gt;PSGetNameFromPropertyKey&lt;/A&gt;&lt;/FONT&gt;. If a property doesn't have a canonical name, I just grab the "&lt;FONT face="courier new,courier"&gt;{GUID} PID&lt;/FONT&gt;" representation.&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;HRESULT _PrintPropertyValue(__in REFPROPERTYKEY key, __in REFPROPVARIANT propvar)
{
    // 1. Get a canonical name for this property
    PWSTR pszName = NULL;
    HRESULT hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetNameFromPropertyKey+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetnamefrompropertykey.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSGetNameFromPropertyKey+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psgetnamefrompropertykey.asp"&gt;PSGetNameFromPropertyKey&lt;/A&gt;(key, &amp;amp;pszName);
    if (FAILED(hr))
    {
        // 1b. There's no canonical name: get the "{GUID} PID" string.
        WCHAR szKey[100];
        hr = &lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psstringfrompropertykey.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psstringfrompropertykey.asp"&gt;PSStringFromPropertyKey&lt;/A&gt;(key, szKey, ARRAYSIZE(szKey));
        if (SUCCEEDED(hr))
        {
            hr = &lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/string/shstrdup.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/string/shstrdup.asp"&gt;SHStrDupW&lt;/A&gt;(szKey, &amp;amp;pszName);
        }
    }&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Here, I get the type of the value. I'll show the helper later.&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;    PCWSTR pszType = NULL;
    if (SUCCEEDED(hr))
    {
        // 2. Get the type
        pszType = _GetVarTypeString(propvar.vt);
    }&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Next, I get the raw value as a string. &lt;FONT face="courier new,courier"&gt;PropVariantToStringAlloc&lt;/FONT&gt; can convert most types to strings, but failing that I just print a message.&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;    PWSTR pszRawValue = NULL;
    if (SUCCEEDED(hr))
    {
        // 3. Get the raw value
        hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PropVariantToStringAlloc+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/propvarconversionfunctions/propvarianttostringalloc.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PropVariantToStringAlloc+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/propvarconversionfunctions/propvarianttostringalloc.asp"&gt;PropVariantToStringAlloc&lt;/A&gt;(propvar, &amp;amp;pszRawValue);
        if (FAILED(hr))
        {
            hr = SHStrDupW(L"&lt;UNPRINTABLE value raw&gt;", &amp;amp;pszRawValue);
        }
    }&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;I also need the formatted value.&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;    PWSTR pszFormattedValue = NULL;
    if (SUCCEEDED(hr))
    {
        // 4. Get the formatted value
        hr = &lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSFormatForDisplay+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psformatfordisplay.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=PSFormatForDisplay+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/functions/psformatfordisplay.asp"&gt;PSFormatForDisplayAlloc&lt;/A&gt;(key, propvar, PDFF_DEFAULT, &amp;amp;pszFormattedValue);
        if (FAILED(hr))
        {
            hr = SHStrDupW(L"&lt;FORMATFORDISPLAY failed&gt;", &amp;amp;pszFormattedValue);
        }
    }
&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face=georgia,palatino&gt;Finally, I check to see if the formatted value differs from the raw value.&amp;nbsp; Sometimes it does and sometimes it doesn't depending on the formatting that is performed.&amp;nbsp; This results in slightly cleaner output:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;    if (SUCCEEDED(hr))
    {&lt;BR&gt;        // LRM RLM LRE RLE PDF LRO RLO
        _StripCharacters(pszFormattedValue, L"\x200e\x200f\x202a\x202b\x202c\x202d\x202e");
        _StripCharacters(pszRawValue, L"\x200e\x200f\x202a\x202b\x202c\x202d\x202e");
        if (&lt;A class="" href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=StrCmpC+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/string/strcmpc.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=StrCmpC+Function&amp;amp;url=http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/string/strcmpc.asp"&gt;StrCmpCW&lt;/A&gt;(pszFormattedValue, pszRawValue))
        {
            // The values are different: print them both
            wprintf(L"%s: %s: %s --&amp;gt; %s\n", pszName, pszType, pszRawValue, pszFormattedValue);
        }
        else
        {
            // The values are the same: print just one
            wprintf(L"%s: %s == %s\n", pszName, pszType, pszFormattedValue);
        }
    }

    CoTaskMemFree(pszName);
    CoTaskMemFree(pszRawValue);
    CoTaskMemFree(pszFormattedValue);

    return hr;
}&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;As promised, here's the&amp;nbsp;helper function to obtain a string form of a VARTYPE:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;PCWSTR _GetVarTypeString(__in VARTYPE vt)
{
#define VARTYPEENTRY(v) case v: return L ## #v
    switch (vt)
    {
        VARTYPEENTRY(VT_EMPTY);
        VARTYPEENTRY(VT_UI1);
        ...[snip]...
    }
    return L"&amp;lt;Unknown type&amp;gt;";
}&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I'll go over the output tomorrow.&lt;/P&gt;
&lt;P&gt;-Ben Karas&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=811227" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category></item><item><title>Properties coding expedition #5 - Stripping characters</title><link>http://blogs.msdn.com/benkaras/archive/2006/10/10/Properties-coding-expedition-_2D00_-Stripping-characters.aspx</link><pubDate>Wed, 11 Oct 2006 03:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:811189</guid><dc:creator>benkaras</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/811189.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=811189</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=811189</wfw:comment><description>&lt;P&gt;&lt;FONT face=georgia,palatino&gt;In &lt;/FONT&gt;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/06/Properties-coding-expedition-_2300_4-_2D00_-The-output.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/06/Properties-coding-expedition-_2300_4-_2D00_-The-output.aspx"&gt;&lt;FONT face=georgia,palatino&gt;Part 4&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt;, I discovered that &lt;/FONT&gt;&lt;A class="" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_2bj9.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_2bj9.asp"&gt;&lt;FONT face=georgia,palatino&gt;WideCharToMultiByte&lt;/FONT&gt;&lt;/A&gt;&lt;FONT face=georgia,palatino&gt; converts certain invisible non-spacing Unicode characters to ?.&amp;nbsp; This makes the output look really silly in a command line application.&amp;nbsp; I want to keep this as a command line application, so I need to strip these characters away.&amp;nbsp; A simple helper solves this rather neatly:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;void _StripCharacters(__inout PWSTR pszText, __in PCWSTR pszRemove)
{
    PWSTR pszSource = pszText;
    PWSTR pszDest = pszSource;
    while (*pszSource)
    {
        // Skip copying characters found in pszRemove
        if (!&lt;A class="" href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/string/strchr.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/string/strchr.asp"&gt;StrChr&lt;/A&gt;(pszRemove, *pszSource))
        {
            *pszDest = *pszSource;
            pszDest++;
        }
        pszSource++;
    }
    *pszDest = 0;   // NULL terminate
}&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P mce_keep="true"&gt;&lt;FONT face=georgia,palatino&gt;This modifies the input string, omitting any characters found in pszRemove.&amp;nbsp; Nothing fancy.&amp;nbsp; Now I call it when I want to send a string to the console:&lt;/FONT&gt;&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;... from &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/05/778241.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/05/778241.aspx"&gt;part 3&lt;/A&gt; ...
PWSTR pszValue;
hr = ppropdesc-&amp;gt;FormatForDisplay(propvar, PDFF_DEFAULT, &amp;amp;pszValue);
if (SUCCEEDED(hr))
{&lt;BR&gt;    // &lt;A class="" href="http://www.fileformat.info/info/unicode/char/200e/index.htm" mce_href="http://www.fileformat.info/info/unicode/char/200e/index.htm"&gt;LRM&lt;/A&gt; &lt;A class="" href="http://www.fileformat.info/info/unicode/char/200f/index.htm" mce_href="http://www.fileformat.info/info/unicode/char/200f/index.htm"&gt;RLM&lt;/A&gt; &lt;A class="" href="http://www.fileformat.info/info/unicode/char/202a/index.htm" mce_href="http://www.fileformat.info/info/unicode/char/202a/index.htm"&gt;LRE&lt;/A&gt; &lt;A class="" href="http://www.fileformat.info/info/unicode/char/202b/index.htm" mce_href="http://www.fileformat.info/info/unicode/char/202b/index.htm"&gt;RLE&lt;/A&gt; &lt;A class="" href="http://www.fileformat.info/info/unicode/char/202c/index.htm" mce_href="http://www.fileformat.info/info/unicode/char/202c/index.htm"&gt;PDF&lt;/A&gt; &lt;A class="" href="http://www.fileformat.info/info/unicode/char/202d/index.htm" mce_href="http://www.fileformat.info/info/unicode/char/202d/index.htm"&gt;LRO&lt;/A&gt; &lt;A class="" href="http://www.fileformat.info/info/unicode/char/202e/index.htm" mce_href="http://www.fileformat.info/info/unicode/char/202e/index.htm"&gt;RLO&lt;/A&gt;&lt;/FONT&gt;&lt;FONT face="courier new,courier"&gt;
    _StripCharacters(pszValue, L"\x200e\x200f\x202a\x202b\x202c\x202d\x202e");  
    wprintf(L"%s: %s\n", pszLabel, pszValue);
    CoTaskMemFree(pszValue);
}
...&lt;/FONT&gt;
&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now the output is free of those annoying question marks: 
&lt;BLOCKQUOTE&gt;&lt;PRE&gt;&lt;FONT face="courier new,courier"&gt;Date last saved: 9/29/2006 10:12 PM
Width: 1139 pixels
Height: 769 pixels
Horizontal resolution: 200 dpi
Vertical resolution: 200 dpi
Bit depth: 24
Dimensions: 1139 x 769&lt;/FONT&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=811189" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category></item><item><title>Properties coding expedition #4 - The output</title><link>http://blogs.msdn.com/benkaras/archive/2006/10/06/Properties-coding-expedition-_2300_4-_2D00_-The-output.aspx</link><pubDate>Sat, 07 Oct 2006 03:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:779032</guid><dc:creator>benkaras</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/benkaras/comments/779032.aspx</comments><wfw:commentRss>http://blogs.msdn.com/benkaras/commentrss.aspx?PostID=779032</wfw:commentRss><wfw:comment>http://blogs.msdn.com/benkaras/rsscomments.aspx?PostID=779032</wfw:comment><description>&lt;P&gt;&lt;FONT face=Georgia size=2&gt;The program itself is provided in parts&amp;nbsp;&lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/03/Properties-coding-expedition-_2300_1-_2D00_-Binding-to-an-item.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/03/Properties-coding-expedition-_2300_1-_2D00_-Binding-to-an-item.aspx"&gt;1&lt;/A&gt;, &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/04/777895.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/04/777895.aspx"&gt;2&lt;/A&gt;, and &lt;A class="" href="http://blogs.msdn.com/benkaras/archive/2006/10/05/778241.aspx" mce_href="http://blogs.msdn.com/benkaras/archive/2006/10/05/778241.aspx"&gt;3&lt;/A&gt;.&amp;nbsp; So I compiled my&amp;nbsp;program and ran it from the command line.&amp;nbsp; Here's a snippet of what I got back:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;FONT size=2&gt;Properties for 'scan0010.jpg'&lt;BR&gt;Folder name: propshow&lt;BR&gt;Type: JPEG Image&lt;BR&gt;Name: scan0010.jpg&lt;BR&gt;Size: 638 KB&lt;BR&gt;Attributes: A&lt;BR&gt;Date modified: ?9/?29/?2006 ??10:12 PM&lt;BR&gt;Date created: ?9/?30/?2006 ??8:00 AM&lt;BR&gt;Date accessed: ?9/?30/?2006 ??8:00 AM&lt;BR&gt;Title: Mountain goat&lt;BR&gt;Authors: Ben Karas&lt;BR&gt;Tags: Sol Duc Valley; Wildlife&lt;BR&gt;Content created: ?9/?29/?2006 ??10:12 PM&lt;BR&gt;Date last saved: ?9/?29/?2006 ??10:12 PM&lt;BR&gt;Width: ?1139 pixels&lt;BR&gt;Height: ?769 pixels&lt;BR&gt;Horizontal resolution: ?200 dpi&lt;BR&gt;Vertical resolution: ?200 dpi&lt;BR&gt;Bit depth: 24&lt;BR&gt;Dimensions: ?1139 x 769?&lt;BR&gt;Rating: 5 Stars&lt;BR&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;...[snip 20 more lines]...&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Georgia size=2&gt;Ok, now you get a sense about&amp;nbsp;what properties are on a file!&amp;nbsp; JPGs happen to be one of the better supported filetypes on the system.&amp;nbsp; We can see titles, authors, ratings, dimensions, etc on JPG files.&amp;nbsp; &lt;/FONT&gt;&lt;FONT face=Georgia size=2&gt;Also notice the variety of information.&amp;nbsp; Some items are dates, others are numbers.&amp;nbsp; There's even a list of tags in there!&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Georgia color=#ff0000 size=2&gt;&lt;FONT color=#000000&gt;Now the question you really want to ask is &lt;STRONG&gt;"What are those "?" doing in there?"&lt;/STRONG&gt;&amp;nbsp; This is a very common question&lt;/FONT&gt;&lt;FONT color=#000000&gt;.&amp;nbsp; The ? result from a bad UNICODE-&amp;gt;OEM conversion.&amp;nbsp; &lt;A href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/formatfordisplay.asp" mce_href="http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/ifaces/ipropertydescription/formatfordisplay.asp"&gt;IPropertyDescription::FormatForDisplay&lt;/A&gt; inserts UNICODE &lt;A href="http://www.fileformat.info/info/unicode/char/200e/index.htm" mce_href="http://www.fileformat.info/info/unicode/char/200e/index.htm"&gt;LTR&lt;/A&gt; and &lt;A href="http://www.fileformat.info/info/unicode/char/200f/index.htm" mce_href="http://www.fileformat.info/info/unicode/char/200f/index.htm"&gt;RTL&lt;/A&gt; characters (0x200e and 0x200f).&amp;nbsp; These characters let English strings &lt;A href="http://www.unicode.org/reports/tr9/" mce_href="http://www.unicode.org/reports/tr9/"&gt;display correctly on Arabic builds&lt;/A&gt;.&amp;nbsp; Arabic strings get similar characters so that they display correctly on left to right builds.&amp;nbsp; &lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Georgia color=#ff0000 size=2&gt;&lt;FONT color=#000000&gt;UNICODE applications display these LTR and RTL characters correctly.&amp;nbsp; &lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Georgia color=#ff0000 size=2&gt;&lt;FONT color=#000000&gt;But the command line (and &lt;A href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=WideCharToMultiByte&amp;amp;url=http://msdn.microsoft.com/library/en-us/intl/unicode_2bj9.asp" mce_href="http://search.msdn.microsoft.com/search/Redirect.aspx?title=WideCharToMultiByte&amp;amp;url=http://msdn.microsoft.com/library/en-us/intl/unicode_2bj9.asp"&gt;WideCharToMultiByte&lt;/A&gt;) for some reason converts these to "?".&amp;nbsp; Oops.&amp;nbsp; &lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face=Georgia color=#ff0000 size=2&gt;&lt;FONT color=#000000&gt;&amp;nbsp;&lt;/FONT&gt;&lt;/FONT&gt;&lt;FONT face=Georgia color=#ff0000 size=2&gt;&lt;FONT color=#000000&gt;This is a time when I wish&amp;nbsp;FormatForDisplay had a flag to strip these characters out; alas.&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=779032" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/benkaras/archive/tags/Property+System/default.aspx">Property System</category></item></channel></rss>