c++winapiwindows-shell

SHParseDisplayName when path doesn't exists


I'm developing a replacement for IFileOpenDialog and IFileSaveDialog.

I almost have it working (at least IFileOpenDialog), but when I want to return the IShellItem that represents the new filename (that the user has choosen to save in the GetResult() method), I can't get SHParseDisplayName working with this new filename. I always receive an error "The system cannot find the file specified".

I will appreciate some examples or another solution maybe to my problem.

Edit:

    HRESULT CFileSaveDialogProxy::GetResult( __RPC__deref_out_opt IShellItem **ppsi)
    {
        //return m_Original->GetResult(ppsi);

        WCHAR pszPath[MAX_PATH] = {0};
        HRESULT hr = ERROR_CANCELLED;

        if (m_SelectedFiles.size() > 0)
        {
            QString s = m_SelectedFiles.at(0);
            s.replace(QString("/"),QString("\\"));
            s.toWCharArray(pszPath);

            //PCIDLIST_ABSOLUTE pIdL = ILCreateFromPath(pszPath);
            PIDLIST_ABSOLUTE pIdL = NULL;
            SFGAOF out;
            hr = SHParseDisplayName(pszPath,NULL,&pIdL,SFGAO_FILESYSTEM,&out);
            if (SUCCEEDED(hr))
            {
                hr = SHCreateItemFromIDList(pIdL, IID_PPV_ARGS(ppsi));
            }
        }

        return hr;
    }

Solution

  • You have to use the IBindCtx parameter to pass additional data to the parser, in this case your own file metadata so SHParseDisplayName() will not try to access a real file to get the metadata. This is described in the IShellFolder::ParseDisplayName() and SHCreateItemFromParsingName() documentations:

    A pointer to a bind context used to pass parameters as inputs and outputs to the parsing function. These passed parameters are often specific to the data source and are documented by the data source owners. For example, the file system data source accepts the name being parsed (as a WIN32_FIND_DATA structure), using the STR_FILE_SYS_BIND_DATA bind context parameter. STR_PARSE_PREFER_FOLDER_BROWSING can be passed to indicate that URLs are parsed using the file system data source when possible. Construct a bind context object using CreateBindCtx and populate the values using IBindCtx::RegisterObjectParam. See Bind Context String Keys for a complete list of these.

    And outlined in detail on the MSDN "Old New Thing" blog:

    Creating a simple pidl: For the times you care enough to send the very fake🕗