April 12th, 2019

How can a desktop app use a Windows Runtime object that infers UI context from its thread? The IInitializeWithWindow pattern

Many objects in the Windows Runtime can be used from desktop apps. For today’s example, we’ll use the File­Open­Picker. This is a rather artificial example because you could just use the IFile­Dialog interface to get equivalent functionality in a desktop app, but I just picked it for use as an example.

Start with our scratch program and make these changes:

#include <winrt/windows.storage.pickers.h>

winrt::Windows::Foundation::IAsyncAction
ShowFilePickerAsync(HWND hwnd)
{
    auto picker = winrt::Windows::Storage::Pickers::FileOpenPicker();
    picker.FileTypeFilter().Append(L".jpg");
    auto file = co_await picker.PickSingleFileAsync();
}

winrt::fire_and_forget OnChar(HWND hwnd, TCHAR ch, int cRepeat)
{
    co_await ShowFilePickerAsync(hwnd);
}

// Add to WndProc
    HANDLE_MSG(hwnd, WM_CHAR, OnChar);

Run this program and press a key. The program will crash because the File­Open­Picker looks for a Core­Window on the current thread to serve as the owner of the dialog. But we are a Win32 desktop app without a Core­Window.

The solution is to use the IInitialize­With­Window interface. Many Windows Runtime objects which infer the Core­Window from the current thread support the IInitialize­With­Window interface to allow a Win32 desktop app to specify an explicit window.

Make the following changes to the program:

#include <shobjidl.h>
#include <winrt/windows.storage.pickers.h>

winrt::Windows::Foundation::IAsyncAction
ShowFilePickerAsync(HWND hwnd)
{
    auto picker = winrt::Windows::Storage::Pickers::FileOpenPicker();
    picker.as<IInitializeWithWindow>()->Initialize(hwnd);
    picker.FileTypeFilter().Append(L".jpg");
    auto file = co_await picker.PickSingleFileAsync();
}

This time, the File Open dialog opens because we explicitly provided a window handle to use as the owner.

The IInitialize­Window­Window pattern is used mostly in the case where an object is simply constructed. There is another pattern for the case where an object is obtained by calling a method: The interop pattern, which I covered some time ago.

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.

8 comments

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

  • Dave Bacher

    I actually might use this – the UWP File Picker is a lot nicer for any case involving cloud providers, and is potentially more secure for some cases.

  • Gunnar Dalsnes

    is the as method specific to the picker (or some base class) or is it a c++ thing (ala. extension method)?
    how is it diffetent from regular cast?

    • Me Gusta

      As you may know, the UWP API is based upon COM. The pickers themselves are implemented as a bunch of interfaces. All COM interfaces, even UWP interfaces, inherit from IUnknown (UWP interfaces inherit from IInspectable which inherits from IUnknown).
      Now, the C++/WinRT library wraps this and names it after the logical class. But because this is a COM API then it wraps interfaces to the underlying object that implement this behaviour and these interfaces derive...

      Read more
  • John Selbie

    If you are trying this at home.  The needed headers include:

        #include <shobjidl_core.h>
        #include <winrt/windows.storage.pickers.h>

    And the library to link with:

        runtimeobject.lib

    • Raymond ChenMicrosoft employee Author

      More convenient is to link with the umbrella library windowsapp.lib.

  • Ji Luo

    I inferred that pattern a few weeks ago when I was playing with the Pin to Start dialog. I wonder whether that pattern could be used in production, since MSDN doesn’t mention this pattern, nor does the documentation for FilePickers say a word on it.
    For another thing, FilePickers are quite different from IFileDialog (contrary to the MSDN statement saying that desktop apps don’t need them as they already have IFileDialog and full access to...

    Read more
    • Joe Beans

      I host all my Win32 IFileDialogs out-of-process so you not only get a dedicated UI thread for speed but can do cool stuff like automatically reopen the window if it hard crashes. Fortunately you can specify an out-of-process HWND parent and it will obey it, unlike any dialogs that have to do with the miserable IShellItem Recycle Bin. That tiny section of code needs review BTW. The Recycle Bin's implementation is such a hack, I...

      Read more
  • Me Gusta

    This is interesting. This really helps for interoping with UWP.
    I knew you could get the StorageFolder from GetFolderFromPathAsync and work from that, but knowing how to get the pickers to work really helps