{"id":44853,"date":"2015-01-22T07:00:00","date_gmt":"2015-01-22T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2015\/01\/22\/the-wonderful-world-of-shell-bind-context-strings\/"},"modified":"2019-03-13T12:12:16","modified_gmt":"2019-03-13T19:12:16","slug":"20150122-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20150122-00\/?p=44853","title":{"rendered":"The wonderful world of shell bind context strings"},"content":{"rendered":"<p><a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/05\/03\/10415778.aspx\">Some time ago<\/a>, we saw how the <code>IBindCtx<\/code> parameter to <code>IShell&shy;Folder::Parse&shy;Display&shy;Name<\/code> can be used to modify how the parse takes place. More generally, the <code>IBindCtx<\/code> parameter to a function is a catch-all <i>miscellaneous options<\/i> parameter. <\/p>\n<p>The interesting part of the bind context is all the stuff that has been added to it via <a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/ms687254(v=vs.85).aspx\">the <code>IBindCtx::Register&shy;Object&shy;Param<\/code> method<\/a>. You can attach arbitrary objects to the bind context, using a string to identify each one. <\/p>\n<p>Some bind context parameters are like Boolean parameters that simply change some default behavior of the operation. For these operations, the object that is associated with the bind context string is not important; the important thing is that there is <i>something<\/i> associated with it. Traditionally, you just connect a dummy object that implements just <code>IUnknown<\/code>. <\/p>\n<p>In the most general case, the object associated with a bind context string implements some operation-specific interface. For example, <a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/bb762592(v=vs.85).aspx\">the <code>STR_BIND_DELEGATE_CREATE_OBJECT<\/code> bind context string<\/a> expects you to associate an object that implements the <code>ICreate&shy;Object<\/code> interface, because the whole point of the <code>STR_BIND_DELEGATE_CREATE_OBJECT<\/code> bind context string is to say, &#8220;Hey, I want to create objects in a nonstandard way,&#8221; so you need to tell it what that nonstandard way is. <\/p>\n<p>At the other extreme, you may have a chunk of data that you want to associate with the bind context string. Since bind contexts want to associate objects, you need to wrap the data inside a COM object. We saw this earlier when <a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/05\/03\/10415778.aspx\">we had to create an object that implemented the <code>IFile&shy;System&shy;Bind&shy;Data<\/code> interface<\/a> in order to babysit a <code>WIN32_FIND_DATA<\/code> structure. <\/p>\n<p>Rather than having to create a separate interface for each data type (hello, <a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/dd378297(v=vs.85).aspx\"><code>IObject&shy;With&shy;Folder&shy;Enum&shy;Mode<\/code><\/a>), and rather than going to the opposite extreme and just using <code>IStream<\/code> to pass arbitrary unstructured data, the shell folks decided to take a middle-ground approach: Use a common interface that still has a modicum of type safety, namely, <code>IProperty&shy;Bag<\/code>. Other nice things about this approach is that there are a lot of pre-existing helper functions for property bags and property variants. Also, you need to attach only one object instead of a whole bunch of tiny little ones. <\/p>\n<p>Under this new regime (which took hold in Windows&nbsp;8), the bind context has an associated property bag, and you put your data in that property bag. <\/p>\n<p>In pictures: <\/p>\n<table CELLPADDING=\"3\" STYLE=\"border-collapse: collapse\">\n<tr>\n<td><\/td>\n<td>&nbsp;<\/td>\n<td COLSPAN=\"2\"><code>IBindCtx::Register&shy;Object&shy;Param<\/code><\/td>\n<td><\/td>\n<td COLSPAN=\"2\"><code>IProperty&shy;Bag::Write<\/code><\/td>\n<\/tr>\n<tr>\n<td STYLE=\"border: solid 1px black\"><code>IBindCtx<\/code><\/td>\n<td>&rarr;<\/td>\n<td STYLE=\"border: solid 1px black\">Boolean parameter<\/td>\n<td STYLE=\"border: solid 1px black\"><code>IUnknown<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><\/td>\n<td STYLE=\"border: solid 1px black\">Interface parameter<\/td>\n<td STYLE=\"border: solid 1px black\">object with custom interface<\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><\/td>\n<td STYLE=\"border: solid 1px black\"><code>STR_PROPERTY&shy;BAG_PARAM<\/code><\/td>\n<td STYLE=\"border: solid 1px black\"><code>IPropertyBag<\/code><\/td>\n<td>&rarr;<\/td>\n<td STYLE=\"border: solid 1px black\">Property bag <code>DWORD<\/code> parameter<\/td>\n<td STYLE=\"border: solid 1px black\"><code>VT_UI4<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<td STYLE=\"border: solid 1px black\">Property bag string parameter<\/td>\n<td STYLE=\"border: solid 1px black\"><code>VT_BSTR<\/code><\/td>\n<\/tr>\n<tr>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<td STYLE=\"border: solid 1px black\">Property bag Boolean parameter<\/td>\n<td STYLE=\"border: solid 1px black\"><a HREF=\"https:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2004\/12\/22\/329884.aspx\"><code>VT_BOOL<\/code><\/a><\/td>\n<\/tr>\n<\/table>\n<p>If you want a Boolean-style parameter to be <code>true<\/code>, then set it in the bind context with a dummy object that implements <code>IUnknown<\/code>. If you want a Boolean-style parameter to <code>false<\/code>, then omit it from the bind context entirely. <\/p>\n<p>To set an interface-style parameter, set it in the bind context with an object that implements the desired interface. <\/p>\n<p>To set a property bag-based parameter, set it in the property bag with the appropriate variant type. <\/p>\n<p>Here are the bind context strings defined up through Windows&nbsp;8.1 and the way you set them into the bind context. <\/p>\n<table BORDER=\"1\" CELLPADDING=\"3\" STYLE=\"border-collapse: collapse\">\n<tr>\n<th>Bind context string<\/th>\n<th>Model<\/th>\n<th>Operation<\/th>\n<\/tr>\n<tr>\n<td><code>STR_AVOID_DRIVE_RESTRICTION_POLICY<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding<\/td>\n<\/tr>\n<tr>\n<td><code>STR_BIND_DELEGATE_CREATE_OBJECT<\/code><\/td>\n<td>Interface <code>ICreateObject<\/code><\/td>\n<td>Binding<\/td>\n<\/tr>\n<tr>\n<td><code>STR_BIND_FOLDER_ENUM_MODE<\/code><\/td>\n<td>Interface <code>IObjectWith&shy;FolderEnumMode<\/code><\/code>     <\/p>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_BIND_FOLDERS_READ_ONLY<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_BIND_FORCE_FOLDER_SHORTCUT_RESOLVE<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding<\/td>\n<\/tr>\n<tr>\n<td><code>STR_DONT_PARSE_RELATIVE<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_DONT_RESOLVE_LINK<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding<\/td>\n<\/tr>\n<tr>\n<td><code>STR_ENUM_ITEMS_FLAGS<\/code><\/td>\n<td>Property bag: <code>VT_UI4<\/code><\/td>\n<td>Binding for enumeration<\/td>\n<\/tr>\n<tr>\n<td><code>STR_FILE_SYS_FIND_DATA<\/code><\/td>\n<td>Interface <code>IFileSys&shy;BindData<\/code> or <code>IFileSys&shy;BindData2<\/code><\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_FILE_SYS_BIND_DATA_WIN7_FORMAT<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_GET_ASYNC_HANDLER<\/code><\/td>\n<td>Boolean<\/td>\n<td>GetUIObjectOf<\/td>\n<\/tr>\n<tr>\n<td><code>STR_GPS_BEST&shy;EFFORT<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding for <code>IProperty&shy;Store<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>STR_GPS_DELAY&shy;CREATION<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding for <code>IProperty&shy;Store<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>STR_GPS_FAST&shy;PROPERTIES&shy;ONLY<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding for <code>IProperty&shy;Store<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>STR_GPS_HANDLER&shy;PROPERTIES&shy;ONLY<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding for <code>IProperty&shy;Store<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>STR_GPS_NO_OPLOCK<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding for <code>IProperty&shy;Store<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>STR_GPS_OPEN&shy;SLOW&shy;ITEM<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding for <code>IProperty&shy;Store<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>STR_IFILTER_FORCE_TEXT_FILTER_FALLBACK<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding for <code>IFilter<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>STR_IFILTER_LOAD_DEFINED_FILTER<\/code><\/td>\n<td>Boolean<\/td>\n<td>Binding for <code>IFilter<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>STR_INTERNAL_NAVIGATE<\/code><\/td>\n<td>Boolean<\/td>\n<td>Loading history<\/td>\n<\/tr>\n<tr>\n<td><code>STR_INTERNET&shy;FOLDER_PARSE_ONLY_URLMON_BINDABLE<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_ITEM_CACHE_CONTEXT<\/code><\/td>\n<td>Interface <code>IBindCtx<\/code><\/td>\n<td>Parsing and initiailzing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_NO_VALIDATE_FILE&shy;NAME_CHARS<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_ALLOW_INTERNET_SHELL_FOLDERS<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_AND_CREATE_ITEM<\/code><\/td>\n<td>Interface <code>IParse&shy;And&shy;Create&shy;Item<\/code><\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_DONT_REQUIRE_VALIDATED_URLS<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_EXPLICIT_ASSOCIATION_SUCCESSFUL<\/code><\/td>\n<td>Property bag: <code>VT_BOOL<\/code><\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_PARTIAL_IDLIST<\/code><\/td>\n<td>Interface <code>IShell&shy;Item<\/code><\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_PREFER_FOLDER_BROWSING<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_PREFER_WEB_BROWSING<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_PROPERTY&shy;STORE<\/code><\/td>\n<td>Interface <code>IProperty&shy;Bag<\/code><\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_SHELL_PROTOCOL_TO_FILE_OBJECTS<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_SHOW_NET_DIAGNOSTICS_UI<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_SKIP_NET_CACHE<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_TRANSLATE_ALIASES<\/code><\/td>\n<td>Boolean<\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_WITH_EXPLICIT_ASSOCAPP<\/code><\/td>\n<td>Property bag: <code>VT_BSTR<\/code><\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_WITH_EXPLICIT_PROGID<\/code><\/td>\n<td>Property bag: <code>VT_BSTR<\/code><\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PARSE_WITH_PROPERTIES<\/code><\/td>\n<td>Interface <code>IProperty&shy;Store<\/code><\/td>\n<td>Parsing<\/td>\n<\/tr>\n<tr>\n<td><code>STR_PROPERTYBAG_PARAM<\/code><\/td>\n<td>Interface <code>IProperty&shy;Bag<\/code><\/td>\n<td>holds property bag parameters<\/td>\n<\/tr>\n<tr>\n<td><code>STR_SKIP_BINDING_CLSID<\/code><\/td>\n<td>Interface <code>IPersist<\/code><\/td>\n<td>Parsing and binding<\/td>\n<\/tr>\n<\/table>\n<p>There are some oddities in the above table. <\/p>\n<ul>\n<li>All of the <code>STR_GPS_*<\/code> values would be more conveniently     expressed as a single <code>VT_UI4<\/code> property bag-based     value. (Exercise: Why isn&#8217;t it?) \n<li>The <code>STR_ITEM_CACHE_CONTEXT<\/code> bind context     parameter is itself another bind context!     The idea here is that you, the caller, are enabling caching     during the parse,     and the inner bind context acts as the cache. \n<li>The <code>STR_PARSE_EXPLICIT_ASSOCIATION_SUCCESSFUL<\/code>     value is unusual in that it is something set by the parser and passed     back to the caller. \n<li>As we have been discussing,     <code>STR_PROPERTY&shy;BAG_PARAM<\/code> is a bind context     string that doesn&#8217;t mean anything on its own.     Rather, it provides a property bag into which more parameters can be     stored. <\/ul>\n<p>Next time, I&#8217;ll write some helper functions to make all this slightly more manageable. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>A generic options parameter.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-44853","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A generic options parameter.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/44853","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=44853"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/44853\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=44853"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=44853"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=44853"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}