March 9th, 2023

From a Windows app, how can I check whether there is an app installed that implements a particular URI scheme?, part 2

Last time, we looked at detecting packaged apps which support a particular URI scheme. Unpackaged apps do not have AppIds (in the Windows Store sense), so some of the operations don’t work.

Function Packaged apps Unpackaged apps
Launcher.Find­Uri­Scheme­Handlers­Async Yes No
Launcher.Query­Uri­Support­Async(uri) Yes Yes
Launcher.Query­Uri­Support­Async(uri, pfn) Yes N/A
Launcher.Launch­Uri­Async Yes Yes

If you think about it, the reasons for the above entries are obvious:

  • Launcher.Find­Uri­Scheme­Handlers­Async returns a collection of AppInfo objects, and AppInfo objects describe packaged apps. So it has no way to report an unpackaged app.
  • Launcher.Query­Uri­Support­Async(uri) just tells you whether the URI can be launched or not. If it can be launched by an unpackaged app, then it will report Available, just like the case where it can be launched by a packaged app. It doesn’t tell you which app will launch it, so it doesn’t run into the problem of trying to describe something that it has no way to describe.
  • Launcher.Query­Uri­Support­Async(uri, pfn) takes a package family name, and unpackaged apps don’t have a package family name, so it’s not even possible to specify the unpackaged app you are querying for.
  • Launcher.Launch­Uri­Async tries to launch the URI and tells you whether it succeeded. It doesn’t tell you anything about the app that ultimately handled the URI, so unpackaged apps don’t cause any problems.

But what if you want to ask about unpackaged apps, too?

The SH­Assoc­Enum­Handlers­For­Protocol­By­Application function gives you the apps (both packaged and unpackaged) which can launch a particular URI scheme.

Today’s smart pointer library will be (rolls dice)¹ WRL.

Microsoft::WRL::ComPtr<IEnumAssocHandlers> e;
auto hr = SHAssocEnumHandlersForProtocolByApplication(L"http", IID_PPV_ARGS(&e));
if (SUCCEEDED(hr)) {
    Microsoft::WRL::ComPtr<IAssocHandler> handler;
    while (e->Next(1, &handler, nullptr) == S_OK) {
        PWSTR name;
        if (SUCCEEDED(handler->GetUIName(&name))) {
            printf("UI Name: %ls\n", name);
            CoTaskMemFree(name);
        }
    }
}

You can even ask pass the URI to a specific handler by calling the Invoke method:

HRESULT InvokeHandlerOnURI(IAssocHandler* handler, PCWSTR uri)
{
    Microsoft::WRL::ComPtr<IShellItem> item;
    RETURN_IF_FAILED(SHCreateItemFromParsingName(
        L"http://msn.com/", nullptr, IID_PPV_ARGS(&item)));
    Microsoft::WRL::ComPtr<IDataObject> dto;
    RETURN_IF_FAILED(item->BindToHandler(nullptr,
        BHID_DataObject, IID_PPV_ARGS(&dto)));
    RETURN_IF_FAILED(handler->Invoke(dto.Get()));
    return S_OK;
}

¹ Dirty secret: The dice are loaded.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

5 comments

Discussion is closed. Login to edit/delete existing comments.

  • Paulo Pinto

    It is interesting that WRL keeps being used by plenty of developers, despite of its deprecation, most likely because C++/WinRT hardly adds any value to the Visual Studio developer experience.

    • George Tokmaji · Edited

      It's classic COM, WRL is just as good an option as C++/WinRT is (or _com_ptr, if you're willing to deal with some of its gotchas). C++/WinRT gives you more helpers to make life easier - I consider <code> + exception handling to be more readable than <code> - but that doesn't make it a game changer.

      On the other hand, try consuming Windows Runtime classes with WRL... (And if you already might be using the Windows...

      Read more
    • Me Gusta

      Is WRL deprecated? I know that it was superseded by C++/WinRT, but I don’t remember seeing any mention of it being deprecated.
      Isn’t it also only superseded on the Windows Runtime side of things? Since the interfaces used in this post are classic COM interfaces then WRL is just as good an option.

      • Paulo Pinto

        It is, check its documentation, it is quite hard to miss the big pink square,

        https://learn.microsoft.com/en-us/cpp/cppcx/wrl/windows-runtime-cpp-template-library-wrl?view=msvc-170

        While it says superseded, and not deprecated, it is really the same, as it is clear where development budget is being spent.

        However since, having the one true library was never a WinDev in regards to COM, not only you can use MFC, ATL, WRL, C++/CX, C++/WinRT, there is WIL as well,

        https://github.com/microsoft/wil

        With exception of MFC, they all share one common thread, bad...

        Read more
      • Me Gusta

        Then no, you are incorrect on this matter.
        Supersede and deprecate have completely different meanings. That big pink box states that it has been superseded and then provides reasons for why C++/WinRT should be used. It does not provide any kind of disapproval of WRL though. There is a big difference between "you shouldn't use this" and "you would find using that to be a much better experience". When Microsoft deprecate things, they don't just...

        Read more