winapiwindows-shell

GetOpenFileName url behaviour


When using GetOpenFileName, if the user types an URL in the open box, the function (at least in Windows 11) downloads in the background the file then it caches in a local folder somewhere under %user%\AppData\Local and returns it to the user.

OPENFILENAME of = { 0 };
of.lStructSize = sizeof(of);
of.lpstrFilter = L"*.xml\0*.xml\0\0";
wchar_t fil[1000] = {};
of.lpstrFile = fil;
of.nMaxFile = 1000;
GetOpenFileName(&of); // if you paste an URL to the box, it gets it.
  1. Is this behaviour somewhere documented so I can rely on it?
  2. It is synchronous, meaning that the dialog box gets stuck until the download is completed, is there a way to change that?
  3. I tested with a PHP url that sets Content-Disposition and Content-Type to XML, for example, but the returned "file" from the function is still "php". Is there some options to set that?

Best,


Solution

  • On modern Windows, GetOpenFileName is implemented by using the newer IFileOpenDialog interface.

    You can use IFileOpenDialog yourself directly instead using a code like this:

    int main()
    {
        CoInitialize(nullptr);
    
        IFileOpenDialog* dlg;
        CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&dlg));
        if (dlg)
        {
            if (SUCCEEDED(dlg->Show(nullptr)))
            {
                IShellItem* result;
                if (SUCCEEDED(dlg->GetResult(&result)))
                {
                    // a download or a cache access may happen here
                    IStream* stream;
                    if (SUCCEEDED(result->BindToHandler(nullptr, BHID_Stream, IID_PPV_ARGS(&stream))))
                    {
                        // you will get here if the download succeeded or if the url's download result was already in the cache
                        ... read from the stream ...
                        stream->Release();
                    }
                    else
                    {
                        // the url download probably failed
                    }
    
                    result->Release();
                }
            }
            dlg->Release();)
        }
    
        CoUninitialize();
    }
    

    Note in the case of urls, when we call IFileOpenDialog::GetResult(s), we will get IShellItem(s) back with their name being the url itself.

    With these items, we can call IShellItem::BindToHandler and ask for an IStream interface. If the underlying operation succeeds (something is downloaded from the url or from a local cache), we can then read from that stream (note it's a readonly stream) to read the content w/o knowing where it was actually downloaded locally.

    AFAIK there's no way to customize anything to these workings.

    Internally it relies on SHParseDisplayName (from the desktop) and higher-level alike functions, so for example, you can do this too:

    SHCreateItemFromParsingName(L"http://www.example.com", nullptr, IID_PPV_ARGS(&item));
    item->BindToHandler(nullptr, BHID_Stream, IID_PPV_ARGS(&stream));