{"id":107922,"date":"2023-03-09T07:00:00","date_gmt":"2023-03-09T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107922"},"modified":"2023-03-09T09:11:21","modified_gmt":"2023-03-09T17:11:21","slug":"20230309-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230309-00\/?p=107922","title":{"rendered":"From a Windows app, how can I check whether there is an app installed that implements a particular URI scheme?, part 2"},"content":{"rendered":"<p>Last time, we looked at <a title=\"From a Windows app, how can I check whether there is an app installed that implements a particular URI scheme?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230308-04\/?p=107915\"> detecting packaged apps which support a particular URI scheme<\/a>. Unpackaged apps do not have AppIds (in the Windows Store sense), so some of the operations don&#8217;t work.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>Function<\/th>\n<th>Packaged apps<\/th>\n<th>Unpackaged apps<\/th>\n<\/tr>\n<tr>\n<td><code>Launcher.<wbr \/>Find\u00adUri\u00adScheme\u00adHandlers\u00adAsync<\/code><\/td>\n<td>Yes<\/td>\n<td>No<\/td>\n<\/tr>\n<tr>\n<td><code>Launcher.<wbr \/>Query\u00adUri\u00adSupport\u00adAsync(<wbr \/>uri)<\/code><\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td><code>Launcher.<wbr \/>Query\u00adUri\u00adSupport\u00adAsync(<wbr \/>uri, pfn)<\/code><\/td>\n<td>Yes<\/td>\n<td>N\/A<\/td>\n<\/tr>\n<tr>\n<td><code>Launcher.<wbr \/>Launch\u00adUri\u00adAsync<\/code><\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If you think about it, the reasons for the above entries are obvious:<\/p>\n<ul>\n<li><code>Launcher.<wbr \/>Find\u00adUri\u00adScheme\u00adHandlers\u00adAsync<\/code> returns a collection of <code>AppInfo<\/code> objects, and <code>AppInfo<\/code> objects describe packaged apps. So it has no way to report an unpackaged app.<\/li>\n<li><code>Launcher.<wbr \/>Query\u00adUri\u00adSupport\u00adAsync(<wbr \/>uri)<\/code> just tells you whether the URI can be launched or not. If it can be launched by an unpackaged app, then it will report <code>Available<\/code>, just like the case where it can be launched by a packaged app. It doesn&#8217;t tell you <i>which<\/i> app will launch it, so it doesn&#8217;t run into the problem of trying to describe something that it has no way to describe.<\/li>\n<li><code>Launcher.<wbr \/>Query\u00adUri\u00adSupport\u00adAsync(<wbr \/>uri, pfn)<\/code> takes a package family name, and unpackaged apps don&#8217;t have a package family name, so it&#8217;s not even possible to specify the unpackaged app you are querying for.<\/li>\n<li><code>Launcher.<wbr \/>Launch\u00adUri\u00adAsync<\/code> tries to launch the URI and tells you whether it succeeded. It doesn&#8217;t tell you anything about the app that ultimately handled the URI, so unpackaged apps don&#8217;t cause any problems.<\/li>\n<\/ul>\n<p>But what if you want to ask about unpackaged apps, too?<\/p>\n<p>The <code>SH\u00adAssoc\u00adEnum\u00adHandlers\u00adFor\u00adProtocol\u00adBy\u00adApplication<\/code> function gives you the apps (both packaged and unpackaged) which can launch a particular URI scheme.<\/p>\n<p>Today&#8217;s smart pointer library will be (rolls dice)\u00b9 WRL.<\/p>\n<pre>Microsoft::WRL::ComPtr&lt;IEnumAssocHandlers&gt; e;\r\nauto hr = SHAssocEnumHandlersForProtocolByApplication(L\"http\", IID_PPV_ARGS(&amp;e));\r\nif (SUCCEEDED(hr)) {\r\n    Microsoft::WRL::ComPtr&lt;IAssocHandler&gt; handler;\r\n    while (e-&gt;Next(1, &amp;handler, nullptr) == S_OK) {\r\n        PWSTR name;\r\n        if (SUCCEEDED(handler-&gt;GetUIName(&amp;name))) {\r\n            printf(\"UI Name: %ls\\n\", name);\r\n            CoTaskMemFree(name);\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>You can even ask pass the URI to a specific handler by calling the <code>Invoke<\/code> method:<\/p>\n<pre>HRESULT InvokeHandlerOnURI(IAssocHandler* handler, PCWSTR uri)\r\n{\r\n    Microsoft::WRL::ComPtr&lt;IShellItem&gt; item;\r\n    RETURN_IF_FAILED(SHCreateItemFromParsingName(\r\n        L\"http:\/\/msn.com\/\", nullptr, IID_PPV_ARGS(&amp;item)));\r\n    Microsoft::WRL::ComPtr&lt;IDataObject&gt; dto;\r\n    RETURN_IF_FAILED(item-&gt;BindToHandler(nullptr,\r\n        BHID_DataObject, IID_PPV_ARGS(&amp;dto)));\r\n    RETURN_IF_FAILED(handler-&gt;Invoke(dto.Get()));\r\n    return S_OK;\r\n}\r\n<\/pre>\n<p>\u00b9 Dirty secret: The dice are loaded.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Alternatives that work for unpackaged apps.<\/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-107922","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Alternatives that work for unpackaged apps.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107922","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=107922"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107922\/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=107922"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107922"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107922"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}